react-native-tcp/ios/TcpSockets.m

193 lines
5.4 KiB
Mathematica
Raw Normal View History

//
// TcpSockets.m
// react-native-tcp
//
// Created by Andy Prock on 12/14/15.
// Copyright (c) 2015 Peel, Inc. All rights reserved.
//
#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;
}
RCT_EXPORT_MODULE()
@synthesize bridge = _bridge;
2015-12-22 23:53:08 +00:00
-(void)dealloc
{
2015-12-22 23:53:08 +00:00
for (NSNumber *cId in _clients.allKeys) {
[self destroyClient:cId callback:nil];
}
}
2015-12-15 00:16:45 +00:00
RCT_EXPORT_METHOD(createSocket:(nonnull NSNumber*)cId)
{
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]) {
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];
}
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-22 23:53:08 +00:00
TcpSocketClient* client = [self findClient:cId callback:nil];
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-15 00:16:45 +00:00
[self onError:client withError:error];
return;
}
}
RCT_EXPORT_METHOD(write:(nonnull NSNumber*)cId
string:(NSString *)base64String
encoded:(BOOL)encoded
callback:(RCTResponseSenderBlock)callback) {
2015-12-22 23:53:08 +00:00
TcpSocketClient* client = [self findClient:cId callback:callback];
if (!client) return;
// iOS7+
// TODO: use https://github.com/nicklockwood/Base64 for compatibility with earlier iOS versions
NSData *data = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
[client writeData:data callback:callback];
}
2015-12-15 00:16:45 +00:00
RCT_EXPORT_METHOD(end:(nonnull NSNumber*)cId
callback:(RCTResponseSenderBlock)callback) {
2015-12-22 23:53:08 +00:00
[self endClient:cId callback:callback];
2015-12-15 00:16:45 +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
{
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-event", client.id]
2015-12-15 00:16:45 +00:00
body:@{ @"event": @"connect" }];
}
2015-12-22 23:53:08 +00:00
- (void)onData:(NSNumber *)clientID data:(NSData *)data
{
NSString *base64String = [data base64EncodedStringWithOptions:0];
2015-12-15 00:16:45 +00:00
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-event", clientID]
body:@{ @"event": @"data", @"data": base64String }];
}
2015-12-22 23:53:08 +00:00
- (void)onClose:(TcpSocketClient*) client withError:(NSError *)err
2015-12-15 00:16:45 +00:00
{
if (err) {
[self onError:client withError:err];
}
2015-12-15 00:16:45 +00:00
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-event", client.id]
2015-12-15 00:16:45 +00:00
body:@{ @"event": @"close", @"data": err == nil ? @NO : @YES }];
2015-12-22 23:53:08 +00:00
client.clientDelegate = nil;
[_clients removeObjectForKey:client.id];
}
2015-12-15 00:16:45 +00:00
- (void)onError:(TcpSocketClient*) client withError:(NSError *)err {
2015-12-15 00:16:45 +00:00
NSString* msg = [[err userInfo] valueForKey:@"NSLocalizedFailureReason"];
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-event", client.id]
2015-12-15 00:16:45 +00:00
body:@{ @"event": @"error", @"data": @[msg] }];
}
2015-12-22 23:53:08 +00:00
-(TcpSocketClient*)findClient:(nonnull NSNumber*)cId callback:(RCTResponseSenderBlock)callback
{
2015-12-22 23:53:08 +00:00
TcpSocketClient *client = _clients[cId];
if (!client) {
if (!callback) {
RCTLogError(@"%@.missing callback parameter.", [self class]);
} else {
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
callback:(RCTResponseSenderBlock)callback
{
2015-12-22 23:53:08 +00:00
TcpSocketClient* client = [self findClient:cId callback:callback];
if (!client) return;
2015-12-15 00:16:45 +00:00
[client end];
if (callback) callback(@[]);
}
2015-12-22 23:53:08 +00:00
-(void)destroyClient:(nonnull NSNumber*)cId
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
-(void)onConnection:(TcpSocketClient *)client toClient:(NSNumber *)clientID {
_clients[client.id] = client;
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-event", clientID]
body:@{ @"event": @"connection", @"data": client.id }];
}
-(NSNumber*)generateRandomId {
int r = 0;
do {
r = (arc4random() % 1000) + 5001;
} while(_clients[@(r)]);
return @(r);
}
@end