forked from Redth/PushSharp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into gcm-chrome
# By Redth (22) and others # Via Redth (5) and Jon (1) * master: (25 commits) Fixes Redth#186 Added some xml documentation to GCM Registration ID's. Close Redth#193 Switched to ToLowerInvariant(), closes Redth#192 Bumped nuget version for a beta release Update README.md Cleaned up ADM, now working by some preliminary tests :) Blackberry test to BIS works... Fixed header content type, added additional header type for xml Refactoring, and using PAP Fix documentation of DelayWhileIdle Redth#194 Converted to HttpClient End Rename nightmare Rename nightmare More rename refactoring Change BIS to Bis Revert "Temp Remove" Temp Remove Changing BIS to Bis Revert "Old dir name" Old dir name ... Conflicts: README.md
- Loading branch information
Showing
40 changed files
with
1,540 additions
and
241 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
|
||
namespace PushSharp.Amazon.Adm | ||
{ | ||
public class AdmMessageTooLargeException : Exception | ||
{ | ||
public AdmMessageTooLargeException(AdmNotification notification, string msg) : base(msg) | ||
{ | ||
Notification = notification; | ||
} | ||
|
||
public AdmNotification Notification { get; private set; } | ||
} | ||
|
||
public class AdmRateLimitExceededException : Exception | ||
{ | ||
public AdmRateLimitExceededException(AdmNotification notification, string msg) : base(msg) | ||
{ | ||
Notification = notification; | ||
} | ||
|
||
public AdmNotification Notification { get; private set; } | ||
} | ||
|
||
public class AdmSendException : Exception | ||
{ | ||
public AdmSendException(AdmNotification notification, string msg) : base(msg) | ||
{ | ||
Notification = notification; | ||
} | ||
|
||
public AdmNotification Notification { get; private set; } | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using PushSharp.Amazon.Adm; | ||
|
||
namespace PushSharp | ||
{ | ||
public static class AdmFluentNotification | ||
{ | ||
public static AdmNotification ForRegistrationId(this AdmNotification n, string registrationId) | ||
{ | ||
n.RegistrationId = registrationId; | ||
return n; | ||
} | ||
|
||
public static AdmNotification WithConsolidationKey(this AdmNotification n, string consolidationKey) | ||
{ | ||
n.ConsolidationKey = consolidationKey; | ||
return n; | ||
} | ||
|
||
public static AdmNotification WithExpiresAfter(this AdmNotification n, int expiresAfterSeconds) | ||
{ | ||
n.ExpiresAfter = expiresAfterSeconds; | ||
return n; | ||
} | ||
|
||
public static AdmNotification WithData(this AdmNotification n, IDictionary<string, string> data) | ||
{ | ||
if (n.Data == null) | ||
n.Data = new Dictionary<string, string>(); | ||
|
||
foreach (var item in data) | ||
{ | ||
if (!n.Data.ContainsKey(item.Key)) | ||
n.Data.Add(item.Key, item.Value); | ||
else | ||
n.Data[item.Key] = item.Value; | ||
} | ||
|
||
return n; | ||
} | ||
|
||
public static AdmNotification WithData(this AdmNotification n, string key, string value) | ||
{ | ||
if (n.Data == null) | ||
n.Data = new Dictionary<string, string>(); | ||
|
||
if (!n.Data.ContainsKey(key)) | ||
n.Data.Add(key, value); | ||
else | ||
n.Data[key] = value; | ||
|
||
return n; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
using System; | ||
using Newtonsoft.Json.Linq; | ||
using System.Collections.Generic; | ||
using PushSharp.Core; | ||
|
||
namespace PushSharp.Amazon.Adm | ||
{ | ||
public class AdmNotification : Notification | ||
{ | ||
public AdmNotification () | ||
{ | ||
Data = new Dictionary<string, string> (); | ||
} | ||
|
||
public Dictionary<string, string> Data { get; set; } | ||
|
||
public string ConsolidationKey { get;set; } | ||
|
||
public int? ExpiresAfter { get;set; } | ||
|
||
public string RegistrationId { get;set; } | ||
|
||
public string ToJson() | ||
{ | ||
var json = new JObject (); | ||
|
||
var data = new JObject(); | ||
|
||
if (Data != null && Data.Count > 0) | ||
{ | ||
foreach (var key in Data.Keys) | ||
data [key] = Data [key]; | ||
} | ||
|
||
json ["data"] = data; | ||
|
||
if (!string.IsNullOrEmpty (ConsolidationKey)) | ||
json ["consolidationKey"] = ConsolidationKey; | ||
|
||
if (ExpiresAfter.HasValue && ExpiresAfter.Value >= 0) | ||
json ["expiresAfter"] = ExpiresAfter.Value; | ||
|
||
return json.ToString(); | ||
} | ||
|
||
public override string ToString () | ||
{ | ||
return ToJson (); | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using PushSharp.Amazon.Adm; | ||
using PushSharp.Core; | ||
|
||
namespace PushSharp | ||
{ | ||
public static class GcmPushBrokerExtensions | ||
{ | ||
public static void RegisterGcmService(this PushBroker broker, AdmPushChannelSettings channelSettings, PushServiceSettings serviceSettings = null) | ||
{ | ||
broker.RegisterService<AdmNotification>(new AdmPushService(new AdmPushChannelFactory(), channelSettings, serviceSettings)); | ||
} | ||
|
||
public static AdmNotification GcmNotification(this PushBroker broker) | ||
{ | ||
return new AdmNotification(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
using System; | ||
using System.Net.Http.Headers; | ||
using PushSharp.Core; | ||
using System.Net.Http; | ||
using System.Threading.Tasks; | ||
using System.Collections.Generic; | ||
using Newtonsoft.Json.Linq; | ||
using System.Net; | ||
using System.Threading; | ||
|
||
namespace PushSharp.Amazon.Adm | ||
{ | ||
public class AdmPushChannel : IPushChannel | ||
{ | ||
AdmPushChannelSettings admSettings; | ||
long waitCounter = 0; | ||
HttpClient http = new HttpClient(); | ||
|
||
public AdmPushChannel (AdmPushChannelSettings admSettings) | ||
{ | ||
this.admSettings = admSettings; | ||
|
||
Expires = DateTime.UtcNow.AddYears(-1); | ||
|
||
//http.DefaultRequestHeaders.Add ("Content-Type", "application/json"); | ||
http.DefaultRequestHeaders.Add ("X-Amzn-Type-Version", "com.amazon.device.messaging.ADMMessage@1.0"); | ||
http.DefaultRequestHeaders.Add ("X-Amzn-Accept-Type", "com.amazon.device.messaging.ADMSendResult@1.0"); | ||
http.DefaultRequestHeaders.Add ("Accept", "application/json"); | ||
|
||
|
||
//http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", this.AccessToken); | ||
http.DefaultRequestHeaders.ConnectionClose = true; | ||
|
||
http.DefaultRequestHeaders.Remove("connection"); | ||
} | ||
|
||
public void SendNotification (INotification notification, SendNotificationCallbackDelegate callback) | ||
{ | ||
SendNotificationAsync (notification, callback); | ||
} | ||
|
||
void SendNotificationAsync(INotification notification, SendNotificationCallbackDelegate callback) | ||
{ | ||
var n = notification as AdmNotification; | ||
|
||
try | ||
{ | ||
Interlocked.Increment(ref waitCounter); | ||
|
||
if (string.IsNullOrEmpty(AccessToken) || Expires <= DateTime.UtcNow) | ||
{ | ||
UpdateAccessToken(); | ||
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", this.AccessToken); | ||
} | ||
|
||
var sc = new StringContent(n.ToJson()); | ||
sc.Headers.ContentType = new MediaTypeHeaderValue("application/json"); | ||
|
||
var response = http.PostAsync (string.Format(admSettings.AdmSendUrl, n.RegistrationId), sc).Result; | ||
|
||
if (response.IsSuccessStatusCode) | ||
{ | ||
callback(this, new SendNotificationResult(n)); | ||
return; | ||
} | ||
|
||
var data = response.Content.ReadAsStringAsync().Result; | ||
|
||
var json = JObject.Parse (data); | ||
|
||
var reason = json ["reason"].ToString (); | ||
|
||
|
||
var regId = n.RegistrationId; | ||
|
||
if (json["registrationID"] != null) | ||
regId = json["registrationID"].ToString(); | ||
|
||
switch (response.StatusCode) | ||
{ | ||
case HttpStatusCode.BadGateway: //400 | ||
case HttpStatusCode.BadRequest: // | ||
if ("InvalidRegistrationId".Equals (reason, StringComparison.InvariantCultureIgnoreCase)) | ||
{ | ||
callback (this, new SendNotificationResult (n) | ||
{ | ||
IsSubscriptionExpired = true, | ||
OldSubscriptionId = regId | ||
}); | ||
} | ||
callback(this, new SendNotificationResult(n, false, new AdmSendException(n, "Send Failed: " + reason))); | ||
break; | ||
case HttpStatusCode.Unauthorized: //401 | ||
//Access token expired | ||
this.AccessToken = null; | ||
callback(this, new SendNotificationResult(n, true)); | ||
break; | ||
case HttpStatusCode.Forbidden: //403 | ||
callback(this, new SendNotificationResult(n, true, new AdmRateLimitExceededException(n, "Rate Limit Exceeded (" + reason + ")"))); | ||
break; | ||
case HttpStatusCode.RequestEntityTooLarge: //413 | ||
callback(this, new SendNotificationResult(n, false, new AdmMessageTooLargeException(n, "ADM Message too Large, must be <= 6kb"))); | ||
break; | ||
default: | ||
callback(this, new SendNotificationResult(n, false, new AdmSendException(n, "Unknown Failure"))); | ||
break; | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
callback(this, new SendNotificationResult(n, false, new AdmSendException(n, "Unknown Failure"))); | ||
} | ||
finally | ||
{ | ||
Interlocked.Decrement (ref waitCounter); | ||
} | ||
} | ||
|
||
|
||
void UpdateAccessToken() | ||
{ | ||
var http = new HttpClient (); | ||
|
||
var param = new Dictionary<string, string> (); | ||
param.Add ("grant_type", "client_credentials"); | ||
param.Add ("scope", "messaging:push"); | ||
param.Add ("client_id", admSettings.ClientId); | ||
param.Add ("client_secret", admSettings.ClientSecret); | ||
|
||
|
||
var result = http.PostAsync (admSettings.AdmAuthUrl, new FormUrlEncodedContent (param)).Result; | ||
var data = result.Content.ReadAsStringAsync().Result; | ||
|
||
var json = JObject.Parse (data); | ||
|
||
this.AccessToken = json ["access_token"].ToString (); | ||
|
||
JToken expiresJson = new JValue(3540); | ||
if (json.TryGetValue("expires_in", out expiresJson)) | ||
Expires = DateTime.UtcNow.AddSeconds(expiresJson.ToObject<int>() - 60); | ||
else | ||
Expires = DateTime.UtcNow.AddSeconds(3540); | ||
|
||
if (result.Headers.Contains ("X-Amzn-RequestId")) | ||
this.LastAmazonRequestId = string.Join("; ", result.Headers.GetValues("X-Amzn-RequestId")); | ||
|
||
LastRequest = DateTime.UtcNow; | ||
} | ||
|
||
public DateTime Expires { get; set; } | ||
public DateTime LastRequest { get; private set; } | ||
public string LastAmazonRequestId { get; private set; } | ||
public string AccessToken { get; private set; } | ||
|
||
|
||
public void Dispose () | ||
{ | ||
var slept = 0; | ||
while (Interlocked.Read(ref waitCounter) > 0 && slept <= 5000) | ||
{ | ||
slept += 100; | ||
Thread.Sleep(100); | ||
} | ||
} | ||
|
||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
using PushSharp.Core; | ||
|
||
namespace PushSharp.Amazon.Adm | ||
{ | ||
public class AdmPushChannelSettings : IPushChannelSettings | ||
{ | ||
private const string ADM_SEND_URL = "https://api.amazon.com/messaging/registrations/{0}/messages"; | ||
private const string ADM_AUTH_URL = "https://api.amazon.com/auth/O2/token"; | ||
|
||
public AdmPushChannelSettings(string clientId, string clientSecret) | ||
{ | ||
this.ClientId = clientId; | ||
this.ClientSecret = clientSecret; | ||
this.AdmSendUrl = ADM_SEND_URL; | ||
this.AdmAuthUrl = ADM_AUTH_URL; | ||
} | ||
|
||
public string ClientId { get; private set; } | ||
public string ClientSecret { get; private set; } | ||
|
||
public string AdmSendUrl { get; private set; } | ||
public string AdmAuthUrl { get; private set; } | ||
|
||
public void OverrideSendUrl(string url) | ||
{ | ||
AdmSendUrl = url; | ||
} | ||
|
||
public void OverrideAuthUrl(string url) | ||
{ | ||
AdmAuthUrl = url; | ||
} | ||
} | ||
} |
Oops, something went wrong.