Skip to content

Commit

Permalink
Updated Websocket to use new event system
Browse files Browse the repository at this point in the history
Reviewed By: javache

Differential Revision: D3292473

fbshipit-source-id: f9a9e0a1b5a12f7fa8b36ebdba88405370f91c54
  • Loading branch information
nicklockwood authored and Facebook Github Bot 6 committed May 12, 2016
1 parent cd691e2 commit 2525feb
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 54 deletions.
3 changes: 2 additions & 1 deletion Libraries/Components/Keyboard/Keyboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
'use strict';

const NativeEventEmitter = require('NativeEventEmitter');
const KeyboardObserver = require('NativeModules').KeyboardObserver;

module.exports = new NativeEventEmitter('KeyboardObserver');
module.exports = new NativeEventEmitter(KeyboardObserver);
5 changes: 3 additions & 2 deletions Libraries/Components/StatusBar/StatusBarIOS.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

const NativeEventEmitter = require('NativeEventEmitter');
const StatusBar = require('StatusBar');
const StatusBarManager = require('NativeModules').StatusBarManager;

import type {StatusBarStyle, StatusBarAnimation} from 'StatusBar';

Expand All @@ -38,6 +39,6 @@ class StatusBarIOS extends NativeEventEmitter {
);
StatusBar.setNetworkActivityIndicatorVisible(visible);
}
};
}

module.exports = new StatusBarIOS('StatusBarManager');
module.exports = new StatusBarIOS(StatusBarManager);
14 changes: 4 additions & 10 deletions Libraries/Device/NativeEventEmitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
*/
'use strict';

