Skip to content

Commit 88270de

Browse files
committed
Fixed APN Enhanced format error detection
The APNS Enhanced format returns a response if a notification failed, but then it also closes the connection. This allows for a possibility of sending one notification, then sending a second one immediately after, and then getting notified that the first one failed. What happens in this case is that the second one looks like it's been sent to us, but apple closes the stream after the second one was sent, without acknowledging that it failed or wasn't sent. This means we have to wait for possible errors from each message on the connection before sending the next. This sucks, and means an added 250 ms delay to sending each message. This also means that to speed up message delivery, more Notification Channels are needed to scale across connections/threads. Unavoidable if the Enhanced format is to be used (which provides the ability to expire notifications as well as error reporting).
1 parent 3951329 commit 88270de

File tree

3 files changed

+42
-18
lines changed

3 files changed

+42
-18
lines changed

PushSharp.Apple/ApplePushChannel.cs

+37-17
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ public ApplePushChannel(ApplePushChannelSettings settings) : base(settings)
5757
taskCleanup.ContinueWith((t) => { var ex = t.Exception; }, TaskContinuationOptions.OnlyOnFaulted);
5858
taskCleanup.Start();
5959
}
60-
60+
61+
object streamWriteLock = new object();
6162
int reconnectDelay = 3000;
6263
float reconnectBackoffMultiplier = 1.5f;
6364

@@ -75,8 +76,6 @@ protected override void SendNotification(Common.Notification notification)
7576
{
7677
var appleNotification = notification as AppleNotification;
7778

78-
Connect();
79-
8079
bool isOkToSend = true;
8180
byte[] notificationData = new byte[] {};
8281

@@ -94,12 +93,19 @@ protected override void SendNotification(Common.Notification notification)
9493

9594
if (isOkToSend)
9695
{
96+
Connect();
97+
9798
try
98-
{
99-
stream.Write(notificationData);
100-
sentNotifications.TryAdd(appleNotification.Identifier, new SentNotification(appleNotification));
99+
{
100+
lock (streamWriteLock)
101+
{
102+
stream.Write(notificationData);
103+
Console.WriteLine("Wrote Notification: " + appleNotification.Identifier);
104+
sentNotifications.TryAdd(appleNotification.Identifier, new SentNotification(appleNotification));
105+
Thread.Sleep(150);
106+
}
101107
}
102-
catch
108+
catch (Exception ex)
103109
{
104110
this.QueueNotification(notification);
105111
} //If this failed, we probably had a networking error, so let's requeue the notification
@@ -117,28 +123,32 @@ public override void Stop(bool waitForQueueToDrain)
117123

118124
void Reader()
119125
{
120-
//try
121-
//{
126+
try
127+
{
122128
var result = stream.BeginRead(readBuffer, 0, 6, new AsyncCallback((asyncResult) =>
123129
{
124-
//try
125-
//{
130+
try
131+
{
126132
var bytesRead = stream.EndRead(asyncResult);
127133

134+
//Console.WriteLine("End Read: " + bytesRead + " bytes read.");
135+
128136
if (bytesRead > 0)
129137
{
130138
//Get the enhanced format response
131139
// byte 0 is always '1', byte 1 is the status, bytes 2,3,4,5 are the identifier of the notification
132140
var status = readBuffer[1];
133141
var identifier = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(readBuffer, 2));
134142

143+
Console.WriteLine(status + "=" + identifier);
144+
135145
SentNotification sentNotification = null;
136-
146+
137147
//Gets the matching notification and removes it from the sent queue at the same time
138148
sentNotifications.TryRemove(identifier, out sentNotification);
139149

140150
if (sentNotification != null)
141-
{
151+
{
142152
var nfex = new NotificationFailureException(status, sentNotification.Notification);
143153

144154
//Raise alert that notification failed
@@ -149,15 +159,24 @@ void Reader()
149159
Reader();
150160
}
151161
else
162+
{
152163
connected = false;
153-
//}
154-
//catch { }
164+
Console.WriteLine("Disconnected");
165+
}
166+
}
167+
catch (Exception ex)
168+
{
169+
Console.WriteLine(ex.ToString());
170+
}
155171

156172
//Otherwise, our connection was closed
157173

158174
}), null);
159-
//}
160-
// catch { }
175+
}
176+
catch (Exception ex)
177+
{
178+
Console.WriteLine(ex.ToString());
179+
}
161180
}
162181

163182

@@ -285,6 +304,7 @@ void connect()
285304
throw new ConnectionFailureException("SSL Stream is not Writable", null);
286305

287306
//Start reading from the stream asynchronously
307+
Console.WriteLine("Connect -> Reader()");
288308
Reader();
289309
}
290310

PushSharp.Sample/Program.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,17 @@ static void Main(string[] args)
4040
.WithSound("default")
4141
.WithBadge(7));
4242

43+
//System.Threading.Thread.Sleep(2000);
44+
4345
//Fluent construction of an iOS notification
4446
push.QueueNotification(NotificationFactory.Apple()
45-
.ForDeviceToken("2071737321559691b28fffa1aa4c8259d970fe0fc496794ad0486552fc9ec3db")
47+
.ForDeviceToken("0071737321559691b28fffa1aa4c8259d970fe0fc496794ad0486552fc9ec3db")
4648
.WithAlert("Alert Text 2!")
4749
.WithSound("default")
4850
.WithBadge(7));
4951

52+
//System.Threading.Thread.Sleep(2000);
53+
5054
//Fluent construction of an iOS notification
5155
push.QueueNotification(NotificationFactory.Apple()
5256
.ForDeviceToken("1071737321559691b28fffa1aa4c8259d970fe0fc496794ad0486552fc9ec3db")

PushSharp.suo

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)