Merge pull request #35 from PeelTechnologies/RCTEventEmitter

switch to NativeEventEmitter for sending events
This commit is contained in:
Andy Prock 2017-01-13 12:44:09 -08:00 committed by GitHub
commit aec6937e19
7 changed files with 125 additions and 73 deletions

View File

@ -16,7 +16,7 @@ var stream = require('stream-browserify');
// var EventEmitter = require('events').EventEmitter; // var EventEmitter = require('events').EventEmitter;
var ipRegex = require('ip-regex'); var ipRegex = require('ip-regex');
var { var {
DeviceEventEmitter, NativeEventEmitter,
NativeModules NativeModules
} = require('react-native'); } = require('react-native');
var Sockets = NativeModules.TcpSockets; var Sockets = NativeModules.TcpSockets;
@ -47,6 +47,7 @@ function TcpSocket(options: ?{ id: ?number }) {
this._id = instances++; this._id = instances++;
} }
this._eventEmitter = new NativeEventEmitter(Sockets);
stream.Duplex.call(this, {}); stream.Duplex.call(this, {});
// ensure compatibility with node's EventEmitter // ensure compatibility with node's EventEmitter
@ -248,28 +249,41 @@ TcpSocket.prototype._registerEvents = function(): void {
} }
this._subs = [ this._subs = [
DeviceEventEmitter.addListener( this._eventEmitter.addListener('connect', ev => {
'tcp-' + this._id + '-connect', this._onConnect.bind(this) if (this._id !== ev.id) {
), return;
DeviceEventEmitter.addListener( }
'tcp-' + this._id + '-connection', this._onConnection.bind(this) this._onConnect(ev.address);
), }),
DeviceEventEmitter.addListener( this._eventEmitter.addListener('connection', ev => {
'tcp-' + this._id + '-data', this._onData.bind(this) if (this._id !== ev.id) {
), return;
DeviceEventEmitter.addListener( }
'tcp-' + this._id + '-close', this._onClose.bind(this) this._onConnection(ev.info);
), }),
DeviceEventEmitter.addListener( this._eventEmitter.addListener('data', ev => {
'tcp-' + this._id + '-error', this._onError.bind(this) if (this._id !== ev.id) {
) return;
}
this._onData(ev.data);
}),
this._eventEmitter.addListener('close', ev => {
if (this._id !== ev.id) {
return;
}
this._onClose(ev.hadError);
}),
this._eventEmitter.addListener('error', ev => {
if (this._id !== ev.id) {
return;
}
this._onError(ev.error);
})
]; ];
}; };
TcpSocket.prototype._unregisterEvents = function(): void { TcpSocket.prototype._unregisterEvents = function(): void {
this._subs.forEach(function(listener) { this._subs.forEach(e => e.remove());
listener.remove();
});
this._subs = []; this._subs = [];
}; };

View File

