1 | var toDuplex = require('stream-to-pull-stream').duplex
|
2 | var net = require('net')
|
3 | var fs = require('fs')
|
4 | var path = require('path')
|
5 | var debug = require('debug')('multiserver:unix')
|
6 |
|
7 |
|
8 | var started = false
|
9 |
|
10 | module.exports = function (opts) {
|
11 | const socket = path.join(opts.path || '', 'socket')
|
12 | const addr = 'unix:' + socket
|
13 | let scope = opts.scope || 'device'
|
14 | opts = opts || {}
|
15 | return {
|
16 | name: 'unix',
|
17 | scope: function() { return scope },
|
18 | server: function (onConnection, cb) {
|
19 | if (started) return
|
20 |
|
21 | if (scope !== "device") {
|
22 | debug('Insecure scope for unix socket! Reverting to device scope')
|
23 | scope = 'device'
|
24 | }
|
25 |
|
26 | debug('listening on socket %s', addr)
|
27 |
|
28 | var server = net.createServer(opts, function (stream) {
|
29 | stream = toDuplex(stream)
|
30 | stream.address = addr
|
31 | onConnection(stream)
|
32 | }).listen(socket, cb)
|
33 |
|
34 | server.on('error', function (e) {
|
35 | if (e.code == 'EADDRINUSE') {
|
36 | var clientSocket = new net.Socket()
|
37 | clientSocket.on('error', function(e) {
|
38 | if (e.code == 'ECONNREFUSED') {
|
39 | fs.unlinkSync(socket)
|
40 | server.listen(socket)
|
41 | }
|
42 | })
|
43 |
|
44 | clientSocket.connect({ path: socket }, function() {
|
45 | debug('someone else is listening on socket!')
|
46 | })
|
47 | }
|
48 | })
|
49 |
|
50 | if (process.platform !== 'win32') {
|
51 | fs.chmodSync(socket, 0600)
|
52 | }
|
53 |
|
54 | started = true
|
55 |
|
56 | return function () {
|
57 | server.close()
|
58 | }
|
59 | },
|
60 | client: function (opts, cb) {
|
61 | debug('unix socket client')
|
62 | var started = false
|
63 | var stream = net.connect(opts.path)
|
64 | .on('connect', function () {
|
65 | if(started) return
|
66 | started = true
|
67 |
|
68 | var _stream = toDuplex(stream)
|
69 | _stream.address = addr
|
70 | cb(null, _stream)
|
71 | })
|
72 | .on('error', function (err) {
|
73 | debug('err? %o', err)
|
74 | if(started) return
|
75 | started = true
|
76 | cb(err)
|
77 | })
|
78 |
|
79 | return function () {
|
80 | started = true
|
81 | stream.destroy()
|
82 | cb(new Error('multiserver.unix: aborted'))
|
83 | }
|
84 | },
|
85 |
|
86 | parse: function (s) {
|
87 | var ary = s.split(':')
|
88 | if(ary.length < 2) return null
|
89 | if('unix' !== ary.shift()) return null
|
90 | return {
|
91 | name: '',
|
92 | path: ary.shift()
|
93 | }
|
94 | },
|
95 | stringify: function (_scope) {
|
96 | if(scope !== _scope) return null
|
97 | return ['unix', socket].join(':')
|
98 | }
|
99 | }
|
100 | }
|