Skip to content

Commit 98e9d68

Browse files
authored
[BUG thoov#72, thoov#209] Change server callback argument to socket (thoov#214)
Fixes: thoov#72 thoov#209
1 parent 732a075 commit 98e9d68

File tree

8 files changed

+211
-129
lines changed

8 files changed

+211
-129
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ import { Server } from 'mock-socket';
6060
describe('Chat Unit Test', () => {
6161
it('basic test', (done) => {
6262
const mockServer = new Server('ws://localhost:8080');
63-
mockServer.on('connection', server => {
64-
mockServer.send('test message 1');
65-
mockServer.send('test message 2');
63+
mockServer.on('connection', socket => {
64+
socket.send('test message 1');
65+
socket.send('test message 2');
6666
});
6767

6868
// Now when Chat tries to do new WebSocket() it
@@ -100,7 +100,7 @@ import { SocketIO, Server } from 'mock-socket';
100100
describe('Chat Unit Test', () => {
101101
it('basic test', (done) => {
102102
const mockServer = new Server('http://localhost:8080');
103-
mockServer.on('connection', server => {
103+
mockServer.on('connection', socket => {
104104
mockServer.emit('chat-message', 'test message 1');
105105
mockServer.emit('chat-message', 'test message 2');
106106
});

src/helpers/proxy-factory.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { CLOSE_CODES } from '../constants';
2+
import { closeWebSocketConnection } from '../algorithms/close';
3+
import normalizeSendData from './normalize-send';
4+
import { createMessageEvent } from '../event/factory';
5+
6+
export default function proxyFactory(target) {
7+
const handler = {
8+
get(obj, prop) {
9+
if (prop === 'close') {
10+
return function close(options = {}) {
11+
const code = options.code || CLOSE_CODES.CLOSE_NORMAL;
12+
const reason = options.reason || '';
13+
14+
closeWebSocketConnection(target, code, reason);
15+
};
16+
}
17+
18+
if (prop === 'send') {
19+
return function send(data) {
20+
data = normalizeSendData(data);
21+
22+
target.dispatchEvent(
23+
createMessageEvent({
24+
type: 'message',
25+
data,
26+
origin: this.url,
27+
target
28+
})
29+
);
30+
};
31+
}
32+
33+
if (prop === 'on') {
34+
return function onWrapper(type, cb) {
35+
target.addEventListener(`server::${type}`, cb);
36+
};
37+
}
38+
39+
return obj[prop];
40+
}
41+
};
42+
43+
const proxy = new Proxy(target, handler);
44+
return proxy;
45+
}

src/server.js

Lines changed: 50 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
import URL from 'url-parse';
22
import WebSocket from './websocket';
3+
import dedupe from './helpers/dedupe';
34
import EventTarget from './event/target';
4-
import networkBridge from './network-bridge';
55
import { CLOSE_CODES } from './constants';
6+
import networkBridge from './network-bridge';
67
import globalObject from './helpers/global-object';
7-
import dedupe from './helpers/dedupe';
88
import normalizeSendData from './helpers/normalize-send';
99
import { createEvent, createMessageEvent, createCloseEvent } from './event/factory';
1010

11-
/*
12-
* https://github.com/websockets/ws#server-example
13-
*/
1411
class Server extends EventTarget {
15-
/*
16-
* @param {string} url
17-
*/
1812
constructor(url, options = {}) {
1913
super();
2014
const urlRecord = new URL(url);
@@ -42,13 +36,12 @@ class Server extends EventTarget {
4236
}
4337

4438
this.options = options;
45-
4639
this.start();
4740
}
4841

4942
/*
50-
* Attaches the mock websocket object to the global object
51-
*/
43+
* Attaches the mock websocket object to the global object
44+
*/
5245
start() {
5346
const globalObj = globalObject();
5447

@@ -60,8 +53,8 @@ class Server extends EventTarget {
6053
}
6154

6255
/*
63-
* Removes the mock websocket object from the global object
64-
*/
56+
* Removes the mock websocket object from the global object
57+
*/
6558
stop(callback = () => {}) {
6659
const globalObj = globalObject();
6760

@@ -81,30 +74,51 @@ class Server extends EventTarget {
8174
}
8275

8376
/*
84-
* This is the main function for the mock server to subscribe to the on events.
85-
*
86-
* ie: mockServer.on('connection', function() { console.log('a mock client connected'); });
87-
*
88-
* @param {string} type - The event key to subscribe to. Valid keys are: connection, message, and close.
89-
* @param {function} callback - The callback which should be called when a certain event is fired.
90-
*/
77+
* This is the main function for the mock server to subscribe to the on events.
78+
*
79+
* ie: mockServer.on('connection', function() { console.log('a mock client connected'); });
80+
*
81+
* @param {string} type - The event key to subscribe to. Valid keys are: connection, message, and close.
82+
* @param {function} callback - The callback which should be called when a certain event is fired.
83+
*/
9184
on(type, callback) {
9285
this.addEventListener(type, callback);
9386
}
9487

9588
/*
96-
* This send function will notify all mock clients via their onmessage callbacks that the server
97-
* has a message for them.
98-
*
99-
* @param {*} data - Any javascript object which will be crafted into a MessageObject.
100-
*/
101-
send(data, options = {}) {
102-
this.emit('message', data, options);
89+
* Closes the connection and triggers the onclose method of all listening
90+
* websockets. After that it removes itself from the urlMap so another server
91+
* could add itself to the url.
92+
*
93+
* @param {object} options
94+
*/
95+
close(options = {}) {
96+
const { code, reason, wasClean } = options;
97+
const listeners = networkBridge.websocketsLookup(this.url);
98+
99+
// Remove server before notifications to prevent immediate reconnects from
100+
// socket onclose handlers
101+
networkBridge.removeServer(this.url);
102+
103+
listeners.forEach(socket => {
104+
socket.readyState = WebSocket.CLOSE;
105+
socket.dispatchEvent(
106+
createCloseEvent({
107+
type: 'close',
108+
target: socket,
109+
code: code || CLOSE_CODES.CLOSE_NORMAL,
110+
reason: reason || '',
111+
wasClean
112+
})
113+
);
114+
});
115+
116+
this.dispatchEvent(createCloseEvent({ type: 'close' }), this);
103117
}
104118

105119
/*
106-
* Sends a generic message event to all mock clients.
107-
*/
120+
* Sends a generic message event to all mock clients.
121+
*/
108122
emit(event, data, options = {}) {
109123
let { websockets } = options;
110124

@@ -144,48 +158,18 @@ class Server extends EventTarget {
144158
}
145159

146160
/*
147-
* Closes the connection and triggers the onclose method of all listening
148-
* websockets. After that it removes itself from the urlMap so another server
149-
* could add itself to the url.
150-
*
151-
* @param {object} options
152-
*/
153-
close(options = {}) {
154-
const { code, reason, wasClean } = options;
155-
const listeners = networkBridge.websocketsLookup(this.url);
156-
157-
// Remove server before notifications to prevent immediate reconnects from
158-
// socket onclose handlers
159-
networkBridge.removeServer(this.url);
160-
161-
listeners.forEach(socket => {
162-
socket.readyState = WebSocket.CLOSE;
163-
socket.dispatchEvent(
164-
createCloseEvent({
165-
type: 'close',
166-
target: socket,
167-
code: code || CLOSE_CODES.CLOSE_NORMAL,
168-
reason: reason || '',
169-
wasClean
170-
})
171-
);
172-
});
173-
174-
this.dispatchEvent(createCloseEvent({ type: 'close' }), this);
175-
}
176-
177-
/*
178-
* Returns an array of websockets which are listening to this server
179-
*/
161+
* Returns an array of websockets which are listening to this server
162+
* TOOD: this should return a set and not be a method
163+
*/
180164
clients() {
181165
return networkBridge.websocketsLookup(this.url);
182166
}
183167

184168
/*
185-
* Prepares a method to submit an event to members of the room
186-
*
187-
* e.g. server.to('my-room').emit('hi!');
188-
*/
169+
* Prepares a method to submit an event to members of the room
170+
*
171+
* e.g. server.to('my-room').emit('hi!');
172+
*/
189173
to(room, broadcaster, broadcastList = []) {
190174
const self = this;
191175
const websockets = dedupe(broadcastList.concat(networkBridge.websocketsLookup(this.url, room, broadcaster)));

src/websocket.js

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
import lengthInUtf8Bytes from './helpers/byte-length';
2-
import urlVerification from './helpers/url-verification';
3-
import protocolVerification from './helpers/protocol-verification';
41
import delay from './helpers/delay';
5-
import normalizeSendData from './helpers/normalize-send';
2+
import logger from './helpers/logger';
63
import EventTarget from './event/target';
74
import networkBridge from './network-bridge';
5+
import proxyFactory from './helpers/proxy-factory';
6+
import lengthInUtf8Bytes from './helpers/byte-length';
87
import { CLOSE_CODES, ERROR_PREFIX } from './constants';
9-
import logger from './helpers/logger';
8+
import urlVerification from './helpers/url-verification';
9+
import normalizeSendData from './helpers/normalize-send';
10+
import protocolVerification from './helpers/protocol-verification';
1011
import { createEvent, createMessageEvent, createCloseEvent } from './event/factory';
1112
import { closeWebSocketConnection, failWebSocketConnection } from './algorithms/close';
1213

1314
/*
14-
* The main websocket class which is designed to mimick the native WebSocket class as close
15-
* as possible.
16-
*
17-
* https://html.spec.whatwg.org/multipage/web-sockets.html
18-
*/
15+
* The main websocket class which is designed to mimick the native WebSocket class as close
16+
* as possible.
17+
*
18+
* https://html.spec.whatwg.org/multipage/web-sockets.html
19+
*/
1920
class WebSocket extends EventTarget {
2021
constructor(url, protocols) {
2122
super();
@@ -30,19 +31,19 @@ class WebSocket extends EventTarget {
3031
const server = networkBridge.attachWebSocket(this, this.url);
3132

3233
/*
33-
* This delay is needed so that we dont trigger an event before the callbacks have been
34-
* setup. For example:
35-
*
36-
* var socket = new WebSocket('ws://localhost');
37-
*
38-
* // If we dont have the delay then the event would be triggered right here and this is
39-
* // before the onopen had a chance to register itself.
40-
*
41-
* socket.onopen = () => { // this would never be called };
42-
*
43-
* // and with the delay the event gets triggered here after all of the callbacks have been
44-
* // registered :-)
45-
*/
34+
* This delay is needed so that we dont trigger an event before the callbacks have been
35+
* setup. For example:
36+
*
37+
* var socket = new WebSocket('ws://localhost');
38+
*
39+
* If we dont have the delay then the event would be triggered right here and this is
40+
* before the onopen had a chance to register itself.
41+
*
42+
* socket.onopen = () => { // this would never be called };
43+
*
44+
* and with the delay the event gets triggered here after all of the callbacks have been
45+
* registered :-)
46+
*/
4647
delay(function delayCallback() {
4748
if (server) {
4849
if (
@@ -79,7 +80,7 @@ class WebSocket extends EventTarget {
7980
}
8081
this.readyState = WebSocket.OPEN;
8182
this.dispatchEvent(createEvent({ type: 'open', target: this }));
82-
server.dispatchEvent(createEvent({ type: 'connection' }), server, this);
83+
server.dispatchEvent(createEvent({ type: 'connection' }), proxyFactory(this));
8384
}
8485
} else {
8586
this.readyState = WebSocket.CLOSED;
@@ -135,7 +136,7 @@ class WebSocket extends EventTarget {
135136
// TODO: handle bufferedAmount
136137

137138
const messageEvent = createMessageEvent({
138-
type: 'message',
139+
type: 'server::message',
139140
origin: this.url,
140141
data: normalizeSendData(data)
141142
});
@@ -144,7 +145,7 @@ class WebSocket extends EventTarget {
144145

145146
if (server) {
146147
delay(() => {
147-
server.dispatchEvent(messageEvent, data);
148+
this.dispatchEvent(messageEvent, data);
148149
}, server);
149150
}
150151
}

tests/functional/websockets.test.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ test.cb('that verifyClient is only invoked if it is a function', t => {
6666
test.cb('that onmessage is called after the server sends a message', t => {
6767
const testServer = new Server('ws://localhost:8080');
6868

69-
testServer.on('connection', server => {
70-
server.send('Testing');
69+
testServer.on('connection', socket => {
70+
socket.send('Testing');
7171
});
7272

7373
const mockSocket = new WebSocket('ws://localhost:8080');
@@ -81,8 +81,8 @@ test.cb('that onmessage is called after the server sends a message', t => {
8181
test.cb('that onclose is called after the client closes the connection', t => {
8282
const testServer = new Server('ws://localhost:8080');
8383

84-
testServer.on('connection', server => {
85-
server.send('Testing');
84+
testServer.on('connection', socket => {
85+
socket.send('Testing');
8686
});
8787

8888
const mockSocket = new WebSocket('ws://localhost:8080');
@@ -100,9 +100,11 @@ test.cb('that onclose is called after the client closes the connection', t => {
100100
test.cb('that the server gets called when the client sends a message', t => {
101101
const testServer = new Server('ws://localhost:8080');
102102

103-
testServer.on('message', data => {
104-
t.is(data, 'Testing', 'on message fires as expected');
105-
t.end();
103+
testServer.on('connection', socket => {
104+
socket.on('message', data => {
105+
t.is(data, 'Testing', 'on message fires as expected');
106+
t.end();
107+
});
106108
});
107109

108110
const mockSocket = new WebSocket('ws://localhost:8080');

tests/issues/143.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ test.cb('reassigning websocket onmessage listener should replace previous listen
4040
secondListenerCalled = true;
4141
};
4242

43-
mockServer.on('connection', () => {
44-
mockServer.send('test message');
43+
mockServer.on('connection', socket => {
44+
socket.send('test message');
4545
t.false(firstListenerCalled, 'The first listener should not be called');
4646
t.true(secondListenerCalled, 'Only the second listener should be called');
4747
mockServer.close();

tests/issues/157.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ test.cb('websocket onmessage fired before onopen', t => {
99

1010
let onOpenCalled = false;
1111

12-
mockServer.on('connection', () => {
13-
mockServer.send('test message');
12+
mockServer.on('connection', socket => {
13+
socket.send('test message');
1414
});
1515

1616
mockSocket.onopen = () => {

0 commit comments

Comments
 (0)