@ -35,8 +35,11 @@ public final class TcpSockets extends ReactContextBaseJavaModule implements TcpS
private boolean mShuttingDown = false; private boolean mShuttingDown = false;
private TcpSocketManager socketManager; private TcpSocketManager socketManager;
private ReactContext mReactContext;
public TcpSockets(ReactApplicationContext reactContext) { public TcpSockets(ReactApplicationContext reactContext) {
super(reactContext); super(reactContext);
mReactContext = reactContext;
try { try {
socketManager = new TcpSocketManager(this); socketManager = new TcpSocketManager(this);
@ -73,6 +76,12 @@ public final class TcpSockets extends ReactContextBaseJavaModule implements TcpS
} }
} }
private void sendEvent(String eventName, WritableMap params) {
mReactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
@ReactMethod @ReactMethod
public void listen(final Integer cId, final String host, final Integer port) { public void listen(final Integer cId, final String host, final Integer port) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) { new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@ -146,19 +155,20 @@ public final class TcpSockets extends ReactContextBaseJavaModule implements TcpS
return; return;
} }
WritableMap eventParams = Arguments.createMap(); WritableMap eventParams = Arguments.createMap();
eventParams.putInt("id", clientId); eventParams.putInt("id", serverId);
WritableMap infoParams = Arguments.createMap();
infoParams.putInt("id", clientId);
WritableMap addressParams = Arguments.createMap(); WritableMap addressParams = Arguments.createMap();
addressParams.putString("address", socketAddress.getHostName()); addressParams.putString("address", socketAddress.getHostName());
addressParams.putInt("port", socketAddress.getPort()); addressParams.putInt("port", socketAddress.getPort());
addressParams.putString("family", socketAddress.getAddress() instanceof Inet6Address ? "IPv6" : "IPv4"); addressParams.putString("family", socketAddress.getAddress() instanceof Inet6Address ? "IPv6" : "IPv4");
eventParams.putMap("address", addressParams); infoParams.putMap("address", addressParams);
eventParams.putMap("info", infoParams);
ReactContext reactContext = TcpSockets.this.getReactApplicationContext(); sendEvent("connection", eventParams);
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("tcp-" + serverId + "-connection", eventParams);
} }
@Override @Override
@ -167,14 +177,16 @@ public final class TcpSockets extends ReactContextBaseJavaModule implements TcpS
return; return;
} }
WritableMap eventParams = Arguments.createMap(); WritableMap eventParams = Arguments.createMap();
eventParams.putString("address", address.getHostName()); eventParams.putInt("id", id);
eventParams.putInt("port", address.getPort());
eventParams.putString("family", address.getAddress() instanceof Inet6Address ? "IPv6" : "IPv4");
ReactContext reactContext = TcpSockets.this.getReactApplicationContext(); WritableMap addressParams = Arguments.createMap();
reactContext addressParams.putString("address", address.getHostName());
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) addressParams.putInt("port", address.getPort());
.emit("tcp-" + id + "-connect", eventParams); addressParams.putString("family", address.getAddress() instanceof Inet6Address ? "IPv6" : "IPv4");
eventParams.putMap("address", addressParams);
sendEvent("connect", eventParams);
} }
@Override @Override
@ -182,10 +194,11 @@ public final class TcpSockets extends ReactContextBaseJavaModule implements TcpS
if (mShuttingDown) { if (mShuttingDown) {
return; return;
} }
ReactContext reactContext = TcpSockets.this.getReactApplicationContext(); WritableMap eventParams = Arguments.createMap();
reactContext eventParams.putInt("id", id);
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) eventParams.putString("data", Base64.encodeToString(data, Base64.NO_WRAP));
.emit("tcp-" + id + "-data", Base64.encodeToString(data, Base64.NO_WRAP));
sendEvent("data", eventParams);
} }
@Override @Override
@ -197,10 +210,11 @@ public final class TcpSockets extends ReactContextBaseJavaModule implements TcpS
onError(id, error); onError(id, error);
} }
ReactContext reactContext = TcpSockets.this.getReactApplicationContext(); WritableMap eventParams = Arguments.createMap();
reactContext eventParams.putInt("id", id);
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) eventParams.putBoolean("hadError", error != null);
.emit("tcp-" + id + "-close", error != null);
sendEvent("close", eventParams);
} }
@Override @Override
@ -208,9 +222,11 @@ public final class TcpSockets extends ReactContextBaseJavaModule implements TcpS
if (mShuttingDown) { if (mShuttingDown) {
return; return;
} }
ReactContext reactContext = TcpSockets.this.getReactApplicationContext();
reactContext WritableMap eventParams = Arguments.createMap();
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) eventParams.putInt("id", id);
.emit("tcp-" + id + "-error", error); eventParams.putString("error", error);
sendEvent("error", eventParams);
} }
} }

View File

