Skip to content

Commit

Permalink
Merge branch 'master' into gcm-chrome
Browse files Browse the repository at this point in the history
# 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
Redth committed May 30, 2013
2 parents 4308012 + 1684c5c commit 3addbcf
Show file tree
Hide file tree
Showing 40 changed files with 1,540 additions and 241 deletions.
Binary file added NuGet/PushSharp.2.1.0.0-beta.nupkg
Binary file not shown.
37 changes: 37 additions & 0 deletions PushSharp.Amazon.Adm/AdmExceptions.cs
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; }
}

}
58 changes: 58 additions & 0 deletions PushSharp.Amazon.Adm/AdmFluentNotification.cs
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;
}
}
}
52 changes: 52 additions & 0 deletions PushSharp.Amazon.Adm/AdmNotification.cs
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 ();
}
}
}

22 changes: 22 additions & 0 deletions PushSharp.Amazon.Adm/AdmPushBrokerExtensions.cs
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();
}
}
}
168 changes: 168 additions & 0 deletions PushSharp.Amazon.Adm/AdmPushChannel.cs
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);
}
}

}
}

37 changes: 37 additions & 0 deletions PushSharp.Amazon.Adm/AdmPushChannelSettings.cs
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;
}
}
}
Loading

0 comments on commit 3addbcf

Please sign in to comment.