private async Task PushNotifyInboxMessageGoogleAsync(InboxEntity inbox) { if (!string.IsNullOrEmpty(inbox.GoogleCloudMessagingRegistrationId)) { var notifications = new GooglePushNotifications(this.HttpClient, ConfigurationManager.AppSettings["GoogleApiKey"], inbox.GoogleCloudMessagingRegistrationId); bool invalidChannel = false; try { bool successfulPush = await notifications.PushGoogleRawNotificationAsync(CancellationToken.None); invalidChannel |= !successfulPush; } catch (HttpRequestException) { invalidChannel = true; } if (invalidChannel) { inbox.GoogleCloudMessagingRegistrationId = null; this.InboxTable.UpdateObject(inbox); } } }
private async Task PushNotifyInboxMessageWinPhoneAsync(InboxEntity inbox) { if (!string.IsNullOrEmpty(inbox.WinPhone8PushChannelUri)) { var notifications = new WinPhonePushNotifications(this.HttpClient, new Uri(inbox.WinPhone8PushChannelUri)); int count = await this.RetrieveInboxItemsCountAsync(inbox.RowKey); bool invalidChannel = false; try { var pushTile = notifications.PushWinPhoneTileAsync(inbox.WinPhone8TileTemplate, count: count); Task <bool> pushToast = Task.FromResult(false); if (!string.IsNullOrEmpty(inbox.WinPhone8ToastText1) || !string.IsNullOrEmpty(inbox.WinPhone8ToastText2)) { var line1 = string.Format(CultureInfo.InvariantCulture, inbox.WinPhone8ToastText1 ?? string.Empty, count); var line2 = string.Format(CultureInfo.InvariantCulture, inbox.WinPhone8ToastText2 ?? string.Empty, count); if (inbox.LastWinPhone8PushNotificationUtc.HasValue && inbox.LastAuthenticatedInteractionUtc.HasValue && inbox.LastWinPhone8PushNotificationUtc.Value > inbox.LastAuthenticatedInteractionUtc.Value) { // We've sent a toast notification more recently than the user has checked messages, // so there's no reason to send another for now. pushToast = Task.FromResult(true); } else { pushToast = notifications.PushWinPhoneToastAsync(line1, line2); } } Task <bool> pushRaw = Task.FromResult(false); if (!string.IsNullOrEmpty(inbox.WinPhone8PushChannelContent)) { pushRaw = notifications.PushWinPhoneRawNotificationAsync(inbox.WinPhone8PushChannelContent); } await Task.WhenAll(pushTile, pushToast, pushRaw); invalidChannel |= !(pushTile.Result || pushToast.Result || pushRaw.Result); } catch (HttpRequestException) { invalidChannel = true; } if (invalidChannel) { inbox.WinPhone8PushChannelUri = null; inbox.WinPhone8PushChannelContent = null; inbox.WinPhone8ToastText1 = null; inbox.WinPhone8ToastText2 = null; } else { inbox.LastWinPhone8PushNotificationUtc = DateTime.UtcNow; } this.InboxTable.UpdateObject(inbox); } }
private async Task PushNotifyInboxMessageAsync(InboxEntity inbox) { Requires.NotNull(inbox, "inbox"); await Task.WhenAll( this.PushNotifyInboxMessageWinStoreAsync(inbox), this.PushNotifyInboxMessageWinPhoneAsync(inbox)); }
private async Task PushNotifyInboxMessageWinStoreAsync(InboxEntity inbox, int failedAttempts = 0) { if (string.IsNullOrEmpty(inbox.ClientPackageSecurityIdentifier) || string.IsNullOrEmpty(inbox.PushChannelUri)) { return; } var client = await this.ClientTable.GetAsync(inbox.ClientPackageSecurityIdentifier); string bearerToken = client.AccessToken; var pushNotifyRequest = new HttpRequestMessage(HttpMethod.Post, inbox.PushChannelUri); pushNotifyRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken); pushNotifyRequest.Headers.Add("X-WNS-Type", "wns/raw"); pushNotifyRequest.Content = new StringContent(inbox.PushChannelContent ?? string.Empty); // yes, it's a string, but we must claim it's an octet-stream pushNotifyRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); var response = await this.HttpClient.SendAsync(pushNotifyRequest); if (response.IsSuccessStatusCode) { inbox.LastWindows8PushNotificationUtc = DateTime.UtcNow; this.InboxTable.UpdateObject(inbox); } else { if (failedAttempts == 0) { var authHeader = response.Headers.WwwAuthenticate.FirstOrDefault(); if (authHeader != null) { if (authHeader.Parameter.Contains("Token expired")) { await client.AcquireWnsPushBearerTokenAsync(this.HttpClient); this.ClientTable.UpdateObject(client); await this.ClientTable.SaveChangesAsync(); await this.PushNotifyInboxMessageWinStoreAsync(inbox, failedAttempts + 1); return; } } } // Log a failure. // TODO: code here. } }
private async Task PushNotifyInboxMessageAppleAsync(InboxEntity inbox) { if (MvcApplication.IsApplePushRegistered) { if (!string.IsNullOrEmpty(inbox.ApplePushNotificationGatewayDeviceToken)) { int count = await this.RetrieveInboxItemsCountAsync(inbox.RowKey); MvcApplication.PushBroker.QueueNotification(new AppleNotification() .ForDeviceToken(inbox.ApplePushNotificationGatewayDeviceToken) .WithBadge(count)); } } }
public async Task <ActionResult> PostNotificationAsync(string id, int lifetime) { Requires.NotNullOrEmpty(id, "id"); Requires.Range(lifetime > 0, "lifetime"); if (this.Request.ContentLength > MaxNotificationSize) { throw new ArgumentException("Maximum message notification size exceeded."); } InboxEntity inbox = await this.GetInboxAsync(id); if (inbox == null) { return(new HttpNotFoundResult()); } var directory = this.InboxContainer.GetDirectoryReference(id); var blob = directory.GetBlockBlobReference(Utilities.CreateRandomWebSafeName(24)); Debug.WriteLine("Defining blob: {0} ({1})", blob.Name, blob.Uri); var requestedLifeSpan = TimeSpan.FromMinutes(lifetime); var actualLifespan = requestedLifeSpan > MaxLifetimeCeiling ? MaxLifetimeCeiling : requestedLifeSpan; var expirationDate = DateTime.UtcNow + actualLifespan; blob.Metadata[ExpirationDateMetadataKey] = expirationDate.ToString(CultureInfo.InvariantCulture); await blob.UploadFromStreamAsync(this.Request.InputStream); // One more last ditch check that the max size was not exceeded, in case // the client is lying in the HTTP headers. if (blob.Properties.Length > MaxNotificationSize) { await blob.DeleteAsync(); throw new ArgumentException("Maximum message notification size exceeded."); } // Notifying the receiver isn't something the sender needs to wait for. var nowait = Task.Run(async delegate { await this.AlertLongPollWaiterAsync(inbox); await this.InboxTable.SaveChangesWithMergeAsync(inbox); }); return(new HttpStatusCodeResult(HttpStatusCode.Created)); }
public async Task <JsonResult> CreateAsync() { var inbox = InboxEntity.Create(); this.InboxTable.AddObject(inbox); await this.InboxTable.SaveChangesWithMergeAsync(inbox); string messageReceivingEndpoint = this.GetAbsoluteUrlForAction("Slot", new { id = inbox.RowKey }).AbsoluteUri; var result = new InboxCreationResponse { MessageReceivingEndpoint = messageReceivingEndpoint, InboxOwnerCode = inbox.InboxOwnerCode, }; return(new JsonResult { Data = result }); }
private async Task AlertLongPollWaiterAsync(InboxEntity inbox) { Requires.NotNull(inbox, "inbox"); await this.PushNotifyInboxMessageAsync(inbox); var id = inbox.RowKey; TaskCompletionSource <object> tcs; lock (LongPollWaiters) { if (LongPollWaiters.TryGetValue(id, out tcs)) { LongPollWaiters.Remove(id); } } if (tcs != null) { tcs.TrySetResult(null); } }