@ -48,6 +48,10 @@ class RctSockets extends Component {
socket.on('error', (error) => { socket.on('error', (error) => {
this.updateChatter('error ' + error); this.updateChatter('error ' + error);
}); });
socket.on('close', (error) => {
this.updateChatter('server client closed ' + (error ? error : ''));
});
}).listen(serverPort, () => { }).listen(serverPort, () => {
this.updateChatter('opened server on ' + JSON.stringify(server.address())); this.updateChatter('opened server on ' + JSON.stringify(server.address()));
}); });
@ -56,6 +60,10 @@ class RctSockets extends Component {
this.updateChatter('error ' + error); this.updateChatter('error ' + error);
}); });
server.on('close', () => {
this.updateChatter('server close');
});
let client = net.createConnection(serverPort, () => { let client = net.createConnection(serverPort, () => {
this.updateChatter('opened client on ' + JSON.stringify(client.address())); this.updateChatter('opened client on ' + JSON.stringify(client.address()));
client.write('Hello, server! Love, Client.'); client.write('Hello, server! Love, Client.');

View File

@ -4,6 +4,7 @@
*/ */
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "CocoaAsyncSocket/GCDAsyncSocket.h"
#import "RCTBridgeModule.h" #import "RCTBridgeModule.h"
extern NSString *const RCTTCPErrorDomain; extern NSString *const RCTTCPErrorDomain;
@ -35,7 +36,7 @@ typedef enum RCTTCPError RCTTCPError;
@end @end
@interface TcpSocketClient : NSObject @interface TcpSocketClient : NSObject<GCDAsyncSocketDelegate>
@property (nonatomic, retain) NSNumber * id; @property (nonatomic, retain) NSNumber * id;
@property (nonatomic, weak) id<SocketClientDelegate> clientDelegate; @property (nonatomic, weak) id<SocketClientDelegate> clientDelegate;

View File

@ -8,7 +8,6 @@
#import "TcpSocketClient.h" #import "TcpSocketClient.h"
#import "RCTBridgeModule.h" #import "RCTBridgeModule.h"
#import "RCTLog.h" #import "RCTLog.h"
#import "GCDAsyncSocket.h"
NSString *const RCTTCPErrorDomain = @"RCTTCPErrorDomain"; NSString *const RCTTCPErrorDomain = @"RCTTCPErrorDomain";
@ -203,7 +202,7 @@ NSString *const RCTTCPErrorDomain = @"RCTTCPErrorDomain";
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
if (!_clientDelegate) { if (!_clientDelegate) {
RCTLogError(@"didReadData with nil clientDelegate for %@", [sock userData]); RCTLogWarn(@"didReadData with nil clientDelegate for %@", [sock userData]);
return; return;
} }
@ -225,7 +224,7 @@ 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) { if (!_clientDelegate) {
RCTLogError(@"didConnectToHost with nil clientDelegate for %@", [sock userData]); RCTLogWarn(@"didConnectToHost with nil clientDelegate for %@", [sock userData]);
return; return;
} }
@ -244,7 +243,7 @@ NSString *const RCTTCPErrorDomain = @"RCTTCPErrorDomain";
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{ {
if (!_clientDelegate) { if (!_clientDelegate) {
RCTLogError(@"socketDidDisconnect with nil clientDelegate for %@", [sock userData]); RCTLogWarn(@"socketDidDisconnect with nil clientDelegate for %@", [sock userData]);
return; return;
} }

View File

@ -5,12 +5,11 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <Availability.h> #import <Availability.h>
#import "GCDAsyncSocket.h" #import "CocoaAsyncSocket/GCDAsyncSocket.h"
#import "TcpSocketClient.h"
#import "RCTBridgeModule.h" #import "RCTBridgeModule.h"
#import "RCTBridge.h" #import "TcpSocketClient.h"
#import "RCTEventDispatcher.h" #import "RCTEventEmitter.h"
@interface TcpSockets : NSObject<SocketClientDelegate, RCTBridgeModule> @interface TcpSockets : RCTEventEmitter<SocketClientDelegate>
@end @end

View File

@ -4,9 +4,8 @@
*/ */
#import "RCTAssert.h" #import "RCTAssert.h"
#import "RCTBridge.h"
#import "RCTConvert.h"
#import "RCTEventDispatcher.h" #import "RCTEventDispatcher.h"
#import "RCTConvert.h"
#import "RCTLog.h" #import "RCTLog.h"
#import "TcpSockets.h" #import "TcpSockets.h"
#import "TcpSocketClient.h" #import "TcpSocketClient.h"
@ -22,7 +21,22 @@
RCT_EXPORT_MODULE() RCT_EXPORT_MODULE()
@synthesize bridge = _bridge; - (NSArray<NSString *> *)supportedEvents
{
return @[@"connect",
@"connection",
@"data",
@"close",
@"error"];
}
- (void)startObserving {
// Does nothing
}
- (void)stopObserving {
// Does nothing
}
-(void)dealloc -(void)dealloc
{ {
@ -34,7 +48,7 @@ RCT_EXPORT_MODULE()
- (TcpSocketClient *)createSocket:(nonnull NSNumber*)cId - (TcpSocketClient *)createSocket:(nonnull NSNumber*)cId
{ {
if (!cId) { if (!cId) {
RCTLogError(@"%@.createSocket called with nil id parameter.", [self class]); RCTLogWarn(@"%@.createSocket called with nil id parameter.", [self class]);
return nil; return nil;
} }
@ -43,7 +57,7 @@ RCT_EXPORT_MODULE()
} }
if (_clients[cId]) { if (_clients[cId]) {
RCTLogError(@"%@.createSocket called twice with the same id.", [self class]); RCTLogWarn(@"%@.createSocket called twice with the same id.", [self class]);
return nil; return nil;
} }
@ -109,45 +123,45 @@ RCT_EXPORT_METHOD(listen:(nonnull NSNumber*)cId
- (void)onConnect:(TcpSocketClient*) client - (void)onConnect:(TcpSocketClient*) client
{ {
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-connect", client.id] [self sendEventWithName:@"connect"
body:[client getAddress]]; body:@{ @"id": client.id, @"address" : [client getAddress] }];
} }
-(void)onConnection:(TcpSocketClient *)client toClient:(NSNumber *)clientID { -(void)onConnection:(TcpSocketClient *)client toClient:(NSNumber *)clientID {
_clients[client.id] = client; _clients[client.id] = client;
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-connection", clientID] [self sendEventWithName:@"connection"
body:@{ @"id": client.id, @"address" : [client getAddress] }]; body:@{ @"id": clientID, @"info": @{ @"id": client.id, @"address" : [client getAddress] } }];
} }
- (void)onData:(NSNumber *)clientID data:(NSData *)data - (void)onData:(NSNumber *)clientID data:(NSData *)data
{ {
NSString *base64String = [data base64EncodedStringWithOptions:0]; NSString *base64String = [data base64EncodedStringWithOptions:0];
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-data", clientID] [self sendEventWithName:@"data"
body:base64String]; body:@{ @"id": clientID, @"data" : base64String }];
} }
- (void)onClose:(NSNumber*) clientID withError:(NSError *)err - (void)onClose:(NSNumber*) clientID withError:(NSError *)err
{ {
TcpSocketClient* client = [self findClient:clientID]; TcpSocketClient* client = [self findClient:clientID];
if (!client) { if (!client) {
RCTLogError(@"onClose: unrecognized client id %@", clientID); RCTLogWarn(@"onClose: unrecognized client id %@", clientID);
} }
if (err) { if (err) {
[self onError:client withError:err]; [self onError:client withError:err];
} }
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-close", client.id] [self sendEventWithName:@"close"
body:err == nil ? @NO : @YES]; body:@{ @"id": clientID, @"hadError": err == nil ? @NO : @YES }];
[_clients removeObjectForKey:client.id]; [_clients removeObjectForKey:clientID];
} }
- (void)onError:(TcpSocketClient*) client withError:(NSError *)err { - (void)onError:(TcpSocketClient*) client withError:(NSError *)err {
NSString *msg = err.localizedFailureReason ?: err.localizedDescription; NSString *msg = err.localizedFailureReason ?: err.localizedDescription;
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-error", client.id] [self sendEventWithName:@"error"
body:msg]; body:@{ @"id": client.id, @"error": msg }];
} }
@ -156,8 +170,9 @@ RCT_EXPORT_METHOD(listen:(nonnull NSNumber*)cId
TcpSocketClient *client = _clients[cId]; TcpSocketClient *client = _clients[cId];
if (!client) { if (!client) {
NSString *msg = [NSString stringWithFormat:@"no client found with id %@", cId]; NSString *msg = [NSString stringWithFormat:@"no client found with id %@", cId];
[self.bridge.eventDispatcher sendDeviceEventWithName:[NSString stringWithFormat:@"tcp-%@-error", cId] [self sendEventWithName:@"error"
body:msg]; body:@{ @"id": cId, @"error": msg }];
return nil; return nil;
} }