Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Primus/Core/PrimusConnectOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@

@property (nonatomic) PrimusReconnectOptions *reconnect; // Stores the back off configuration
@property (nonatomic) NSArray *strategy; // Default reconnect strategies
@property (nonatomic) NSTimeInterval timeout; // Connection timeout duration
@property (nonatomic) NSTimeInterval ping; // Heartbeat ping interval
@property (nonatomic) NSTimeInterval pong; // Heartbeat pong response timeout.
@property (nonatomic) NSTimeInterval pingInterval; // Interval at which heartbeats are sent
@property (nonatomic) NSTimeInterval pingTimeout; // Max time to wait for a server ping
@property (nonatomic) BOOL autodetect; // Autodetect transformer and parser
@property (nonatomic) BOOL manual; // Manual connection
@property (nonatomic) BOOL stayConnectedInBackground; // Stay connected while app is in background
Expand Down
7 changes: 3 additions & 4 deletions Primus/Core/PrimusConnectOptions.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ - (id)initWithTransformerClass:(Class)transformerClass andStrategy:(NSArray *)st
if (self) {
_reconnect = [[PrimusReconnectOptions alloc] init];
_strategy = strategy ?: [NSArray array];
_timeout = 10;
_ping = 25;
_pong = 10;
_pingTimeout = 45;
_pingInterval = 30;
_autodetect = YES;
_manual = NO;
_stayConnectedInBackground = [[NSBundle.mainBundle objectForInfoDictionaryKey:@"UIBackgroundModes"] containsObject:@"voip"];
Expand All @@ -49,7 +48,7 @@ - (id)initWithTransformerClass:(Class)transformerClass andStrategy:(NSArray *)st

// Set the ping time to 10 minutes and 25 seconds
if (_stayConnectedInBackground) {
_ping = 625;
_pingTimeout = 625;
}
}

Expand Down
3 changes: 1 addition & 2 deletions Primus/Core/PrimusTimers.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
@interface PrimusTimers : NSObject

@property (nonatomic) GCDTimer *open;
@property (nonatomic) GCDTimer *ping;
@property (nonatomic) GCDTimer *pong;
@property (nonatomic) GCDTimer *heartbeat;
@property (nonatomic) GCDTimer *connect;
@property (nonatomic) GCDTimer *reconnect;

Expand Down
6 changes: 2 additions & 4 deletions Primus/Core/PrimusTimers.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ @implementation PrimusTimers
- (void)invalidateAll
{
[self.open invalidate];
[self.ping invalidate];
[self.pong invalidate];
[self.heartbeat invalidate];
[self.connect invalidate];
[self.reconnect invalidate];
}
Expand All @@ -24,8 +23,7 @@ - (void)clearAll
[self invalidateAll];

self.open = nil;
self.ping = nil;
self.pong = nil;
self.heartbeat = nil;
self.connect = nil;
self.reconnect = nil;
}
Expand Down
91 changes: 35 additions & 56 deletions Primus/Primus.m
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,6 @@ - (void)bindRealtimeEvents

_attemptOptions = nil;

[_timers.ping invalidate];
_timers.ping = nil;

[_timers.pong invalidate];
_timers.pong = nil;

[self emit:@"open"];

[self startHeartbeat];
Expand All @@ -115,13 +109,14 @@ - (void)bindRealtimeEvents
}
}];

