PageRenderTime 775ms CodeModel.GetById 54ms RepoModel.GetById 7ms app.codeStats 0ms

/tags/1.7/WordPress.Model/XMLRPC/UploadFileRPC.cs

https://bitbucket.org/sendhil/wordpress-windowsphone
C# | 359 lines | 240 code | 51 blank | 68 comment | 28 complexity | 5c5099a8c8f595b6fe3f1064722fe068 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Xml.Linq;
  10. using Microsoft.Xna.Framework.Media;
  11. namespace WordPress.Model
  12. {
  13. public class UploadFileRPC : XmlRemoteProcedureCall<Media>
  14. {
  15. #region member variables
  16. private const string METHODNAME_VALUE = "wp.uploadFile";
  17. private int retryCount = 0;
  18. private const string FILE_VALUE = "file";
  19. private const string URL_VALUE = "url";
  20. private const string TYPE_VALUE = "type";
  21. /// <summary>
  22. /// Holds a format string with the XMLRPC post content
  23. /// </summary>
  24. private readonly string _content;
  25. private State originalState;
  26. #endregion
  27. #region constructors
  28. public UploadFileRPC()
  29. : base()
  30. {
  31. _content = XMLRPCTable.wp_uploadFile;
  32. MethodName = METHODNAME_VALUE;
  33. }
  34. public UploadFileRPC(Blog blog, Media currentMedia, bool overwrite)
  35. : base(blog.Xmlrpc, METHODNAME_VALUE, blog.Username, blog.Password)
  36. {
  37. _content = XMLRPCTable.wp_uploadFile;
  38. Blog = blog;
  39. CurrentMedia = currentMedia;
  40. Overwrite = overwrite;
  41. }
  42. #endregion
  43. #region properties
  44. public Blog Blog { get; private set; }
  45. public Media CurrentMedia { get; private set; }
  46. public bool Overwrite { get; private set; }
  47. #endregion
  48. #region methods
  49. protected override void ValidateValues()
  50. {
  51. base.ValidateValues();
  52. if (null == Blog)
  53. {
  54. throw new ArgumentException("Blog may not be null", "Blog");
  55. }
  56. if (string.IsNullOrEmpty(CurrentMedia.FileName))
  57. {
  58. throw new ArgumentException("Name may not be null or an empty string.", "Name");
  59. }
  60. if (string.IsNullOrEmpty(CurrentMedia.MimeType))
  61. {
  62. throw new ArgumentException("Type may not be null or an empty string", "Type");
  63. }
  64. if (null == CurrentMedia.LocalPath)
  65. {
  66. throw new ArgumentException("Location of the file may not be null", "Data");
  67. }
  68. }
  69. protected override string BuildPostContentString()
  70. {
  71. throw new NotSupportedException("BuildPostContentString should not be called on image");
  72. /*
  73. string content = "<?xml version=\"1.0\"?><methodCall><methodName>wp.uploadFile</methodName><params>" +
  74. "<param><value><int>" + Blog.BlogId + "</int></value></param>" +
  75. "<param><value><string>" + Credentials.UserName.HtmlEncode() + "</string></value></param>" +
  76. "<param><value><string>" + Credentials.Password.HtmlEncode() + "</string></value></param>" +
  77. "<param><struct><member><name>name</name><value><string>" + FileName.HtmlEncode() + "</string></value></member>" +
  78. "<member><name>type</name><value><string>" + MimeType.HtmlEncode() + "</string></value></member>" +
  79. "<member><name>bits</name><value><base64>";
  80. byte[] chunk = new byte[3600];
  81. _bitmapStream.Position = 0;
  82. int count = 0;
  83. while ((count = _bitmapStream.Read(chunk, 0, chunk.Length)) > 0)
  84. {
  85. string result = Convert.ToBase64String(chunk);
  86. result = result.Trim();
  87. content += result;
  88. }
  89. content += "</base64></value></member>" +
  90. "<member><name>overwrite</name><value><bool>" + Convert.ToInt32(Overwrite) + "</bool></value></member>" +
  91. "</struct></param></params></methodCall>";
  92. return content;*/
  93. }
  94. /* Another way of reading a file by chunks
  95. * bool readCompleted = false;
  96. while ( readCompleted == false )
  97. {
  98. int index = 0;
  99. //we're trying to keep reading into our chunk until either we reach the end of the stream, or we've read everything we need.
  100. while (index < chunk.Length)
  101. {
  102. int bytesRead = _bitmapStream.Read(chunk, index, chunk.Length - index);
  103. this.DebugLog("Read the following noof bytes: " + bytesRead);
  104. if (bytesRead == 0)
  105. {
  106. break;
  107. }
  108. index += bytesRead;
  109. }
  110. if (index != 0) // Our previous chunk may have been the last one
  111. {
  112. string result = Convert.ToBase64String(chunk);
  113. result = result.Trim();
  114. content += result;
  115. }
  116. if (index != chunk.Length) // We didn't read a full chunk: we're done
  117. {
  118. readCompleted = true;
  119. this.DebugLog("No more bytes to read");
  120. }
  121. }
  122. */
  123. /* Read the whole file into the byte array. Do not use this method.
  124. int length = (int)_bitmapStream.Length;
  125. _bitmapStream.Position = 0;
  126. byte[] payload = new byte[length];
  127. _bitmapStream.Read(payload, 0, length);
  128. string result = Convert.ToBase64String(payload);
  129. result = result.Trim();
  130. */
  131. internal override void OnBeginGetRequestStreamCompleted(IAsyncResult result)
  132. {
  133. State state = result.AsyncState as State;
  134. HttpWebRequest request = state.Request;
  135. Stream contentStream = null;
  136. try
  137. {
  138. contentStream = request.EndGetRequestStream(result);
  139. }
  140. catch (Exception ex)
  141. {
  142. CompletionMethod(null, ex, false, state.Operation);
  143. return;
  144. }
  145. Stream _bitmapStream = CurrentMedia.getImageStream();
  146. using (contentStream)
  147. {
  148. //Write the first chunk of data
  149. string content = "<?xml version=\"1.0\"?><methodCall><methodName>wp.uploadFile</methodName><params>" +
  150. "<param><value><int>" + Blog.BlogId + "</int></value></param>" +
  151. "<param><value><string>" + Credentials.UserName.HtmlEncode() + "</string></value></param>" +
  152. "<param><value><string>" + Credentials.Password.HtmlEncode() + "</string></value></param>" +
  153. "<param><struct><member><name>name</name><value><string>" + CurrentMedia.FileName + "</string></value></member>" +
  154. "<member><name>type</name><value><string>" + CurrentMedia.MimeType.HtmlEncode() + "</string></value></member>" +
  155. "<member><name>bits</name><value><base64>";
  156. byte[] payload = Encoding.UTF8.GetBytes(content);
  157. contentStream.Write(payload, 0, payload.Length);
  158. //Write the chunks of the image
  159. byte[] chunk = new byte[3600];
  160. int count = 0;
  161. while ((count = _bitmapStream.Read(chunk, 0, chunk.Length)) > 0 && !IsCancelled)
  162. {
  163. payload = Encoding.UTF8.GetBytes(Convert.ToBase64String(chunk).Trim());
  164. contentStream.Write(payload, 0, payload.Length);
  165. }
  166. _bitmapStream.Close();
  167. if (IsCancelled)
  168. {
  169. return;
  170. }
  171. //Write the last chunk of data
  172. content = "</base64></value></member>" +
  173. "<member><name>overwrite</name><value><bool>" + Convert.ToInt32(Overwrite) + "</bool></value></member>" +
  174. "</struct></param></params></methodCall>";
  175. payload = Encoding.UTF8.GetBytes(content);
  176. contentStream.Write(payload, 0, payload.Length);
  177. }
  178. request.BeginGetResponse(OnBeginFileResponseCompleted, state);
  179. state.Operation.Post(onProgressReportDelegate, new ProgressChangedEventArgs(40, state.Operation.UserSuppliedState));
  180. }
  181. private void OnBeginFileResponseCompleted(IAsyncResult result)
  182. {
  183. if (IsCancelled)
  184. {
  185. return;
  186. }
  187. State state = result.AsyncState as State;
  188. if (retryCount == 0)
  189. {
  190. originalState = state;
  191. }
  192. HttpWebRequest request = state.Request;
  193. HttpWebResponse response = null;
  194. try
  195. {
  196. response = request.EndGetResponse(result) as HttpWebResponse;
  197. }
  198. catch (Exception ex)
  199. {
  200. if (retryCount == 2)
  201. {
  202. CompletionMethod(null, ex, false, originalState.Operation);
  203. return;
  204. }
  205. else
  206. {
  207. retryCount++;
  208. AsyncOperation newAsyncOp = AsyncOperationManager.CreateOperation(Guid.NewGuid());
  209. BeginBuildingHttpWebRequest(newAsyncOp);
  210. return;
  211. }
  212. }
  213. originalState.Operation.Post(onProgressReportDelegate, new ProgressChangedEventArgs(60, originalState.Operation.UserSuppliedState));
  214. Stream responseStream = response.GetResponseStream();
  215. string responseContent = null;
  216. try
  217. {
  218. using (StreamReader reader = new StreamReader(responseStream))
  219. {
  220. responseContent = reader.ReadToEnd();
  221. }
  222. }
  223. catch (Exception ex)
  224. {
  225. CompletionMethod(null, ex, false, originalState.Operation);
  226. return;
  227. }
  228. originalState.Operation.Post(onProgressReportDelegate, new ProgressChangedEventArgs(80, originalState.Operation.UserSuppliedState));
  229. XDocument xDoc = null;
  230. try
  231. {
  232. xDoc = this.cleanAndParseServerResponse(responseContent);
  233. }
  234. catch (Exception ex2)
  235. {
  236. CompletionMethod(null, ex2, false, originalState.Operation);
  237. return;
  238. }
  239. var fault = xDoc.Descendants().Where(element => XmlRPCResponseConstants.NAME == element.Name && XmlRPCResponseConstants.FAULTCODE_VALUE == element.Value);
  240. if (null != fault && 0 < fault.Count())
  241. {
  242. Exception exception = ParseFailureInfo(xDoc.Descendants(XmlRPCResponseConstants.STRUCT).First());
  243. CompletionMethod(null, exception, false, originalState.Operation);
  244. }
  245. else
  246. {
  247. List<Media> items = null;
  248. Exception exception = null;
  249. try
  250. {
  251. items = ParseResponseContent(xDoc);
  252. }
  253. catch (Exception ex)
  254. {
  255. if (ex is XmlRPCException || ex is XmlRPCParserException)
  256. exception = ex;
  257. else
  258. {
  259. exception = new XmlRPCException(XmlRPCResponseConstants.SERVER_RETURNED_INVALID_XML_RPC_CODE, XmlRPCResponseConstants.SERVER_RETURNED_INVALID_XML_RPC_MESSAGE, ex);
  260. }
  261. }
  262. CompletionMethod(items, exception, false, originalState.Operation);
  263. }
  264. }
  265. /* END of the overrided methods */
  266. protected override List<Media> ParseResponseContent(XDocument xDoc)
  267. {
  268. List<Media> result = new List<Media>();
  269. foreach (XElement structElement in xDoc.Descendants(XmlRPCResponseConstants.STRUCT))
  270. {
  271. this.ParseImageResponseElement(structElement);
  272. result.Add(CurrentMedia);
  273. }
  274. return result;
  275. }
  276. private void ParseImageResponseElement(XElement element)
  277. {
  278. if (!element.HasElements)
  279. {
  280. throw new XmlRPCParserException(XmlRPCResponseConstants.XELEMENTMISSINGCHILDELEMENTS_CODE, XmlRPCResponseConstants.XELEMENTMISSINGCHILDELEMENTS_MESSAGE);
  281. }
  282. string value = null;
  283. foreach (XElement member in element.Descendants(XmlRPCResponseConstants.MEMBER))
  284. {
  285. string memberName = member.Descendants(XmlRPCResponseConstants.NAME).First().Value;
  286. if (FILE_VALUE.Equals(memberName))
  287. {
  288. value = member.Descendants(XmlRPCResponseConstants.STRING).First().Value;
  289. CurrentMedia.FileName = value;
  290. }
  291. else if (URL_VALUE.Equals(memberName))
  292. {
  293. value = member.Descendants(XmlRPCResponseConstants.STRING).First().Value;
  294. CurrentMedia.Url = value;
  295. }
  296. else if (TYPE_VALUE.Equals(memberName))
  297. {
  298. value = member.Descendants(XmlRPCResponseConstants.STRING).First().Value;
  299. CurrentMedia.MimeType = value;
  300. }
  301. }
  302. }
  303. #endregion
  304. }
  305. }