private void broker_OnNotificationSent(object sender, INotification notification) { try { int ID = Convert.ToInt32(notification.Tag); var notificationEntity = _databaseContext.PushNotification.FirstOrDefault(s => s.ID == ID); if (notificationEntity != null) { On(DisplayMessage, "ID " + notificationEntity.ID + " sent."); notificationEntity.Description = "(Processor) Notification sent."; notificationEntity.Status = (int)PushNotificationStatus.Processed; _databaseContext.SaveChanges(); } else { On(DisplayErrorMessage, "ERROR: Notification " + notificationEntity.ID + " not found in database!"); } } catch (Exception ex) { On(DisplayErrorMessage, "EX. ERROR: Get notification from DB: " + ex.Message); SimpleErrorLogger.LogError(ex); } finally { if (_isDirectSinglePush) { KillBroker(_databaseContext); } } }
/// <summary> /// This one will fail if your APNS, GCM and WIN registration data is not correct, also if a notification is malformed. /// </summary> /// <remarks>If this one fails check out the inner exception and the base object data for details!</remarks> private void broker_OnNotificationFailed(object sender, INotification notification, Exception error) { try { int ID = Convert.ToInt32(notification.Tag); var notificationEntity = _databaseContext.PushNotification.FirstOrDefault(s => s.ID == ID); if (notificationEntity != null) { On(DisplayErrorMessage, "ID " + notificationEntity.ID + " failed."); notificationEntity.Description = "(Processor) Notification failed."; notificationEntity.Status = (int)PushNotificationStatus.Error; _databaseContext.SaveChanges(); } else { On(DisplayErrorMessage, "ERROR: The failed notification " + notificationEntity.ID + " not found in database!"); } TryKillingTheImmediatePushBroker(); } catch (Exception ex) { On(DisplayErrorMessage, "Notification failed handler failed hard! :-)"); SimpleErrorLogger.LogError(ex); } On(DisplayErrorMessage, "Notification failed!"); SimpleErrorLogger.LogError(error); }
/// <summary> /// A processor method used to process multiple notifications at once. /// </summary> /// <param name="databaseContext">The current database context to be used for processing to the database.</param> /// <param name="pushNotifications">A list of push notifitcation entities to be processed and saved.</param> /// <returns>True if all OK, false if sth. goes wrong.</returns> public bool ProcessNotificationsImmediately(PushSharpDatabaseContext dbContext, IList <PushNotification> pushNotifications) { try { // runs the broker during the loop, then stops InitBroker(); _immediatePushCounter = pushNotifications.Count; foreach (var pushNotification in pushNotifications) { if (!ProcessNotification(dbContext, pushNotification, false)) { throw new Exception("INTERNAL EX. ERROR: Error on processing a single notification in ProcessNotifications method!"); } } // the broker can be stopped by the counter only, all should be processed... // KillBroker(_databaseContext); return(true); } catch (Exception ex) { On(DisplayErrorMessage, "EX. ERROR: Saving and pushing multiple notifications: " + ex.Message); SimpleErrorLogger.LogError(ex); return(false); } }
/// <summary> /// Handles authorization by checking the api key from the basic authorization header. /// </summary> /// <param name="actionContext">Request context.</param> /// <returns>True if valid, else false.</returns> private bool Authorize(HttpActionContext actionContext) { try { if (actionContext.Request.Headers.Authorization == null || actionContext.Request.Headers.Authorization.Scheme.ToLower() != "basic") { return(false); } string authEncoded = actionContext.Request.Headers.Authorization.Parameter ?? ""; string[] credentials = !authEncoded.Equals("") ? Helpers.DecodeBase64NTimes(authEncoded, 1).Split(':') : new string[] { " ", " " }; //validate the apikey from the basic auth key pair return(credentials[0] == "devug" && credentials[1] == "pushsharp"); } catch (Exception ex) { SimpleErrorLogger.LogError(ex); return(false); } }
/// <summary> /// Enqueues a single notification on the database. /// </summary> /// <param name="databaseContext">The database context used for saving.</param> /// <param name="pushNotification">A push notification to be saved for later processing.</param> /// <param name="saveAndDisposeContext"></param> /// <returns>True if all OK, false if not.</returns> public bool EnqueueNotificationOnDatabase(PushSharpDatabaseContext databaseContext, PushNotification pushNotification, bool saveAndDisposeContext = true) { try { databaseContext.PushNotification.Add(pushNotification); if (saveAndDisposeContext) { databaseContext.SaveChanges(); databaseContext.Dispose(); } return(true); } catch (Exception ex) { On(DisplayErrorMessage, "EX. ERROR: Enqueuing notification, DB save failed: " + ex.Message); SimpleErrorLogger.LogError(ex); return(false); } }
/// <summary> /// Enqueues a list of push notifications on the database to be pushed when the processor runs. /// </summary> /// <param name="databaseContext">The database context used for saving.</param> /// <param name="pushNotifications">The list of push notifications on the database to be pushed when the processor runs</param> /// <returns>True if all OK, false if not.</returns> public bool EnqueueNotificationsOnDatabase(PushSharpDatabaseContext databaseContext, List <PushNotification> pushNotifications) { try { foreach (var pushNotification in pushNotifications) { if (!EnqueueNotificationOnDatabase(databaseContext, pushNotification, false)) { throw new Exception("INTERNAL EX. ERROR: Error on adding a single notification in EnqueueNotificationsOnDatabase method!"); } } databaseContext.SaveChanges(); databaseContext.Dispose(); return(true); } catch (Exception ex) { On(DisplayErrorMessage, "EX. ERROR: Enqueuing notification, DB save failed: " + ex.Message); SimpleErrorLogger.LogError(ex); return(false); } }
private void broker_OnChannelException(object sender, IPushChannel pushChannel, Exception error) { On(DisplayErrorMessage, "Channel exception!"); SimpleErrorLogger.LogError(error); }
private void broker_OnServiceException(object sender, Exception error) { On(DisplayErrorMessage, "Push Notification service failure!"); SimpleErrorLogger.LogError(error); }
/// <summary> /// The main processor method used to process a single push notification, checks if the processing will be an immediate single push or regular thread looping model. /// Looks up for a single (or more if you wish) entity in the databae which has not been processed. /// Puts the fetched unprocessed push notification entity to processing over the Push Sharp API. /// Finally saves the state of processing. /// </summary> /// <param name="databaseContext">The current database context to be used for processing to the database.</param> /// <param name="pushNotification">A single push notification entity to be processed and saved.</param> /// <param name="isDirectSinglePush">Decides wethere the processing will take place immediately for the sent notification or will the method lookup from the database for a first unprocessed push notification.</param> /// <returns>True if all OK, false if not.</returns> public bool ProcessNotification(PushSharpDatabaseContext dbContext, PushNotification pushNotification = null, bool isDirectSinglePush = false) { _databaseContext = dbContext; _isDirectSinglePush = isDirectSinglePush; if (_isDirectSinglePush) { InitBroker(); } On(DisplayMessage, "Checking for unprocessed notifications..."); PushNotification notificationEntity = pushNotification; try { if (notificationEntity != null) { // save a new immediate unprocessed push notification _databaseContext.PushNotification.Add(pushNotification); _databaseContext.SaveChanges(); // reload the entity notificationEntity = _databaseContext.PushNotification .Where(x => x.ID == pushNotification.ID) .Include(x => x.MobileDevice) .Include(x => x.MobileDevice.Client) .FirstOrDefault(); } else // take one latest unprocessed notification, this can be changed to take any set size instead of one { notificationEntity = _databaseContext.PushNotification.FirstOrDefault(s => s.Status == (int)PushNotificationStatus.Unprocessed && s.CreatedAt <= DateTime.Now); } } catch (Exception ex) { On(DisplayErrorMessage, "EX. ERROR: Check for unprocessed notifications: " + ex.Message); SimpleErrorLogger.LogError(ex); } // Process i.e. push the push notification via PushSharp... if (notificationEntity != null) { bool messagePushed = true; On(DisplayStatusMessage, "Processing notification..."); On(DisplayMessage, "ID " + notificationEntity.ID + " for " + notificationEntity.MobileDevice.Client.Username + " -> " + notificationEntity.Message); //--------------------------- // ANDROID GCM NOTIFICATIONS //--------------------------- if (notificationEntity.MobileDevice.SmartphonePlatform == "android") { var gcmNotif = new GcmNotification() { Tag = notificationEntity.ID }; string msg = JsonConvert.SerializeObject(new { message = notificationEntity.Message }); gcmNotif.ForDeviceRegistrationId(notificationEntity.MobileDevice.PushNotificationsRegistrationID) .WithJson(msg); _broker.QueueNotification(gcmNotif); UpdateNotificationQueued(notificationEntity); } ////------------------------- //// APPLE iOS NOTIFICATIONS ////------------------------- else if (notificationEntity.MobileDevice.SmartphonePlatform == "ios") { var appleNotif = new AppleNotification() { Tag = notificationEntity.ID }; var msg = new AppleNotificationPayload(notificationEntity.Message); appleNotif.ForDeviceToken(notificationEntity.MobileDevice.PushNotificationsRegistrationID) .WithPayload(msg) .WithSound("default"); _broker.QueueNotification(appleNotif); UpdateNotificationQueued(notificationEntity); } //---------------------- // WINDOWS NOTIFICATIONS //---------------------- else if (notificationEntity.MobileDevice.SmartphonePlatform.Equals("wp") || notificationEntity.MobileDevice.SmartphonePlatform.Equals("wsa")) { var wNotif = new WindowsToastNotification() { Tag = notificationEntity.ID }; wNotif.ForChannelUri(notificationEntity.MobileDevice.PushNotificationsRegistrationID) .AsToastText02("PushSharp Notification", notificationEntity.Message); _broker.QueueNotification(wNotif); UpdateNotificationQueued(notificationEntity); } else { On(DisplayErrorMessage, "ERROR: Unsupported device OS: " + notificationEntity.MobileDevice.SmartphonePlatform); notificationEntity.Status = (int)PushNotificationStatus.Error; notificationEntity.ModifiedAt = DateTime.Now; notificationEntity.Description = "(Processor) Unsupported device OS: " + notificationEntity.MobileDevice.SmartphonePlatform; SimpleErrorLogger.LogError(new Exception("EX. ERROR: " + notificationEntity.Description)); messagePushed = false; } try { // Save changes to DB to keep the correct state of messages _databaseContext.SaveChanges(); // bubble out the single push error, else return true to continue iteration if (_isDirectSinglePush) { return(messagePushed); } return(true); } catch (Exception ex) { On(DisplayErrorMessage, "EX. ERROR: Updating notification, DB save failed: " + ex.Message); SimpleErrorLogger.LogError(ex); // bubble out the single push error, else return true to continue iteration if (_isDirectSinglePush) { return(false); } return(true); } finally { if (_isDirectSinglePush) { KillBroker(_databaseContext); } } } else { if (_isDirectSinglePush) { KillBroker(_databaseContext); } // no messages were queued, take a nap... return(false); } }