[self on:@"incoming::pong" listener:^(NSNumber *time) {
[self on:@"incoming::ping" listener:^(NSNumber *time) {
_online = YES;

[_timers.pong invalidate];
_timers.pong = nil;

[self startHeartbeat];

[self emit:@"outgoing::pong", time];

[self write:[NSString stringWithFormat:@"primus::pong::%li", [time integerValue]]];
}];

[self on:@"incoming::error" listener:^(NSError *error) {
Expand Down Expand Up @@ -151,8 +146,8 @@ - (void)bindRealtimeEvents
return [self end];
}

if ([data hasPrefix:@"primus::pong::"]) {
return [self emit:@"incoming::pong", [data substringFromIndex:14]];
if ([data hasPrefix:@"primus::ping::"]) {
return [self emit:@"incoming::ping", [data substringFromIndex:14]];
}

if ([data hasPrefix:@"primus::id::"]) {
Expand Down Expand Up @@ -246,7 +241,7 @@ - (void)bindSystemEvents

// Send a keep-alive ping every 10 minutes while in background
[UIApplication.sharedApplication setKeepAliveTimeout:kBackgroundFetchIntervalMinimum handler:^{
[self ping];
[self startHeartbeat];
}];
}];

Expand All @@ -265,7 +260,7 @@ - (void)bindSystemEvents

// Reconnect to the server after resuming from background
if ([self.options.reconnect.strategies containsObject:@(kPrimusReconnectionStrategyOnline)]) {
[self ping];
[self startHeartbeat];
}
}];
#endif
Expand All @@ -292,16 +287,21 @@ - (void)initialize
if (!parserClass) {
parserClass = NSClassFromString([spec[@"parser"] uppercaseString]);
}

// Subtract 10 seconds from the maximum server-side timeout, as per the
// official Primus server-side documentation.
NSTimeInterval timeout = ((NSNumber *)spec[@"timeout"]).doubleValue - 10e3;

self.options.ping = MAX(MIN(self.options.ping, timeout / 1000.0f), 0);

// As we're given a timeout value on the server side, we need to update the + // As we're given a `pingInterval` value on the server side, we need to update
// the `pingTimeout` on the client.

if (self.options.pingInterval) {
NSTimeInterval value = self.options.pingInterval + round(self.options.pingInterval / 2);

self.options.pingTimeout = value;
} else {
self.options.pingTimeout = 45;
}
}

// If the calculated ping is smaller than the minimum allowed interval, disable background.
if (self.options.ping < kBackgroundFetchIntervalMinimum) {
if (self.options.pingTimeout < kBackgroundFetchIntervalMinimum) {
self.options.stayConnectedInBackground = NO;
}

Expand Down Expand Up @@ -449,47 +449,26 @@ - (void)id:(PrimusIdCallback)fn
[self once:@"incoming::id" listener:fn];
}

- (void)pong
{
[_timers.pong invalidate];
_timers.pong = nil;

if (self.online) {
return;
}

_online = NO;

[self emit:@"offline"];
[self emit:@"incoming::end", nil];
}

- (void)ping
{
[_timers.ping invalidate];
_timers.ping = nil;

[self write:[NSString stringWithFormat:@"primus::ping::%f", [[NSDate date] timeIntervalSince1970]]];
[self emit:@"outgoing::ping"];

_timers.pong = [GCDTimer scheduledTimerWithTimeInterval:self.options.pong repeats:NO block:^{
[self pong];
}];
}

/**
* Send a new heartbeat over the connection to ensure that we're still
* connected and our internet connection didn't drop. We cannot use server side
* heartbeats for this unfortunately.
* Set a timer that, upon expiration, closes the client.
*/
- (void)startHeartbeat
{
if (! self.options.ping) {
if (! self.options.pingTimeout) {
return;
}

_timers.ping = [GCDTimer scheduledTimerWithTimeInterval:self.options.ping repeats:NO block:^{
[self ping];
[_timers.heartbeat invalidate];
_timers.heartbeat = nil;

_timers.heartbeat = [GCDTimer scheduledTimerWithTimeInterval:self.options.pingTimeout repeats:NO block:^{
if (!self.online) {
return;
}

_online = NO;
[self emit:@"offline"];
[self emit:@"incoming::end", @"Heartbeat timed out"];
}];
}

Expand All @@ -503,7 +482,7 @@ - (void)startTimeout
_timers.connect = nil;
};

_timers.connect = [GCDTimer scheduledTimerWithTimeInterval:self.options.timeout repeats:NO block:^{
_timers.connect = [GCDTimer scheduledTimerWithTimeInterval:self.options.pingInterval repeats:NO block:^{
stop();

if (kPrimusReadyStateOpen == self.readyState || _attemptOptions) {
Expand Down