/clients/cs/samples/YouTubeUploader/YouTubeUploader/insertandretry.cs

http://google-gdata.googlecode.com/ · C# · 246 lines · 187 code · 32 blank · 27 comment · 12 complexity · 4ef671ccbb0f623c768bd92f90d9dbeb MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. using System.Windows.Forms;
  7. using System.Diagnostics;
  8. using Google.GData.Client;
  9. using Google.GData.YouTube;
  10. using Google.GData.Tools;
  11. using Google.YouTube;
  12. using Google.GData.Extensions.MediaRss;
  13. using Google.GData.Client.ResumableUpload;
  14. /// this file contains the CSV related support code
  15. namespace YouTubeUploader {
  16. public partial class YouTubeUploader : Form {
  17. private ResumableUploader ru = null;
  18. /// <summary>
  19. /// userstate is the object that is passed to the async code to identify a particular upload
  20. /// this object remembers the http operation, the row in the spreadsheet, progress, etc.
  21. /// This object get's added to the the current queue, or the retryqueue
  22. /// </summary>
  23. internal class UserState {
  24. private DataGridViewRow row;
  25. private long currentPosition;
  26. private string httpVerb;
  27. private Uri resumeUri;
  28. private int retryCounter;
  29. private string errorText;
  30. internal UserState(DataGridViewRow r) {
  31. this.row = r;
  32. this.currentPosition = 0;
  33. this.retryCounter = 0;
  34. }
  35. internal DataGridViewRow Row {
  36. get {
  37. return this.row;
  38. }
  39. }
  40. internal long CurrentPosition {
  41. get {
  42. return this.currentPosition;
  43. }
  44. set {
  45. this.currentPosition = value;
  46. }
  47. }
  48. internal string Error {
  49. get {
  50. return this.errorText;
  51. }
  52. set {
  53. this.errorText = value;
  54. }
  55. }
  56. internal int RetryCounter {
  57. get {
  58. return this.retryCounter;
  59. }
  60. set {
  61. this.retryCounter = value;
  62. }
  63. }
  64. internal string HttpVerb {
  65. get {
  66. return this.httpVerb;
  67. }
  68. set {
  69. this.httpVerb = value;
  70. }
  71. }
  72. internal Uri ResumeUri {
  73. get {
  74. return this.resumeUri;
  75. }
  76. set {
  77. this.resumeUri = value;
  78. }
  79. }
  80. }
  81. // helper to create a ResumableUploader object and setup the event handlers
  82. private void EnsureRU() {
  83. this.ru = new ResumableUploader((int)this.ChunkSize.Value);
  84. this.ru.AsyncOperationCompleted += new AsyncOperationCompletedEventHandler(this.OnDone);
  85. this.ru.AsyncOperationProgress += new AsyncOperationProgressEventHandler(this.OnProgress);
  86. }
  87. // retry one row. The userstate was removed from the retry queue before that call
  88. private bool RetryRow(UserState us) {
  89. if (us != null) {
  90. Trace.Indent();
  91. Trace.TraceInformation("Retrying a row, current position is: " + us.CurrentPosition + "for uri: " + us.ResumeUri);
  92. Trace.Unindent();
  93. if (us.CurrentPosition > 0 && us.ResumeUri != null) {
  94. string contentType = MediaFileSource.GetContentTypeForFileName(us.Row.Cells[COLUMNINDEX_FILENAME].Value.ToString());
  95. MediaFileSource mfs = new MediaFileSource(us.Row.Cells[COLUMNINDEX_FILENAME].Value.ToString(), contentType);
  96. Stream s = mfs.GetDataStream();
  97. s.Seek(us.CurrentPosition, SeekOrigin.Begin);
  98. lock (this.flag) {
  99. this.queue.Add(us);
  100. }
  101. us.Row.Cells[COLUMNINDEX_STATUS].Value = "Retrying (" + us.RetryCounter + ") - Last error was: " + us.Error;
  102. ru.ResumeAsync(this.youTubeAuthenticator, us.ResumeUri, us.HttpVerb, s, contentType, us);
  103. return true;
  104. }
  105. // else treat this as a new one, a resume from null
  106. return InsertVideo(us.Row, us.RetryCounter + 1);
  107. }
  108. return false;
  109. }
  110. /// <summary>
  111. /// insert a new video.
  112. /// </summary>
  113. /// <param name="row"></param>
  114. /// <param name="retryCounter"></param>
  115. /// <returns></returns>
  116. private bool InsertVideo(DataGridViewRow row, int retryCounter) {
  117. Trace.TraceInformation("Entering InsertVideo: starting a new upload");
  118. Video v = new Video();
  119. v.Title = row.Cells[0].Value.ToString();
  120. v.Description = row.Cells[1].Value.ToString();
  121. v.Keywords = row.Cells[2].Value.ToString();
  122. v.Tags.Add(new MediaCategory(row.Cells[3].Value.ToString()));
  123. v.Private = row.Cells[4].Value.ToString().ToLower() == "true";
  124. string contentType = MediaFileSource.GetContentTypeForFileName(row.Cells[COLUMNINDEX_FILENAME].Value.ToString());
  125. v.MediaSource = new MediaFileSource(row.Cells[COLUMNINDEX_FILENAME].Value.ToString(), contentType);
  126. // add the upload uri to it
  127. AtomLink link = new AtomLink("http://uploads.gdata.youtube.com/resumable/feeds/api/users/" + this.youtubeAccount + "/uploads");
  128. link.Rel = ResumableUploader.CreateMediaRelation;
  129. v.YouTubeEntry.Links.Add(link);
  130. UserState u = new UserState(row);
  131. u.RetryCounter = retryCounter;
  132. lock (this.flag) {
  133. this.queue.Add(u);
  134. }
  135. ru.InsertAsync(this.youTubeAuthenticator, v.YouTubeEntry, u);
  136. row.Cells[COLUMNINDEX_STATUS].Value = "Queued up...";
  137. row.Cells[COLUMNINDEX_STATUS].Tag = u;
  138. return true;
  139. }
  140. // when an upload is completed successfully we parse the return stream
  141. // to setup the videoid.
  142. // also all retry counts will be reset to 0, as a successful upload incidates
  143. // a restored network condition (e.g.).
  144. private void ParseAndFinish(UserState u, Stream s) {
  145. YouTubeRequestSettings ys = new YouTubeRequestSettings(YouTubeUploader.ApplicationName,
  146. this.developerKey);
  147. YouTubeRequest ytr = new YouTubeRequest(ys);
  148. Video v = ytr.ParseVideo(s);
  149. Trace.TraceInformation("Upload successful");
  150. u.Row.Cells[COLUMNINDEX_STATUS].Value = "Upload successful";
  151. u.Row.Cells[COLUMNINDEX_STATUS].Tag = u;
  152. u.Row.Cells[COLUMNINDEX_VIDEOID].Value = v.VideoId;
  153. // we had one successful upload, reset the retry counts to 0
  154. lock (this.flag) {
  155. foreach (UserState us in retryQueue) {
  156. us.RetryCounter = 0;
  157. }
  158. }
  159. }
  160. private void RemoveFromProcessingQueue(UserState u) {
  161. lock (this.flag) {
  162. this.queue.Remove(u);
  163. }
  164. }
  165. private bool AddToRetryQueue(UserState u) {
  166. u.RetryCounter++;
  167. if (u.RetryCounter > (int)this.automaticRetries.Value) {
  168. u.Row.Cells[COLUMNINDEX_STATUS].Value = "Number of retries exceeded. Last error was: " + u.Error;
  169. return false;
  170. }
  171. lock (this.flag) {
  172. this.retryQueue.Add(u);
  173. }
  174. return true;
  175. }
  176. // moves an entry into the retry queue
  177. // and enables the retry timer
  178. private void TryARetry(UserState u) {
  179. if (AddToRetryQueue(u)) {
  180. this.RetryTimer.Enabled = true;
  181. }
  182. }
  183. // cancels all currently active threads and empties the queue
  184. private void CancelProcessingQueue() {
  185. // this will go over all rows and tries to upload them
  186. lock (this.flag) {
  187. this.RetryTimer.Enabled = false;
  188. foreach (UserState u in this.queue) {
  189. this.ru.CancelAsync(u);
  190. }
  191. this.queue = new List<UserState>();
  192. }
  193. }
  194. // walks over the retry queue and moves them into the processing queue
  195. // if the queue has free slots
  196. private void RetryRows() {
  197. if (this.retryQueue.Count > 0) {
  198. this.RetryTimer.Enabled = true;
  199. while (this.queue.Count < (int)this.MaxQueue.Value &&
  200. this.retryQueue.Count > 0) {
  201. lock (this.flag) {
  202. UserState u = this.retryQueue[0];
  203. this.retryQueue.Remove(u);
  204. RetryRow(u);
  205. }
  206. }
  207. } else {
  208. this.RetryTimer.Enabled = false;
  209. if (Finished())
  210. ToggleButtons(true);
  211. }
  212. }
  213. }
  214. }