public SqlServerPushService(PushDbContext db, IMapper mapper, IVapidDetailsStore vapid, ILogger <SqlServerPushService> logger) { _db = db; _vapid = vapid; _mapper = mapper; _client = new WebPush.WebPushClient(); _logger = logger; }
public async Task <ActionResult> SendNotification(int id) { var sub = db.PushSubscriptions.Find(id); if (sub == null) { return(HttpNotFound()); } else { var publicKey = ConfigurationManager.AppSettings["VapidPublicKey"]; var privateKey = ConfigurationManager.AppSettings["VapidPrivateKey"]; var subject = @"mailto: [email protected]"; Uri uri = new Uri(sub.Url); string audience = $"{uri.Scheme}{Uri.SchemeDelimiter}{uri.Host}"; var subscription = new WebPush.PushSubscription(sub.Url, sub.P256dh, sub.Auth); var vapidDetails = new WebPush.VapidDetails(subject, publicKey, privateKey); var client = new WebPush.WebPushClient(); try { var opts = new Dictionary <string, object>(); opts["vapidDetails"] = vapidDetails; var notification = new PushNotification(); notification.Title = "Something New Happened!"; notification.Body = "There was some activity on your account and you should go do something about it."; notification.Icon = "https://s3.amazonaws.com/images.productionhub.com/icons/asterisk.png"; notification.Data.Url = "/"; notification.Data.ListingId = "142484"; notification.Actions.Add(new NotificationAction { Action = "ignore", Title = "Ignore Lead", Icon = "https://s3.amazonaws.com/images.productionhub.com/icons/icon_remove_red.png" }); notification.Actions.Add(new NotificationAction { Action = "buy", Title = "Purchase Lead", Icon = "https://s3.amazonaws.com/images.productionhub.com/icons/icon_credit.png" }); var payload = JsonConvert.SerializeObject(notification, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); var requestDetails = client.GenerateRequestDetails(subscription, payload, opts); //await client.SendNotificationAsync(subscription, "payload", vapidDetails); var httpClient = new HttpClient(); await httpClient.SendAsync(requestDetails); return(Json(true)); } catch (WebPush.WebPushException exc) { return(new HttpStatusCodeResult(exc.StatusCode)); } } }
private static async Task SendNotificationToRecipients(IEnumerable <PushSubscription> recipients, PushNotification notification, string senderEmail, string publicKey, string privateKey, ILogger logger, CancellationToken cancelToken) { // This is run in a background thread. We should not access or update any mutable state. var vapidDetails = new WebPush.VapidDetails($"mailto:{senderEmail}", publicKey, privateKey); var client = new WebPush.WebPushClient(); var jsonSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }; foreach (var subscription in recipients) { if (!cancelToken.IsCancellationRequested) { await TrySendPushNotification(notification, subscription, vapidDetails, client, jsonSettings, logger); } } }
private static async Task TrySendPushNotification(PushNotification notification, PushSubscription recipient, WebPush.VapidDetails details, WebPush.WebPushClient client, JsonSerializerSettings serializerSettings, ILogger logger) { // This is run in a background thread. We should not access or update mutable state. try { var payload = JsonConvert.SerializeObject(notification, serializerSettings); var subscription = new WebPush.PushSubscription(recipient.Endpoint, recipient.Keys["p256dh"], recipient.Keys["auth"]); await client.SendNotificationAsync(subscription, payload, details); } catch (Exception error) { using (logger.BeginKeyValueScope("recipient", recipient)) using (logger.BeginKeyValueScope("publicKey", details.PublicKey)) using (logger.BeginKeyValueScope("publicKey", details.PrivateKey)) { logger.LogError(error, "Error sending push notification"); } } }
public async Task <ContentResult> Push([Required, FromBody] string name) { var user = await _userMgr.GetUserAsync(User); string ret; try { if (user.InGroupId == null) { ret = "not_in_group"; } else { if (user.WebSubscription == null) { ret = "s_not_subscribed"; } else { var rcvr = _groupsDb.Users.Where(c => c.InGroupId == user.InGroupId).SingleOrDefault(c => c.UserName == name); if (rcvr == null) { ret = "not_found"; } else { if (rcvr.InGroupId != user.InGroupId) { ret = "not_same_group"; } else { var web_subscription = StaticData.GetPushSubscription(rcvr.WebSubscription); if (web_subscription == null) { ret = "r_not_subscribed"; } else { if (rcvr.LastNotified > DateTime.UtcNow.Subtract(TimeSpan.FromHours(1)).Ticks) { ret = "is_notified_hour"; } else { if (rcvr.ConnectionId != null) { ret = "usr_active"; } else { ValueTask <Chatterer> groupN = _groupsDb.Users.FindAsync(rcvr.InGroupId); WebPush.WebPushClient client = new WebPush.WebPushClient(); WebPush.VapidDetails det = new WebPush.VapidDetails("mailto:[email protected]", _connections.vapidPublic, _connections.vapidPrivate); client.SetVapidDetails(det); var groupName = (await groupN).Group; var send_task = client.SendNotificationAsync(web_subscription, $"\"{groupName}\" by {user.UserName}"); rcvr.LastNotified = DateTime.UtcNow.Ticks; var save_task = _groupsDb.SaveChangesAsync(); await Task.WhenAll(send_task, save_task); ret = "OK"; } } } } } } } } catch (Exception e) { ret = e.Message; } return(Content(ret, "text/plain")); }
private static void doPushBackgroundWork() { try { WebPush.WebPushClient client = new WebPush.WebPushClient(); while (true) { try { if (!newEvents.IsEmpty) { // Accumulate a list of events we want to notify each subscription about. // Map subscriptionkey > event list Dictionary <string, List <EventToNotifyAbout> > accumulatedEvents = new Dictionary <string, List <EventToNotifyAbout> >(); List <User> users = Settings.data.GetAllUsers(); while (newEvents.TryDequeue(out EventToNotifyAbout en)) { foreach (User u in users) { string[] subscriptionKeys = u.GetPushNotificationSubscriptions(en.projectName, en.ev.FolderId); foreach (string key in subscriptionKeys) { List <EventToNotifyAbout> events; if (!accumulatedEvents.TryGetValue(key, out events)) { accumulatedEvents[key] = events = new List <EventToNotifyAbout>(); } events.Add(en); } } } if (accumulatedEvents.Count > 0) { WebPush.VapidDetails vapidDetails = new WebPush.VapidDetails(GetVapidSubject(), Settings.data.vapidPublicKey, Settings.data.vapidPrivateKey); // Build and send one notification to each affected subscription. foreach (KeyValuePair <string, List <EventToNotifyAbout> > kvp in accumulatedEvents) { string subscriptionKey = kvp.Key; List <EventToNotifyAbout> events = kvp.Value; WebPush.PushSubscription subscription = null; try { dynamic dyn = JsonConvert.DeserializeObject(subscriptionKey); subscription = new WebPush.PushSubscription(); subscription.Endpoint = dyn.endpoint; subscription.P256DH = dyn.keys.p256dh; subscription.Auth = dyn.keys.auth; } catch { } // For now, we'll just ignore any unparseable subscription keys. // I know this is asking for trouble later on, and I'm sorry for that. if (subscription != null) { StringBuilder sb = new StringBuilder(); PushMessage message = new PushMessage(Settings.data.systemName, events.Count + " new events:"); if (events.Count == 1) { EventToNotifyAbout en = events[0]; message.message = en.ev.EventType.ToString() + ": " + en.ev.SubType; message.eventid = en.ev.EventId; } // If all events are in the same project, set message.project so that clicking the notification can open the correct project. string projectName = events[0].projectName; if (events.All(en => en.projectName == projectName)) { message.project = projectName; // If all events are in the same folder, set message.folderid so that clicking the notification can open the correct folder. int folderId = events[0].ev.FolderId; if (events.All(en => en.ev.FolderId == folderId)) { message.folderid = folderId; } } try { client.SendNotification(subscription, message.ToString(), vapidDetails); } catch (Exception ex) { Logger.Debug(ex, "Failed to send push notification."); } } } } } Thread.Sleep(1000); } catch (ThreadAbortException) { } catch (Exception ex) { Emailer.SendError(null, "Error in PushManager", ex); } } } catch (ThreadAbortException) { } catch (Exception ex) { Logger.Debug(ex); } }