PageRenderTime 35ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/PushSharp.Android/Gcm/GcmMessageTransportAsync.cs

https://github.com/mustafagenc/PushSharp
C# | 331 lines | 272 code | 53 blank | 6 comment | 34 complexity | 7a632fd37e5485d594e9fa2b8ee02fc4 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Net;
  7. using System.IO;
  8. using System.Security.Cryptography.X509Certificates;
  9. using System.Security;
  10. using System.Net.Security;
  11. using Newtonsoft.Json.Linq;
  12. namespace PushSharp.Android
  13. {
  14. internal class GcmMessageTransportAsync
  15. {
  16. public event Action<string> UpdateGoogleClientAuthToken;
  17. public event Action<GcmMessageTransportResponse> MessageResponseReceived;
  18. public event Action<GcmNotification, Exception> UnhandledException;
  19. static GcmMessageTransportAsync()
  20. {
  21. ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, policyErrs) => { return true; };
  22. }
  23. private const string GCM_SEND_URL = "https://android.googleapis.com/gcm/send";
  24. public void Send(GcmNotification msg, string senderAuthToken, string senderID, string applicationID)
  25. {
  26. try
  27. {
  28. send(msg, senderAuthToken, senderID, applicationID);
  29. }
  30. catch (Exception ex)
  31. {
  32. if (UnhandledException != null)
  33. UnhandledException(msg, ex);
  34. else
  35. throw ex;
  36. }
  37. }
  38. void send(GcmNotification msg, string senderAuthToken, string senderID, string applicationID)
  39. {
  40. var result = new GcmMessageTransportResponse();
  41. result.Message = msg;
  42. var postData = msg.GetJson();
  43. var webReq = (HttpWebRequest)WebRequest.Create(GCM_SEND_URL);
  44. //webReq.ContentLength = postData.Length;
  45. webReq.Method = "POST";
  46. webReq.ContentType = "application/json";
  47. //webReq.ContentType = "application/x-www-form-urlencoded;charset=UTF-8 can be used for plaintext bodies
  48. webReq.UserAgent = "PushSharp (version: 1.0)";
  49. webReq.Headers.Add("Authorization: key=" + senderAuthToken);
  50. webReq.BeginGetRequestStream(new AsyncCallback(requestStreamCallback), new GcmAsyncParameters()
  51. {
  52. WebRequest = webReq,
  53. WebResponse = null,
  54. Message = msg,
  55. SenderAuthToken = senderAuthToken,
  56. SenderId = senderID,
  57. ApplicationId = applicationID
  58. });
  59. }
  60. void requestStreamCallback(IAsyncResult result)
  61. {
  62. var msg = new GcmNotification();
  63. try
  64. {
  65. var asyncParam = result.AsyncState as GcmAsyncParameters;
  66. msg = asyncParam.Message;
  67. if (asyncParam != null)
  68. {
  69. var wrStream = asyncParam.WebRequest.EndGetRequestStream(result);
  70. using (var webReqStream = new StreamWriter(wrStream))
  71. {
  72. var data = asyncParam.Message.GetJson();
  73. webReqStream.Write(data);
  74. webReqStream.Close();
  75. }
  76. try
  77. {
  78. asyncParam.WebRequest.BeginGetResponse(new AsyncCallback(responseCallback), asyncParam);
  79. }
  80. catch (WebException wex)
  81. {
  82. asyncParam.WebResponse = wex.Response as HttpWebResponse;
  83. processResponseError(asyncParam);
  84. }
  85. }
  86. }
  87. catch (Exception ex)
  88. {
  89. if (UnhandledException != null)
  90. UnhandledException(msg, ex);
  91. else
  92. throw ex;
  93. }
  94. }
  95. void responseCallback(IAsyncResult result)
  96. {
  97. var msg = new GcmNotification();
  98. try
  99. {
  100. var asyncParam = result.AsyncState as GcmAsyncParameters;
  101. msg = asyncParam.Message;
  102. try
  103. {
  104. asyncParam.WebResponse = asyncParam.WebRequest.EndGetResponse(result) as HttpWebResponse;
  105. processResponseOk(asyncParam);
  106. }
  107. catch (WebException wex)
  108. {
  109. asyncParam.WebResponse = wex.Response as HttpWebResponse;
  110. processResponseError(asyncParam);
  111. }
  112. }
  113. catch (Exception ex)
  114. {
  115. if (UnhandledException != null)
  116. UnhandledException(msg, ex);
  117. else
  118. throw ex;
  119. }
  120. }
  121. void processResponseOk(GcmAsyncParameters asyncParam)
  122. {
  123. var result = new GcmMessageTransportResponse()
  124. {
  125. ResponseCode = GcmMessageTransportResponseCode.Ok,
  126. Message = asyncParam.Message
  127. };
  128. var updateClientAuth = asyncParam.WebResponse.GetResponseHeader("Update-Client-Auth");
  129. if (!string.IsNullOrEmpty(updateClientAuth) && UpdateGoogleClientAuthToken != null)
  130. UpdateGoogleClientAuthToken(updateClientAuth);
  131. //Get the response body
  132. var json = new JObject();
  133. try { json = JObject.Parse((new StreamReader(asyncParam.WebResponse.GetResponseStream())).ReadToEnd()); }
  134. catch { }
  135. result.NumberOfCanonicalIds = json.Value<long>("canonical_ids");
  136. result.NumberOfFailures = json.Value<long>("failure");
  137. result.NumberOfSuccesses = json.Value<long>("success");
  138. var jsonResults = json["results"] as JArray;
  139. if (jsonResults == null)
  140. jsonResults = new JArray();
  141. foreach (var r in json["results"])
  142. {
  143. var msgResult = new GcmMessageResult();
  144. msgResult.MessageId = r.Value<string>("message_id");
  145. msgResult.CanonicalRegistrationId = r.Value<string>("registration_id");
  146. if (!string.IsNullOrEmpty(msgResult.CanonicalRegistrationId))
  147. {
  148. msgResult.ResponseStatus = GcmMessageTransportResponseStatus.CanonicalRegistrationId;
  149. }
  150. else if (r["error"] != null)
  151. {
  152. var err = r.Value<string>("error") ?? "";
  153. switch (err.ToLower().Trim())
  154. {
  155. case "missingregistration":
  156. msgResult.ResponseStatus = GcmMessageTransportResponseStatus.MissingRegistrationId;
  157. break;
  158. case "unavailable":
  159. msgResult.ResponseStatus = GcmMessageTransportResponseStatus.Unavailable;
  160. break;
  161. case "notregistered":
  162. msgResult.ResponseStatus = GcmMessageTransportResponseStatus.NotRegistered;
  163. break;
  164. case "invalidregistration":
  165. msgResult.ResponseStatus = GcmMessageTransportResponseStatus.InvalidRegistration;
  166. break;
  167. case "mismatchsenderid":
  168. msgResult.ResponseStatus = GcmMessageTransportResponseStatus.MismatchSenderId;
  169. break;
  170. case "messagetoobig":
  171. msgResult.ResponseStatus = GcmMessageTransportResponseStatus.MessageTooBig;
  172. break;
  173. case "invaliddatakey":
  174. msgResult.ResponseStatus = GcmMessageTransportResponseStatus.InvalidDataKey;
  175. break;
  176. case "invalidttl":
  177. msgResult.ResponseStatus = GcmMessageTransportResponseStatus.InvalidTtl;
  178. break;
  179. case "internalservererror":
  180. msgResult.ResponseStatus = GcmMessageTransportResponseStatus.InternalServerError;
  181. break;
  182. default:
  183. msgResult.ResponseStatus = GcmMessageTransportResponseStatus.Error;
  184. break;
  185. }
  186. }
  187. result.Results.Add(msgResult);
  188. }
  189. asyncParam.WebResponse.Close();
  190. var evtmrr = MessageResponseReceived;
  191. if (evtmrr != null)
  192. evtmrr(result);
  193. }
  194. void processResponseError(GcmAsyncParameters asyncParam)
  195. {
  196. var result = new GcmMessageTransportResponse();
  197. result.ResponseCode = GcmMessageTransportResponseCode.Error;
  198. if (asyncParam.WebResponse.StatusCode == HttpStatusCode.Unauthorized)
  199. {
  200. //401 bad auth token
  201. result.ResponseCode = GcmMessageTransportResponseCode.InvalidAuthToken;
  202. throw new GcmAuthenticationErrorTransportException(result);
  203. }
  204. else if (asyncParam.WebResponse.StatusCode == HttpStatusCode.BadRequest)
  205. {
  206. result.ResponseCode = GcmMessageTransportResponseCode.BadRequest;
  207. throw new GcmBadRequestTransportException(result);
  208. }
  209. else if (asyncParam.WebResponse.StatusCode == HttpStatusCode.InternalServerError)
  210. {
  211. result.ResponseCode = GcmMessageTransportResponseCode.InternalServiceError;
  212. throw new GcmMessageTransportException("Internal Service Error", result);
  213. }
  214. else if (asyncParam.WebResponse.StatusCode == HttpStatusCode.ServiceUnavailable)
  215. {
  216. //First try grabbing the retry-after header and parsing it.
  217. TimeSpan retryAfter = new TimeSpan(0, 0, 120);
  218. var wrRetryAfter = asyncParam.WebResponse.GetResponseHeader("Retry-After");
  219. if (!string.IsNullOrEmpty(wrRetryAfter))
  220. {
  221. DateTime wrRetryAfterDate = DateTime.UtcNow;
  222. if (DateTime.TryParse(wrRetryAfter, out wrRetryAfterDate))
  223. retryAfter = wrRetryAfterDate - DateTime.UtcNow;
  224. else
  225. {
  226. int wrRetryAfterSeconds = 120;
  227. if (int.TryParse(wrRetryAfter, out wrRetryAfterSeconds))
  228. retryAfter = new TimeSpan(0, 0, wrRetryAfterSeconds);
  229. }
  230. }
  231. //503 exponential backoff, get retry-after header
  232. result.ResponseCode = GcmMessageTransportResponseCode.ServiceUnavailable;
  233. throw new GcmServiceUnavailableTransportException(retryAfter, result);
  234. }
  235. asyncParam.WebResponse.Close();
  236. throw new GcmMessageTransportException("Unknown Transport Error", result);
  237. }
  238. class GcmAsyncParameters
  239. {
  240. public GcmNotification Message
  241. {
  242. get;
  243. set;
  244. }
  245. public HttpWebRequest WebRequest
  246. {
  247. get;
  248. set;
  249. }
  250. public HttpWebResponse WebResponse
  251. {
  252. get;
  253. set;
  254. }
  255. public string SenderAuthToken
  256. {
  257. get;
  258. set;
  259. }
  260. public string SenderId
  261. {
  262. get;
  263. set;
  264. }
  265. public string ApplicationId
  266. {
  267. get;
  268. set;
  269. }
  270. }
  271. }
  272. public class GcmMessageResult
  273. {
  274. public string MessageId { get; set; }
  275. public string CanonicalRegistrationId { get; set; }
  276. public GcmMessageTransportResponseStatus ResponseStatus { get; set; }
  277. }
  278. }