const NativeModules = require('NativeModules');
const Platform = require('Platform');
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
const invariant = require('fbjs/lib/invariant');
Expand All @@ -24,21 +23,17 @@ import type EmitterSubscription from 'EmitterSubscription';
*/
class NativeEventEmitter {

_listenerCount: number;
_nativeModule: Object;

constructor(nativeModuleName: string) {
constructor(nativeModule: Object) {
if (Platform.OS === 'ios') {
this._listenerCount = 0;
this._nativeModule = NativeModules[nativeModuleName];
invariant(this._nativeModule,
'Native module `' + nativeModuleName + '` not found.');
invariant(nativeModule, 'Native module cannot be null.');
this._nativeModule = nativeModule;
}
}

addListener(eventType: string, listener: any, context: ?Object): EmitterSubscription {
if (Platform.OS === 'ios') {
this._listenerCount++;
this._nativeModule.addListener(eventType);
}
return RCTDeviceEventEmitter.nativeAddListener(eventType, listener, context);
Expand All @@ -54,15 +49,14 @@ class NativeEventEmitter {
removeAllListeners(eventType: string) {
invariant(eventType, 'eventType argument is required.');
if (Platform.OS === 'ios') {
var count = RCTDeviceEventEmitter.listeners(eventType).length;
const count = RCTDeviceEventEmitter.listeners(eventType).length;
this._nativeModule.removeListeners(count);
}
RCTDeviceEventEmitter.removeAllListeners(eventType);
}

removeCurrentListener() {
if (Platform.OS === 'ios') {
this._listenerCount--;
this._nativeModule.removeListeners(1);
}
RCTDeviceEventEmitter.removeCurrentListener();
Expand Down
7 changes: 3 additions & 4 deletions Libraries/Device/RCTDeviceEventEmitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,22 @@

const EventEmitter = require('EventEmitter');
const BatchedBridge = require('BatchedBridge');
const NativeModules = require('NativeModules');

import type EmitterSubscription from 'EmitterSubscription';

/**
* Deprecated - subclass NativeEventEmitter to create granular event modules instead of
* routing all event observation through RCTDeviceEventEmitter.
* adding all event listeners directly to RCTDeviceEventEmitter.
*/
class RCTDeviceEventEmitter extends EventEmitter {

addListener(eventType: string, listener: any, context: ?Object): EmitterSubscription {
if (eventType.lastIndexOf('statusBar', 0) === 0) {
console.warn('statusBar events should be registered via the StatusBarIOS module');
console.warn('`%s` event should be registered via the StatusBarIOS module', eventType);
return require('StatusBarIOS').addListener(eventType, listener, context);
}
if (eventType.lastIndexOf('keyboard', 0) === 0) {
console.warn('keyboard events should be registered via the Keyboard module');
console.warn('`%s` event should be registered via the Keyboard module', eventType);
return require('Keyboard').addListener(eventType, listener, context);
}
return super.addListener(eventType, listener, context);
Expand Down
4 changes: 2 additions & 2 deletions Libraries/WebSocket/RCTWebSocketModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import "RCTBridgeModule.h"
#import "RCTEventEmitter.h"
#import "RCTSRWebSocket.h"

@interface RCTWebSocketModule : NSObject <RCTBridgeModule, RCTSRWebSocketDelegate>
@interface RCTWebSocketModule : RCTEventEmitter <RCTSRWebSocketDelegate>

@end
18 changes: 11 additions & 7 deletions Libraries/WebSocket/RCTWebSocketModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@

#import "RCTWebSocketModule.h"

#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#import "RCTConvert.h"
#import "RCTUtils.h"

Expand All @@ -35,7 +33,13 @@ @implementation RCTWebSocketModule

RCT_EXPORT_MODULE()

@synthesize bridge = _bridge;
- (NSArray *)supportedEvents
{
return @[@"websocketMessage",
@"websocketOpen",
@"websocketFailed",
@"websocketClosed"];
}

- (void)dealloc
{
Expand Down Expand Up @@ -84,7 +88,7 @@ - (void)dealloc
- (void)webSocket:(RCTSRWebSocket *)webSocket didReceiveMessage:(id)message
{
BOOL binary = [message isKindOfClass:[NSData class]];
[_bridge.eventDispatcher sendDeviceEventWithName:@"websocketMessage" body:@{
[self sendEventWithName:@"websocketMessage" body:@{
@"data": binary ? [message base64EncodedStringWithOptions:0] : message,
@"type": binary ? @"binary" : @"text",
@"id": webSocket.reactTag
Expand All @@ -93,14 +97,14 @@ - (void)webSocket:(RCTSRWebSocket *)webSocket didReceiveMessage:(id)message

- (void)webSocketDidOpen:(RCTSRWebSocket *)webSocket
{
[_bridge.eventDispatcher sendDeviceEventWithName:@"websocketOpen" body:@{
[self sendEventWithName:@"websocketOpen" body:@{
@"id": webSocket.reactTag
}];
}

- (void)webSocket:(RCTSRWebSocket *)webSocket didFailWithError:(NSError *)error
{
[_bridge.eventDispatcher sendDeviceEventWithName:@"websocketFailed" body:@{
[self sendEventWithName:@"websocketFailed" body:@{
@"message":error.localizedDescription,
@"id": webSocket.reactTag
}];
Expand All @@ -109,7 +113,7 @@ - (void)webSocket:(RCTSRWebSocket *)webSocket didFailWithError:(NSError *)error
- (void)webSocket:(RCTSRWebSocket *)webSocket didCloseWithCode:(NSInteger)code
reason:(NSString *)reason wasClean:(BOOL)wasClean
{
[_bridge.eventDispatcher sendDeviceEventWithName:@"websocketClosed" body:@{
[self sendEventWithName:@"websocketClosed" body:@{
@"code": @(code),
@"reason": RCTNullIfNil(reason),
@"clean": @(wasClean),
Expand Down
48 changes: 23 additions & 25 deletions Libraries/WebSocket/WebSocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
*/
'use strict';

const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
const RCTWebSocketModule = require('NativeModules').WebSocketModule;
const NativeEventEmitter = require('NativeEventEmitter');
const Platform = require('Platform');
const RCTWebSocketModule = require('NativeModules').WebSocketModule;
const WebSocketEvent = require('WebSocketEvent');

const EventTarget = require('event-target-shim');
Expand Down Expand Up @@ -67,6 +67,7 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) {
CLOSED: number = CLOSED;

_socketId: number;
_eventEmitter: NativeEventEmitter;
_subscriptions: Array<EventSubscription>;

onclose: ?Function;
Expand All @@ -91,6 +92,7 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) {
protocols = null;
}

this._eventEmitter = new NativeEventEmitter(RCTWebSocketModule);
this._socketId = nextWebSocketId++;
RCTWebSocketModule.connect(url, protocols, options, this._socketId);
this._registerEvents();
Expand Down Expand Up @@ -136,8 +138,8 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) {
_close(code?: number, reason?: string): void {
if (Platform.OS === 'android') {
// See https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
var statusCode = typeof code === 'number' ? code : CLOSE_NORMAL;
var closeReason = typeof reason === 'string' ? reason : '';
const statusCode = typeof code === 'number' ? code : CLOSE_NORMAL;
const closeReason = typeof reason === 'string' ? reason : '';
RCTWebSocketModule.close(statusCode, closeReason, this._socketId);
} else {
RCTWebSocketModule.close(this._socketId);
Expand All @@ -151,47 +153,43 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) {

_registerEvents(): void {
this._subscriptions = [
RCTDeviceEventEmitter.addListener('websocketMessage', ev => {
this._eventEmitter.addListener('websocketMessage', ev => {
if (ev.id !== this._socketId) {
return;
}
var event = new WebSocketEvent('message', {
this.dispatchEvent(new WebSocketEvent('message', {
data: (ev.type === 'binary') ? base64.toByteArray(ev.data).buffer : ev.data
});
this.dispatchEvent(event);
}));
}),
RCTDeviceEventEmitter.addListener('websocketOpen', ev => {
this._eventEmitter.addListener('websocketOpen', ev => {
if (ev.id !== this._socketId) {
return;
}
this.readyState = this.OPEN;
var event = new WebSocketEvent('open');
this.dispatchEvent(event);
this.dispatchEvent(new WebSocketEvent('open'));
}),
RCTDeviceEventEmitter.addListener('websocketClosed', ev => {
this._eventEmitter.addListener('websocketClosed', ev => {
if (ev.id !== this._socketId) {
return;
}
this.readyState = this.CLOSED;
var event = new WebSocketEvent('close');
event.code = ev.code;
event.reason = ev.reason;
this.dispatchEvent(event);
this.dispatchEvent(new WebSocketEvent('close', {
code: ev.code,
reason: ev.reason,
}));
this._unregisterEvents();
this.close();
}),
RCTDeviceEventEmitter.addListener('websocketFailed', ev => {
this._eventEmitter.addListener('websocketFailed', ev => {
if (ev.id !== this._socketId) {
return;
}
var event = new WebSocketEvent('error');
event.message = ev.message;
this.dispatchEvent(event);

event = new WebSocketEvent('close');
event.message = ev.message;
this.dispatchEvent(event);

this.dispatchEvent(new WebSocketEvent('error', {
message: ev.message,
}));
this.dispatchEvent(new WebSocketEvent('close', {
message: ev.message,
}));
this._unregisterEvents();
this.close();
})
Expand Down
11 changes: 8 additions & 3 deletions React/Modules/RCTEventEmitter.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,23 @@ + (NSString *)moduleName

- (NSArray<NSString *> *)supportedEvents
{
RCTAssert(NO, @"You must override the `supportedEvents` method of %@", [self class]);
return nil;
}

- (void)sendEventWithName:(NSString *)eventName body:(id)body
{
RCTAssert(self.bridge != nil, @"bridge is not set.");
RCTAssert(_bridge != nil, @"bridge is not set.");

if (RCT_DEBUG && ![[self supportedEvents] containsObject:eventName]) {
RCTLogError(@"`%@` is not a supported event type for %@", eventName, [self class]);
}
[self.bridge enqueueJSCall:@"RCTDeviceEventEmitter.emit"
args:body ? @[eventName, body] : @[eventName]];
if (_listenerCount > 0) {
[_bridge enqueueJSCall:@"RCTDeviceEventEmitter.emit"
args:body ? @[eventName, body] : @[eventName]];
} else {
RCTLogWarn(@"Sending `%@` with no listeners registered.", eventName);
}
}

- (void)startObserving
Expand Down

0 comments on commit 2525feb

Please sign in to comment.