forked from ddunkin/cometclient
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
856 additions
and
10 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
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
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
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,57 @@ | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
|
||
@class DDCometClientOperation; | ||
@class DDCometMessage; | ||
@class DDCometSubscription; | ||
@protocol DDCometClientDelegate; | ||
@protocol DDQueue; | ||
|
||
typedef enum { | ||
DDCometStateDisconnected, | ||
DDCometStateConnecting, | ||
DDCometStateConnected | ||
} DDCometState; | ||
|
||
@interface DDCometClient : NSObject { | ||
@private | ||
NSURL *m_endpointURL; | ||
volatile int32_t m_messageCounter; | ||
NSMutableDictionary *m_pendingSubscriptions; // by id | ||
NSMutableArray *m_subscriptions; | ||
DDCometState m_state; | ||
id<DDQueue> m_outgoingQueue; | ||
id<DDQueue> m_incomingQueue; | ||
NSOperationQueue *m_communicationOperationQueue; | ||
} | ||
|
||
@property (nonatomic, readonly) NSString *clientID; | ||
@property (nonatomic, readonly) NSURL *endpointURL; | ||
@property (nonatomic, assign) id<DDCometClientDelegate> delegate; | ||
|
||
- (id)initWithURL:(NSURL *)endpointURL; | ||
- (BOOL)handshake:(NSError **)error; | ||
- (BOOL)connect:(NSError **)error; | ||
- (void)disconnect; | ||
- (BOOL)subscribeToChannel:(NSString *)channel target:(id)target selector:(SEL)selector error:(NSError **)error; | ||
- (BOOL)unsubsubscribeFromChannel:(NSString *)channel target:(id)target selector:(SEL)selector error:(NSError **)error; | ||
- (BOOL)publishMessage:(DDCometMessage *)message toChannel:(NSString *)channel error:(NSError **)error; | ||
|
||
@end | ||
|
||
@interface DDCometClient (Internal) | ||
|
||
- (id<DDQueue>)outgoingQueue; | ||
- (id<DDQueue>)incomingQueue; | ||
- (void)operationDidFinish:(DDCometClientOperation *)operation; | ||
|
||
@end | ||
|
||
@protocol DDCometClientDelegate <NSObject> | ||
@optional | ||
- (void)cometClientHandshakeDidSucceed:(DDCometClient *)client; | ||
- (void)cometClient:(DDCometClient *)client handshakeDidFailWithError:(NSError *)error; | ||
- (void)cometClient:(DDCometClient *)client subscriptionDidSucceed:(DDCometSubscription *)subscription; | ||
- (void)cometClient:(DDCometClient *)client subscription:(DDCometSubscription *)subscription didFailWithError:(NSError *)error; | ||
@end |
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,208 @@ | ||
|
||
#import "DDCometClient.h" | ||
#import <libkern/OSAtomic.h> | ||
#import "DDCometClientOperation.h" | ||
#import "DDCometMessage.h" | ||
#import "DDCometSubscription.h" | ||
#import "NSMutableArray+Queue.h" | ||
|
||
|
||
@interface DDCometClient () | ||
|
||
- (NSString *)nextMessageID; | ||
- (void)sendMessage:(DDCometMessage *)message; | ||
- (void)handleMessage:(DDCometMessage *)message; | ||
|
||
@end | ||
|
||
@implementation DDCometClient | ||
|
||
@synthesize clientID = m_clientID, | ||
endpointURL = m_endpointURL, | ||
delegate = m_delegate; | ||
|
||
- (id)initWithURL:(NSURL *)endpointURL | ||
{ | ||
if ((self = [super init])) | ||
{ | ||
m_endpointURL = [endpointURL retain]; | ||
m_pendingSubscriptions = [[NSMutableDictionary alloc] init]; | ||
m_subscriptions = [[NSMutableArray alloc] init]; | ||
m_outgoingQueue = [[NSMutableArray alloc] init]; | ||
m_incomingQueue = [[NSMutableArray alloc] init]; | ||
m_communicationOperationQueue = [[NSOperationQueue alloc] init]; | ||
[m_communicationOperationQueue setMaxConcurrentOperationCount:1]; | ||
[self performSelectorInBackground:@selector(processIncomingMessages) withObject:nil]; | ||
} | ||
return self; | ||
} | ||
|
||
- (void)dealloc | ||
{ | ||
[m_communicationOperationQueue release]; | ||
[m_incomingQueue release]; | ||
[m_outgoingQueue release]; | ||
[m_subscriptions release]; | ||
[m_pendingSubscriptions release]; | ||
[m_endpointURL release]; | ||
[m_clientID release]; | ||
[super dealloc]; | ||
} | ||
|
||
- (BOOL)handshake:(NSError **)error | ||
{ | ||
m_state = DDCometStateConnecting; | ||
|
||
DDCometMessage *message = [DDCometMessage messageWithChannel:@"/meta/handshake"]; | ||
message.version = @"1.0"; | ||
message.supportedConnectionTypes = [NSArray arrayWithObject:@"long-polling"]; | ||
|
||
[self sendMessage:message]; | ||
return YES; | ||
} | ||
|
||
- (BOOL)connect:(NSError **)error | ||
{ | ||
return YES; | ||
} | ||
|
||
- (void)disconnect | ||
{ | ||
|
||
} | ||
|
||
- (BOOL)subscribeToChannel:(NSString *)channel target:(id)target selector:(SEL)selector error:(NSError **)error | ||
{ | ||
DDCometMessage *message = [DDCometMessage messageWithChannel:@"/meta/subscribe"]; | ||
message.ID = [self nextMessageID]; | ||
message.subscription = channel; | ||
DDCometSubscription *subscription = [[[DDCometSubscription alloc] initWithChannel:channel target:target selector:selector] autorelease]; | ||
@synchronized(m_pendingSubscriptions) | ||
{ | ||
[m_pendingSubscriptions setObject:subscription forKey:message.ID]; | ||
} | ||
[self sendMessage:message]; | ||
return YES; | ||
} | ||
|
||
- (BOOL)unsubsubscribeFromChannel:(NSString *)channel target:(id)target selector:(SEL)selector error:(NSError **)error | ||
{ | ||
return YES; | ||
} | ||
|
||
- (BOOL)publishMessage:(DDCometMessage *)message toChannel:(NSString *)channel error:(NSError **)error | ||
{ | ||
return YES; | ||
} | ||
|
||
#pragma mark - | ||
|
||
- (id<DDQueue>)outgoingQueue | ||
{ | ||
return m_outgoingQueue; | ||
} | ||
|
||
- (id<DDQueue>)incomingQueue | ||
{ | ||
return m_incomingQueue; | ||
} | ||
|
||
- (void)operationDidFinish:(DDCometClientOperation *)operation | ||
{ | ||
if (m_state != DDCometStateDisconnected) | ||
[m_communicationOperationQueue addOperation:[[[DDCometClientOperation alloc] initWithClient:self] autorelease]]; | ||
} | ||
|
||
#pragma mark - | ||
|
||
- (NSString *)nextMessageID | ||
{ | ||
return [NSString stringWithFormat:@"%d", OSAtomicIncrement32Barrier(&m_messageCounter)]; | ||
} | ||
|
||
- (void)sendMessage:(DDCometMessage *)message | ||
{ | ||
message.clientID = m_clientID; | ||
if (!message.ID) | ||
message.ID = [self nextMessageID]; | ||
[m_outgoingQueue addObject:message]; | ||
|
||
if ([m_communicationOperationQueue operationCount] == 0) | ||
[m_communicationOperationQueue addOperation:[[[DDCometClientOperation alloc] initWithClient:self] autorelease]]; | ||
} | ||
|
||
- (void)handleMessage:(DDCometMessage *)message | ||
{ | ||
NSLog(@"%@", message); | ||
NSString *channel = message.channel; | ||
if ([channel isEqualToString:@"/meta/handshake"]) | ||
{ | ||
if ([message.successful boolValue]) | ||
{ | ||
m_clientID = [message.clientID retain]; | ||
m_state = DDCometStateConnected; | ||
if (m_delegate && [m_delegate respondsToSelector:@selector(cometClientHandshakeDidSucceed:)]) | ||
[m_delegate cometClientHandshakeDidSucceed:self]; | ||
} | ||
else | ||
{ | ||
m_state = DDCometStateDisconnected; | ||
if (m_delegate && [m_delegate respondsToSelector:@selector(cometClient:handshakeDidFailWithError:)]) | ||
[m_delegate cometClient:self handshakeDidFailWithError:message.error]; | ||
} | ||
} | ||
else if ([channel isEqualToString:@"/meta/subscribe"]) | ||
{ | ||
DDCometSubscription *subscription = nil; | ||
@synchronized(m_pendingSubscriptions) | ||
{ | ||
subscription = [[[m_pendingSubscriptions objectForKey:message.ID] retain] autorelease]; | ||
if (subscription) | ||
[m_pendingSubscriptions removeObjectForKey:message.ID]; | ||
} | ||
if ([message.successful boolValue]) | ||
{ | ||
@synchronized(m_subscriptions) | ||
{ | ||
[m_subscriptions addObject:subscription]; | ||
} | ||
if (m_delegate && [m_delegate respondsToSelector:@selector(cometClient:subscriptionDidSucceed:)]) | ||
[m_delegate cometClient:self subscriptionDidSucceed:subscription]; | ||
} | ||
else | ||
{ | ||
if (m_delegate && [m_delegate respondsToSelector:@selector(cometClient:subscription:didFailWithError:)]) | ||
[m_delegate cometClient:self subscription:subscription didFailWithError:message.error]; | ||
} | ||
} | ||
else | ||
{ | ||
NSMutableArray *subscriptions = [NSMutableArray array]; | ||
@synchronized(m_subscriptions) | ||
{ | ||
for (DDCometSubscription *subscription in m_subscriptions) | ||
{ | ||
if ([channel isEqualToString:subscription.channel]) // TODO: handle wildcards | ||
[subscriptions addObject:subscription]; | ||
} | ||
} | ||
for (DDCometSubscription *subscription in subscriptions) | ||
[subscription.target performSelector:subscription.selector withObject:message]; | ||
} | ||
} | ||
|
||
- (void)processIncomingMessages | ||
{ | ||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | ||
|
||
while (YES) | ||
{ | ||
DDCometMessage *message; | ||
while ((message = [m_incomingQueue removeObject])) | ||
[self handleMessage:message]; | ||
[NSThread sleepForTimeInterval:0.1]; | ||
} | ||
|
||
[pool release]; | ||
} | ||
@end |
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,15 @@ | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
|
||
@class DDCometClient; | ||
|
||
@interface DDCometClientOperation : NSOperation { | ||
@private | ||
DDCometClient *m_client; | ||
NSMutableData *m_responseData; | ||
} | ||
|
||
- (id)initWithClient:(DDCometClient *)client; | ||
|
||
@end |
Oops, something went wrong.