1 | var net
|
2 | try {
|
3 | net = require('net')
|
4 | } catch (_) {}
|
5 |
|
6 | function isString(s) {
|
7 | return 'string' == typeof s
|
8 | }
|
9 |
|
10 | var toPull = require('stream-to-pull-stream')
|
11 | var scopes = require('multiserver-scopes')
|
12 | var debug = require('debug')('multiserver:net')
|
13 |
|
14 | function toDuplex (str) {
|
15 | var stream = toPull.duplex(str)
|
16 | stream.address = 'net:'+str.remoteAddress+':'+str.remotePort
|
17 | return stream
|
18 | }
|
19 |
|
20 | module.exports = function (opts) {
|
21 |
|
22 |
|
23 | var port = opts.port || Math.floor(49152 + (65535 - 49152 + 1) * Math.random())
|
24 |
|
25 | var host = opts.host || (isString(opts.scope) && scopes.host(opts.scope))
|
26 | var scope = opts.scope || 'device'
|
27 |
|
28 | opts.allowHalfOpen = opts.allowHalfOpen !== false
|
29 |
|
30 | function isScoped (s) {
|
31 | return s === scope || Array.isArray(scope) && ~scope.indexOf(s)
|
32 | }
|
33 |
|
34 | return {
|
35 | name: 'net',
|
36 | scope: function() {
|
37 | return scope
|
38 | },
|
39 | server: function (onConnection, startedCb) {
|
40 | debug('Listening on %s:%d', host, port)
|
41 | var server = net.createServer(opts, function (stream) {
|
42 | onConnection(toDuplex(stream))
|
43 | }).listen(port, host, startedCb)
|
44 | return function (cb) {
|
45 | debug('Closing server on %s:%d', host, port)
|
46 | server.close(function(err) {
|
47 | if (err) console.error(err)
|
48 | else debug('No longer listening on %s:%d', host, port)
|
49 | if (cb) cb(err)
|
50 | })
|
51 | }
|
52 | },
|
53 | client: function (opts, cb) {
|
54 | var addr = 'net:'+opts.host+':'+opts.port
|
55 | var started = false
|
56 | var stream = net.connect(opts)
|
57 | .on('connect', function () {
|
58 | if(started) return
|
59 | started = true
|
60 |
|
61 | cb(null, toDuplex(stream))
|
62 | })
|
63 | .on('error', function (err) {
|
64 | if(started) return
|
65 | started = true
|
66 | cb(err)
|
67 | })
|
68 |
|
69 | return function () {
|
70 | started = true
|
71 | stream.destroy()
|
72 | cb(new Error('multiserver.net: aborted'))
|
73 | }
|
74 | },
|
75 |
|
76 | parse: function (s) {
|
77 | if(!net) return null
|
78 | var ary = s.split(':')
|
79 | if(ary.length < 3) return null
|
80 | if('net' !== ary.shift()) return null
|
81 | var port = +ary.pop()
|
82 | if(isNaN(port)) return null
|
83 | return {
|
84 | name: 'net',
|
85 | host: ary.join(':') || 'localhost',
|
86 | port: port
|
87 | }
|
88 | },
|
89 | stringify: function (scope) {
|
90 | scope = scope || 'device'
|
91 | if(!isScoped(scope)) return
|
92 | var _host = (scope == 'public' && opts.external) || scopes.host(scope)
|
93 | if(!_host) return null
|
94 | return ['net', _host, port].join(':')
|
95 | }
|
96 | }
|
97 | }
|
98 |
|