2015-12-23 18:56:33 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2015-present, Peel Technologies, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
2015-12-04 17:44:16 +00:00
|
|
|
|
|
|
|
#import "RCTAssert.h"
|
|
|
|
#import "RCTBridge.h"
|
|
|
|
#import "RCTConvert.h"
|
|
|
|
#import "RCTEventDispatcher.h"
|
|
|
|
#import "RCTLog.h"
|
|
|
|
#import "TcpSockets.h"
|
|
|
|
#import "TcpSocketClient.h"
|
|
|
|
|
|
|
|
@implementation TcpSockets
|
2015-12-22 23:53:08 +00:00
|
|
|
{
|
|
|
|
NSMutableDictionary<NSNumber *,TcpSocketClient *> *_clients;
|
|
|
|
}
|
2015-12-04 17:44:16 +00:00
|
|
|
|
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
|
|
|
|
@synthesize bridge = _bridge;
|
|
|
|
|
2015-12-22 23:53:08 +00:00
|
|
|
-(void)dealloc
|
2015-12-04 17:44:16 +00:00
|
|
|
{
|
2015-12-22 23:53:08 +00:00
|
|
|
for (NSNumber *cId in _clients.allKeys) {
|
|
|
|
[self destroyClient:cId callback:nil];
|
|
|
|
}
|
2015-12-04 17:44:16 +00:00
|
|
|
}
|
|
|
|
|
2015-12-15 00:16:45 +00:00
|
|
|
RCT_EXPORT_METHOD(createSocket:(nonnull NSNumber*)cId)
|
2015-12-04 17:44:16 +00:00
|
|
|
{
|
|
|
|
if (!cId) {
|
|
|
|
RCTLogError(@"%@.createSocket called with nil id parameter.", [self class]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-12-22 23:53:08 +00:00
|
|
|
if (!_clients) {
|
|
|
|
_clients = [NSMutableDictionary new];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_clients[cId]) {
|
2015-12-04 17:44:16 +00:00
|
|
|
RCTLogError(@"%@.createSocket called twice with the same id.", [self class]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-12-22 23:53:08 +00:00
|
|
|
_clients[cId] = [TcpSocketClient socketClientWithId:cId andConfig:self];
|
2015-12-04 17:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(connect:(nonnull NSNumber*)cId
|
|
|
|
host:(NSString *)host
|
2015-12-15 00:16:45 +00:00
|
|
|
port:(int)port
|
|
|
|
withOptions:(NSDictionary *)options)
|
2015-12-04 17:44:16 +00:00
|
|
|
{
|
2015-12-22 23:53:08 +00:00
|
|
|
TcpSocketClient* client = [self findClient:cId callback:nil];
|
2015-12-04 17:44:16 +00:00
|
|
|
if (!client) return;
|
|
|
|
|
|
|
|
NSError *error = nil;
|
2015-12-15 00:16:45 +00:00
|
|
|
if (![client connect:host port:port withOptions:options error:&error])
|
2015-12-04 17:44:16 +00:00
|
|
|
{
|
2015-12-15 00:16:45 +00:00
|
|
|
[self onError:client withError:error];
|
2015-12-04 17:44:16 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(write:(nonnull NSNumber*)cId
|
2015-12-17 16:10:00 +00:00
|
|
|
string:(NSString *)base64String
|
2015-12-04 17:44:16 +00:00
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
2015-12-22 23:53:08 +00:00
|
|
|
TcpSocketClient* client = [self findClient:cId callback:callback];
|
2015-12-04 17:44:16 +00:00
|
|
|
if (!client) return;
|
|
|
|
|
2015-12-17 16:10:00 +00:00
|
|
|
// iOS7+
|
|
|
|
// TODO: use https://github.com/nicklockwood/Base64 for compatibility with earlier iOS versions
|
|
|
|
NSData *data = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
|
2015-12-04 17:44:16 +00:00
|
|
|
[client writeData:data callback:callback];
|
|
|
|
}
|
|
|
|
|
2015-12-15 00:16:45 +00:00
|
|
|
RCT_EXPORT_METHOD(end:(nonnull NSNumber*)cId
|
2015-12-04 17:44:16 +00:00
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
2015-12-22 23:53:08 +00:00
|
|
|
[self endClient:cId callback:callback];
|
2015-12-15 00:16:45 +00:00
|
|
|
}
|
|
|
|
|
2015-12-17 16:10:00 +00:00
|
|
|
RCT_EXPORT_METHOD(destroy:(nonnull NSNumber*)cId
|
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
2015-12-22 23:53:08 +00:00
|
|
|
[self destroyClient:cId callback:callback];
|
2015-12-15 00:16:45 +00:00
|
|
|
}
|
|
|
|
|
2015-12-22 23:53:08 +00:00
|
|
|
RCT_EXPORT_METHOD(listen:(nonnull NSNumber*)cId
|
|
|
|
host:(NSString *)host
|
|
|
|
port:(int)port)
|
|
|
|
{
|
|
|
|
TcpSocketClient* client = [self findClient:cId callback:nil];
|
|
|
|
if (!client) return;
|
|
|
|
|
|
|
|
NSError *error = nil;
|
|
|
|
if (![client listen:host port:port error:&error])
|
|
|
|
{
|
|
|
|
[self onError:client withError:error];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)onConnect:(TcpSocketClient*) client
|
2015-12-15 00:16:45 +00:00
|
|
|
{
|
2015-12-24 19:18:51 +00:00
|
|
|
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-connect", client.id]
|
|
|
|
body:[client getAddress]];
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void)onConnection:(TcpSocketClient *)client toClient:(NSNumber *)clientID {
|
|
|
|
_clients[client.id] = client;
|
|
|
|
|
|
|
|
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-connection", clientID]
|
2015-12-27 06:34:17 +00:00
|
|
|
body:@{ @"id": client.id, @"address" : [client getAddress] }];
|
2015-12-04 17:44:16 +00:00
|
|
|
}
|
|
|
|
|
2015-12-22 23:53:08 +00:00
|
|
|
- (void)onData:(NSNumber *)clientID data:(NSData *)data
|
2015-12-04 17:44:16 +00:00
|
|
|
{
|
|
|
|
NSString *base64String = [data base64EncodedStringWithOptions:0];
|
2015-12-24 19:18:51 +00:00
|
|
|
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-data", clientID]
|
|
|
|
body:base64String];
|
2015-12-15 00:16:45 +00:00
|
|
|
}
|
|
|
|
|
2015-12-22 23:53:08 +00:00
|
|
|
- (void)onClose:(TcpSocketClient*) client withError:(NSError *)err
|
2015-12-15 00:16:45 +00:00
|
|
|
{
|
2015-12-17 16:10:00 +00:00
|
|
|
if (err) {
|
|
|
|
[self onError:client withError:err];
|
|
|
|
}
|
2015-12-15 00:16:45 +00:00
|
|
|
|
2015-12-24 19:18:51 +00:00
|
|
|
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-close", client.id]
|
|
|
|
body:err == nil ? @NO : @YES];
|
2015-12-15 00:16:45 +00:00
|
|
|
|
2015-12-22 23:53:08 +00:00
|
|
|
client.clientDelegate = nil;
|
2015-12-17 16:10:00 +00:00
|
|
|
[_clients removeObjectForKey:client.id];
|
|
|
|
}
|
2015-12-15 00:16:45 +00:00
|
|
|
|
2015-12-17 16:10:00 +00:00
|
|
|
- (void)onError:(TcpSocketClient*) client withError:(NSError *)err {
|
2015-12-23 23:14:41 +00:00
|
|
|
NSString *msg = [err userInfo][@"NSLocalizedFailureReason"] ?: [err userInfo][@"NSLocalizedDescription"];
|
2015-12-24 19:18:51 +00:00
|
|
|
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-error", client.id]
|
|
|
|
body:msg];
|
2015-12-15 00:16:45 +00:00
|
|
|
|
2015-12-04 17:44:16 +00:00
|
|
|
}
|
|
|
|
|
2015-12-22 23:53:08 +00:00
|
|
|
-(TcpSocketClient*)findClient:(nonnull NSNumber*)cId callback:(RCTResponseSenderBlock)callback
|
2015-12-04 17:44:16 +00:00
|
|
|
{
|
2015-12-22 23:53:08 +00:00
|
|
|
TcpSocketClient *client = _clients[cId];
|
2015-12-04 17:44:16 +00:00
|
|
|
if (!client) {
|
|
|
|
if (!callback) {
|
|
|
|
RCTLogError(@"%@.missing callback parameter.", [self class]);
|
2015-12-17 16:10:00 +00:00
|
|
|
} else {
|
2015-12-04 17:44:16 +00:00
|
|
|
callback(@[[NSString stringWithFormat:@"no client found with id %@", cId]]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
return client;
|
|
|
|
}
|
|
|
|
|
2015-12-22 23:53:08 +00:00
|
|
|
-(void)endClient:(nonnull NSNumber*)cId
|
2015-12-04 17:44:16 +00:00
|
|
|
callback:(RCTResponseSenderBlock)callback
|
|
|
|
{
|
2015-12-22 23:53:08 +00:00
|
|
|
TcpSocketClient* client = [self findClient:cId callback:callback];
|
2015-12-04 17:44:16 +00:00
|
|
|
if (!client) return;
|
|
|
|
|
2015-12-15 00:16:45 +00:00
|
|
|
[client end];
|
2015-12-04 17:44:16 +00:00
|
|
|
|
|
|
|
if (callback) callback(@[]);
|
|
|
|
}
|
|
|
|
|
2015-12-22 23:53:08 +00:00
|
|
|
-(void)destroyClient:(nonnull NSNumber*)cId
|
2015-12-17 16:10:00 +00:00
|
|
|
callback:(RCTResponseSenderBlock)callback
|
2015-12-15 00:16:45 +00:00
|
|
|
{
|
2015-12-22 23:53:08 +00:00
|
|
|
TcpSocketClient* client = [self findClient:cId callback:nil];
|
2015-12-15 00:16:45 +00:00
|
|
|
if (!client) return;
|
|
|
|
|
|
|
|
[client destroy];
|
|
|
|
[_clients removeObjectForKey:cId];
|
|
|
|
}
|
|
|
|
|
2015-12-22 23:53:08 +00:00
|
|
|
-(NSNumber*)generateRandomId {
|
|
|
|
int r = 0;
|
|
|
|
do {
|
|
|
|
r = (arc4random() % 1000) + 5001;
|
|
|
|
} while(_clients[@(r)]);
|
|
|
|
|
|
|
|
return @(r);
|
2015-12-04 17:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|