-
Notifications
You must be signed in to change notification settings - Fork 155
/
Server.js
158 lines (135 loc) · 3.7 KB
/
Server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/**
* @file Represents a websocket server
*/
'use strict'
function nop() {}
var util = require('util'),
net = require('net'),
tls = require('tls'),
events = require('events'),
Connection
/**
* @callback SelectProtocolCallback
* @param {Connection} connection
* @param {Array<string>} protocols
* @returns {?string}
*/
/**
* Creates a new ws server and starts listening for new connections
* @class
* @param {boolean} secure indicates if it should use tls
* @param {Object} [options] will be passed to net.createServer() or tls.createServer()
* @param {Array<string>} [options.validProtocols]
* @param {SelectProtocolCallback} [options.selectProtocol]
* @param {Function} [callback] will be added as "connection" listener
* @inherits EventEmitter
* @event listening
* @event close
* @event error an error object is passed
* @event connection a Connection object is passed
*/
function Server(secure, options, callback) {
var that = this
if (typeof options === 'function') {
callback = options
options = undefined
}
var onConnection = function (socket) {
var conn = new Connection(socket, that, function () {
that.connections.push(conn)
conn.removeListener('error', nop)
that.emit('connection', conn)
})
conn.on('close', function () {
var pos = that.connections.indexOf(conn)
if (pos !== -1) {
that.connections.splice(pos, 1)
}
})
// Ignore errors before the connection is established
conn.on('error', nop)
}
if (secure) {
this.socket = tls.createServer(options, onConnection)
} else {
this.socket = net.createServer(options, onConnection)
}
this.socket.on('close', function () {
that.emit('close')
})
this.socket.on('error', function (err) {
that.emit('error', err)
})
this.connections = []
// super constructor
events.EventEmitter.call(this)
if (callback) {
this.on('connection', callback)
}
// Add protocol agreement handling
/**
* @member {?SelectProtocolCallback}
* @private
*/
this._selectProtocol = null
if (options && options.selectProtocol) {
// User-provided logic
this._selectProtocol = options.selectProtocol
} else if (options && options.validProtocols) {
// Default logic
this._selectProtocol = this._buildSelectProtocol(options.validProtocols)
}
}
util.inherits(Server, events.EventEmitter)
module.exports = Server
Connection = require('./Connection')
/**
* Start listening for connections
* @param {number} port
* @param {string} [host]
* @param {Function} [callback] will be added as "connection" listener
*/
Server.prototype.listen = function (port, host, callback) {
var that = this
if (typeof host === 'function') {
callback = host
host = undefined
}
if (callback) {
this.on('listening', callback)
}
this.socket.listen(port, host, function () {
that.emit('listening')
})
return this
}
/**
* Stops the server from accepting new connections and keeps existing connections.
* This function is asynchronous, the server is finally closed when all connections are ended and the server emits a 'close' event.
* The optional callback will be called once the 'close' event occurs.
* @param {function()} [callback]
*/
Server.prototype.close = function (callback) {
if (callback) {
this.once('close', callback)
}
this.socket.close()
}
/**
* Create a resolver to pick the client's most preferred protocol the server recognises
* @param {Array<string>} validProtocols
* @returns {SelectProtocolCallback}
* @private
*/
Server.prototype._buildSelectProtocol = function (validProtocols) {
return function (conn, protocols) {
var i
for (i = 0; i < protocols.length; i++) {
if (validProtocols.indexOf(protocols[i]) !== -1) {
// A valid protocol was found
return protocols[i]
}
}
// No agreement
}
}