set version to 0.0.1
end now closes the socket after writes are done
This commit is contained in:
parent
87e2093be5
commit
3eb82c2fde
27
TcpSocket.js
27
TcpSocket.js
|
@ -21,6 +21,7 @@ var {
|
||||||
} = require('react-native');
|
} = require('react-native');
|
||||||
var Sockets = NativeModules.TcpSockets;
|
var Sockets = NativeModules.TcpSockets;
|
||||||
var base64 = require('base64-js');
|
var base64 = require('base64-js');
|
||||||
|
var Base64Str = require('./base64-str');
|
||||||
var noop = function () {};
|
var noop = function () {};
|
||||||
var instances = 0;
|
var instances = 0;
|
||||||
var STATE = {
|
var STATE = {
|
||||||
|
@ -124,6 +125,8 @@ function isLegalPort(port) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TcpSocket.prototype.setTimeout = function(msecs, callback) {
|
TcpSocket.prototype.setTimeout = function(msecs, callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
if (this._timeout) {
|
if (this._timeout) {
|
||||||
clearTimeout(this._timeout);
|
clearTimeout(this._timeout);
|
||||||
this._timeout = null;
|
this._timeout = null;
|
||||||
|
@ -137,7 +140,8 @@ TcpSocket.prototype.setTimeout = function(msecs, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this._timeout = setTimeout(msecs, function() {
|
this._timeout = setTimeout(msecs, function() {
|
||||||
self.emit('timeout');
|
self.emit('timeout');
|
||||||
this._timeout = null;
|
self._timeout = null;
|
||||||
|
self.destroy();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -191,11 +195,13 @@ TcpSocket.prototype.end = function(data, encoding) {
|
||||||
};
|
};
|
||||||
|
|
||||||
TcpSocket.prototype.destroy = function() {
|
TcpSocket.prototype.destroy = function() {
|
||||||
this._destroyed = true;
|
if (!this._destroyed) {
|
||||||
this._debug('destroying');
|
this._destroyed = true;
|
||||||
this._subscription.remove();
|
this._debug('destroying');
|
||||||
|
this._subscription.remove();
|
||||||
|
|
||||||
Sockets.destroy(this._id);
|
Sockets.destroy(this._id, this._debug.bind(this, 'closed'));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TcpSocket.prototype._onEvent = function(info) {
|
TcpSocket.prototype._onEvent = function(info) {
|
||||||
|
@ -239,8 +245,8 @@ TcpSocket.prototype.write = function(buffer, encoding, callback) {
|
||||||
callback = callback || noop;
|
callback = callback || noop;
|
||||||
var str;
|
var str;
|
||||||
if (typeof buffer === 'string') {
|
if (typeof buffer === 'string') {
|
||||||
console.warn('socket.WRITE(): interpreting as UTF8');
|
console.warn('socket.WRITE(): encoding as base64');
|
||||||
str = buffer;
|
str = Base64Str.encode(buffer);
|
||||||
} else if (typeof Buffer !== 'undefined' && global.Buffer.isBuffer(buffer)) {
|
} else if (typeof Buffer !== 'undefined' && global.Buffer.isBuffer(buffer)) {
|
||||||
encoded = true;
|
encoded = true;
|
||||||
str = buffer.toString('base64');
|
str = buffer.toString('base64');
|
||||||
|
@ -252,9 +258,14 @@ TcpSocket.prototype.write = function(buffer, encoding, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Sockets.write(this._id, str, encoded, function(err) {
|
Sockets.write(this._id, str, encoded, function(err) {
|
||||||
|
if (self._timeout) {
|
||||||
|
clearTimeout(self._timeout);
|
||||||
|
self._timeout = null;
|
||||||
|
}
|
||||||
|
|
||||||
err = normalizeError(err);
|
err = normalizeError(err);
|
||||||
if (err) {
|
if (err) {
|
||||||
self._debug('send failed', err);
|
self._debug('write failed', err);
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/**
|
||||||
|
* Source: https://gist.github.com/ncerminara/11257943
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var Base64Str = {
|
||||||
|
_keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
|
||||||
|
encode: function(e: string) {
|
||||||
|
var t = '';
|
||||||
|
var n, r, i, s, o, u, a;
|
||||||
|
var f = 0;
|
||||||
|
e = Base64Str._utf8_encode(e);
|
||||||
|
while (f < e.length) {
|
||||||
|
n = e.charCodeAt(f++);
|
||||||
|
r = e.charCodeAt(f++);
|
||||||
|
i = e.charCodeAt(f++);
|
||||||
|
s = n >> 2;
|
||||||
|
o = (n & 3) << 4 | r >> 4;
|
||||||
|
u = (r & 15) << 2 | i >> 6;
|
||||||
|
a = i & 63;
|
||||||
|
if (isNaN(r)) {
|
||||||
|
u = a = 64;
|
||||||
|
} else if (isNaN(i)) {
|
||||||
|
a = 64;
|
||||||
|
}
|
||||||
|
t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr
|
||||||
|
.charAt(u) + this._keyStr.charAt(a);
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
decode: function(e: string) {
|
||||||
|
var t = '';
|
||||||
|
var n, r, i;
|
||||||
|
var s, o, u, a;
|
||||||
|
var f = 0;
|
||||||
|
e = e.replace(/[^A-Za-z0-9\+\/\=]/g, '');
|
||||||
|
while (f < e.length) {
|
||||||
|
s = this._keyStr.indexOf(e.charAt(f++));
|
||||||
|
o = this._keyStr.indexOf(e.charAt(f++));
|
||||||
|
u = this._keyStr.indexOf(e.charAt(f++));
|
||||||
|
a = this._keyStr.indexOf(e.charAt(f++));
|
||||||
|
n = s << 2 | o >> 4;
|
||||||
|
r = (o & 15) << 4 | u >> 2;
|
||||||
|
i = (u & 3) << 6 | a;
|
||||||
|
t = t + String.fromCharCode(n);
|
||||||
|
if (u !== 64) {
|
||||||
|
t = t + String.fromCharCode(r);
|
||||||
|
}
|
||||||
|
if (a !== 64) {
|
||||||
|
t = t + String.fromCharCode(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t = Base64Str._utf8_decode(t);
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
_utf8_encode: function(e) {
|
||||||
|
e = e.replace(/\r\n/g, '\n');
|
||||||
|
var t = '';
|
||||||
|
for (var n = 0; n < e.length; n++) {
|
||||||
|
var r = e.charCodeAt(n);
|
||||||
|
if (r < 128) {
|
||||||
|
t += String.fromCharCode(r);
|
||||||
|
} else if (r > 127 && r < 2048) {
|
||||||
|
t += String.fromCharCode(r >> 6 | 192);
|
||||||
|
t += String.fromCharCode(r & 63 | 128);
|
||||||
|
} else {
|
||||||
|
t += String.fromCharCode(r >> 12 | 224);
|
||||||
|
t += String.fromCharCode(r >> 6 & 63 | 128);
|
||||||
|
t += String.fromCharCode(r & 63 | 128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
_utf8_decode: function(e) {
|
||||||
|
var t = '';
|
||||||
|
var n = 0;
|
||||||
|
var r = 0, /*c1 = 0, */c2 = 0;
|
||||||
|
while (n < e.length) {
|
||||||
|
r = e.charCodeAt(n);
|
||||||
|
if (r < 128) {
|
||||||
|
t += String.fromCharCode(r);
|
||||||
|
n++;
|
||||||
|
} else if (r > 191 && r < 224) {
|
||||||
|
c2 = e.charCodeAt(n + 1);
|
||||||
|
t += String.fromCharCode((r & 31) << 6 | c2 & 63);
|
||||||
|
n += 2;
|
||||||
|
} else {
|
||||||
|
c2 = e.charCodeAt(n + 1);
|
||||||
|
var c3 = e.charCodeAt(n + 2);
|
||||||
|
t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
|
||||||
|
n += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Base64Str;
|
||||||
|
}());
|
|
@ -38,9 +38,7 @@ typedef enum RCTTCPError RCTTCPError;
|
||||||
|
|
||||||
@interface TcpSocketClient : NSObject
|
@interface TcpSocketClient : NSObject
|
||||||
|
|
||||||
@property (nonatomic, retain) NSString * id;
|
@property (nonatomic, retain) NSNumber * id;
|
||||||
@property (nonatomic, retain) NSString * host;
|
|
||||||
@property (nonatomic) u_int16_t port;
|
|
||||||
|
|
||||||
///---------------------------------------------------------------------------------------
|
///---------------------------------------------------------------------------------------
|
||||||
/// @name Class Methods
|
/// @name Class Methods
|
||||||
|
@ -53,7 +51,7 @@ typedef enum RCTTCPError RCTTCPError;
|
||||||
* @return New RCTTCPClient
|
* @return New RCTTCPClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
+ (id)socketClientWithConfig:(id<SocketClientDelegate>) delegate;
|
+ (id)socketClientWithId:(NSNumber *)clientID andConfig:(id<SocketClientDelegate>) delegate;
|
||||||
|
|
||||||
///---------------------------------------------------------------------------------------
|
///---------------------------------------------------------------------------------------
|
||||||
/// @name Instance Methods
|
/// @name Instance Methods
|
||||||
|
|
|
@ -23,21 +23,22 @@ NSString *const RCTTCPErrorDomain = @"RCTTCPErrorDomain";
|
||||||
long _sendTag;
|
long _sendTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithConfig:(id<SocketClientDelegate>) aDelegate;
|
- (id)initWithClientId:(NSNumber *)clientID andConfig:(id<SocketClientDelegate>) aDelegate;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation TcpSocketClient
|
@implementation TcpSocketClient
|
||||||
|
|
||||||
+ (id)socketClientWithConfig:(id<SocketClientDelegate>)delegate
|
+ (id)socketClientWithId:(nonnull NSNumber *)clientID andConfig:(id<SocketClientDelegate>)delegate
|
||||||
{
|
{
|
||||||
return [[[self class] alloc] initWithConfig:delegate];
|
return [[[self class] alloc] initWithClientId:clientID andConfig:delegate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithConfig:(id<SocketClientDelegate>) aDelegate
|
- (id)initWithClientId:(NSNumber *)clientID andConfig:(id<SocketClientDelegate>) aDelegate
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
|
_id = clientID;
|
||||||
_clientDelegate = aDelegate;
|
_clientDelegate = aDelegate;
|
||||||
_pendingSends = [NSMutableDictionary dictionary];
|
_pendingSends = [NSMutableDictionary dictionary];
|
||||||
}
|
}
|
||||||
|
@ -104,7 +105,7 @@ NSString *const RCTTCPErrorDomain = @"RCTTCPErrorDomain";
|
||||||
|
|
||||||
- (void)end
|
- (void)end
|
||||||
{
|
{
|
||||||
[_tcpSocket disconnectAfterReadingAndWriting];
|
[_tcpSocket disconnectAfterWriting];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)destroy
|
- (void)destroy
|
||||||
|
@ -121,6 +122,9 @@ NSString *const RCTTCPErrorDomain = @"RCTTCPErrorDomain";
|
||||||
|
|
||||||
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
|
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
|
||||||
{
|
{
|
||||||
|
if (!_clientDelegate) return;
|
||||||
|
[_clientDelegate onConnect:self];
|
||||||
|
|
||||||
[sock readDataWithTimeout:-1 tag:-1];
|
[sock readDataWithTimeout:-1 tag:-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ RCT_EXPORT_METHOD(createSocket:(nonnull NSNumber*)cId)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
client = [TcpSocketClient socketClientWithConfig:self];
|
client = [TcpSocketClient socketClientWithId:cId andConfig:self];
|
||||||
[_clients setObject:client forKey:cId];
|
[_clients setObject:client forKey:cId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,21 +75,15 @@ RCT_EXPORT_METHOD(connect:(nonnull NSNumber*)cId
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(write:(nonnull NSNumber*)cId
|
RCT_EXPORT_METHOD(write:(nonnull NSNumber*)cId
|
||||||
string:(NSString *)string
|
string:(NSString *)base64String
|
||||||
encoded:(BOOL)encoded
|
encoded:(BOOL)encoded
|
||||||
callback:(RCTResponseSenderBlock)callback) {
|
callback:(RCTResponseSenderBlock)callback) {
|
||||||
TcpSocketClient* client = [TcpSockets findClient:cId callback:callback];
|
TcpSocketClient* client = [TcpSockets findClient:cId callback:callback];
|
||||||
if (!client) return;
|
if (!client) return;
|
||||||
|
|
||||||
NSData *data;
|
// iOS7+
|
||||||
if (encoded) {
|
// TODO: use https://github.com/nicklockwood/Base64 for compatibility with earlier iOS versions
|
||||||
// iOS7+
|
NSData *data = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
|
||||||
// TODO: use https://github.com/nicklockwood/Base64 for compatibility with earlier iOS versions
|
|
||||||
data = [[NSData alloc] initWithBase64EncodedString:string options:0];
|
|
||||||
} else {
|
|
||||||
data = [string dataUsingEncoding:[NSString defaultCStringEncoding]];
|
|
||||||
}
|
|
||||||
|
|
||||||
[client writeData:data callback:callback];
|
[client writeData:data callback:callback];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,15 +92,14 @@ RCT_EXPORT_METHOD(end:(nonnull NSNumber*)cId
|
||||||
[TcpSockets endClient:cId callback:callback];
|
[TcpSockets endClient:cId callback:callback];
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(destroy:(nonnull NSNumber*)cId) {
|
RCT_EXPORT_METHOD(destroy:(nonnull NSNumber*)cId
|
||||||
[TcpSockets destroyClient:cId];
|
callback:(RCTResponseSenderBlock)callback) {
|
||||||
|
[TcpSockets destroyClient:cId callback:callback];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) onConnect:(TcpSocketClient*) client
|
- (void) onConnect:(TcpSocketClient*) client
|
||||||
{
|
{
|
||||||
NSMutableDictionary<NSNumber *,TcpSocketClient *> *_clients = [TcpSockets clients];
|
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-event", client.id]
|
||||||
NSNumber *clientID = [[_clients allKeysForObject:client] objectAtIndex:0];
|
|
||||||
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-event", clientID]
|
|
||||||
body:@{ @"event": @"connect" }];
|
body:@{ @"event": @"connect" }];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,21 +114,20 @@ RCT_EXPORT_METHOD(destroy:(nonnull NSNumber*)cId) {
|
||||||
|
|
||||||
- (void) onClose:(TcpSocketClient*) client withError:(NSError *)err
|
- (void) onClose:(TcpSocketClient*) client withError:(NSError *)err
|
||||||
{
|
{
|
||||||
[self onError:client withError:err];
|
if (err) {
|
||||||
|
[self onError:client withError:err];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-event", client.id]
|
||||||
|
body:@{ @"event": @"close", @"data": err == nil ? @NO : @YES }];
|
||||||
|
|
||||||
NSMutableDictionary<NSNumber *,TcpSocketClient *> *_clients = [TcpSockets clients];
|
NSMutableDictionary<NSNumber *,TcpSocketClient *> *_clients = [TcpSockets clients];
|
||||||
NSNumber *clientID = [[_clients allKeysForObject:client] objectAtIndex:0];
|
[_clients removeObjectForKey:client.id];
|
||||||
|
|
||||||
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-event", clientID]
|
|
||||||
body:@{ @"event": @"close", @"data": err == nil ? @NO : @YES }];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)onError:(TcpSocketClient*) client withError:(NSError *)err {
|
- (void)onError:(TcpSocketClient*) client withError:(NSError *)err {
|
||||||
NSMutableDictionary<NSNumber *,TcpSocketClient *> *_clients = [TcpSockets clients];
|
|
||||||
NSNumber *clientID = [[_clients allKeysForObject:client] objectAtIndex:0];
|
|
||||||
|
|
||||||
NSString* msg = [[err userInfo] valueForKey:@"NSLocalizedFailureReason"];
|
NSString* msg = [[err userInfo] valueForKey:@"NSLocalizedFailureReason"];
|
||||||
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-event", clientID]
|
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-event", client.id]
|
||||||
body:@{ @"event": @"error", @"data": @[msg] }];
|
body:@{ @"event": @"error", @"data": @[msg] }];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -147,8 +139,7 @@ RCT_EXPORT_METHOD(destroy:(nonnull NSNumber*)cId) {
|
||||||
if (!client) {
|
if (!client) {
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
RCTLogError(@"%@.missing callback parameter.", [self class]);
|
RCTLogError(@"%@.missing callback parameter.", [self class]);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
callback(@[[NSString stringWithFormat:@"no client found with id %@", cId]]);
|
callback(@[[NSString stringWithFormat:@"no client found with id %@", cId]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,17 +152,16 @@ RCT_EXPORT_METHOD(destroy:(nonnull NSNumber*)cId) {
|
||||||
+(void) endClient:(nonnull NSNumber*)cId
|
+(void) endClient:(nonnull NSNumber*)cId
|
||||||
callback:(RCTResponseSenderBlock)callback
|
callback:(RCTResponseSenderBlock)callback
|
||||||
{
|
{
|
||||||
NSMutableDictionary<NSNumber *,TcpSocketClient *> *_clients = [TcpSockets clients];
|
|
||||||
TcpSocketClient* client = [TcpSockets findClient:cId callback:callback];
|
TcpSocketClient* client = [TcpSockets findClient:cId callback:callback];
|
||||||
if (!client) return;
|
if (!client) return;
|
||||||
|
|
||||||
[client end];
|
[client end];
|
||||||
[_clients removeObjectForKey:cId];
|
|
||||||
|
|
||||||
if (callback) callback(@[]);
|
if (callback) callback(@[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
+(void) destroyClient:(nonnull NSNumber*)cId
|
+(void) destroyClient:(nonnull NSNumber*)cId
|
||||||
|
callback:(RCTResponseSenderBlock)callback
|
||||||
{
|
{
|
||||||
NSMutableDictionary<NSNumber *,TcpSocketClient *> *_clients = [TcpSockets clients];
|
NSMutableDictionary<NSNumber *,TcpSocketClient *> *_clients = [TcpSockets clients];
|
||||||
TcpSocketClient* client = [TcpSockets findClient:cId callback:nil];
|
TcpSocketClient* client = [TcpSockets findClient:cId callback:nil];
|
||||||
|
|
|
@ -105,7 +105,7 @@
|
||||||
58B511D31A9E6C8500147676 /* Project object */ = {
|
58B511D31A9E6C8500147676 /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 0610;
|
LastUpgradeCheck = 0720;
|
||||||
ORGANIZATIONNAME = "Tradle, Inc.";
|
ORGANIZATIONNAME = "Tradle, Inc.";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
58B511DA1A9E6C8500147676 = {
|
58B511DA1A9E6C8500147676 = {
|
||||||
|
@ -179,6 +179,7 @@
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "react-native-tcp",
|
"name": "react-native-tcp",
|
||||||
"version": "1.1.1",
|
"version": "0.0.1",
|
||||||
"description": "node's dgram API for react-native",
|
"description": "node's dgram API for react-native",
|
||||||
"main": "TcpSockets.js",
|
"main": "TcpSockets.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
Loading…
Reference in New Issue