/// <summary> /// Initialize a connection the the Apple Push Notification Service (APNS) and deliver a new deal notification /// payload to all registered devices in the database. /// </summary> /// <param name="currentHeadline">The headline to be sent in the push notification payload</param> private void SendNotifications(int id, string headline) { //configure and start Apple APNS PushNotification push; try { push = new PushNotification(false, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, this.key), ConfigurationManager.AppSettings["certPassword"]); } catch (Exception e) { LogError("!Failed to start service.", e); return; } IList<DeviceToken> deviceTokens = null; try { //get a list of all registered device tokens using (PushModelContainer context = new PushModelContainer()) { var q = (from dt in context.DeviceTokens //where dt.Development.Equals(true) where dt.Development.Equals(this.isDevelopment) where dt.AppName.Equals(this.appName) where dt.Active.Equals(true) select dt); deviceTokens = q.ToList<DeviceToken>(); foreach (DeviceToken deviceToken in deviceTokens) { if (deviceToken.BadgeCount > 50) { deviceToken.BadgeCount = 0; } else { deviceToken.BadgeCount++; } } context.SaveChanges(); } } catch (Exception e) { LogError("!Failed to fetch device tokens.", e); return; } //hold a list of payloads to be pushed var payloads = new List<NotificationPayload> {}; //loop for every registered device token foreach (DeviceToken deviceToken in deviceTokens) { //add the payload to the list var payload = new NotificationPayload(deviceToken.Token, ModifyHeadline(headline), deviceToken.BadgeCount, "default"); payload.AddCustom("id", id); payloads.Add(payload); } //send the payloads and get a list of rejected payloads for deletion Logger.Info(@" >Delivering payloads..."); var rejectedTokens = push.SendToApple(payloads); if (rejectedTokens.Count > 0) { //deactivate all rejected device tokens using (PushModelContainer context = new PushModelContainer()) { foreach (var rejectedToken in rejectedTokens) { Logger.Warn(@"Deactivating token: " + rejectedToken); DeviceToken deviceToken = (from dt in context.DeviceTokens where dt.Token.Equals(rejectedToken) select dt).FirstOrDefault(); if (deviceToken != null) { deviceToken.Active = false; } } context.SaveChanges(); } } Logger.Info(@" >All payloads delivered."); Logger.Info(@""); }
/// <summary> /// Access the Passwird Deals API for a list of deals. Checks the newest deal posted against /// a deal that was persisted to the database. If they do not match, push notifications are sent /// to all registered devices for the new deal. /// </summary> private void PollDeals() { bool isNewDeal = false, shouldSendNotification = false; LastDeal lastDeal; Deal currentDeal; RootDeal rootDeal; //grab a copy of current deals using (WebClient wc = new WebClient()) { try { //parse deal json into objects var json = wc.DownloadString(this.apiUrl); rootDeal = JsonConvert.DeserializeObject<RootDeal>(json); currentDeal = new Deal(rootDeal.deals[0]); } catch (Exception e) { LogError("!Failed to parse deals.", e); return; } } //return if no deals were in the collection if (rootDeal.deals.Count <= 0) { LogError("!No deals found.", null); return; } try { //get the most recent lastDeal saved to the database for comparison using (PushModelContainer context = new PushModelContainer()) { lastDeal = (from ld in context.LastDeals orderby ld.id descending select ld).FirstOrDefault(); } } catch (Exception e) { LogError("!Could not fetch last deal.", e); return; } //compare the last deal with the current deal //considering the headline to be unique key for deals, not ideal obviously //but I am limited in what I can get back from scraping the passwird site if (currentDeal.headline == @"Currently experiencing technical difficulties.") { isNewDeal = false; } else if (currentDeal.headline.Truncate(25) != lastDeal.headline.Truncate(25)) { isNewDeal = true; } if (isNewDeal) { //found a new deal, send a notification Logger.Info(@" >Found new deal."); Logger.Info(@" >" + currentDeal.headline); try { //save the current deal as the last deal to the database using (PushModelContainer context = new PushModelContainer()) { //save the current deal as a new last deal record in the database //v1 lastDeal = new LastDeal(); lastDeal.headline = currentDeal.headline; lastDeal.datePosted = currentDeal.datePosted; lastDeal.body = currentDeal.body; lastDeal.image = currentDeal.image; lastDeal.isExpired = currentDeal.isExpired; //v2 lastDeal.C_id = currentDeal.id; lastDeal.legacy = currentDeal.legacy; lastDeal.hot = currentDeal.hot; lastDeal.free = currentDeal.free; lastDeal.price = currentDeal.price; lastDeal.slug = currentDeal.slug; lastDeal.sHeadline = currentDeal.sHeadline; lastDeal.author = currentDeal.author; lastDeal.expirationDate = currentDeal.expirationDate; context.LastDeals.AddObject(lastDeal); context.SaveChanges(); } shouldSendNotification = true; if (lastDeal.headline == "root") shouldSendNotification = true; } catch (Exception e) { LogError("!Failed to save last deal.", e); return; } } //if a new deal was found, start sending notifications if (shouldSendNotification) { SendNotifications(lastDeal.id, currentDeal.headline); } }