1 | http = require 'http'
|
2 | path = require 'path'
|
3 | url = require 'url'
|
4 | fs = require 'fs'
|
5 | request = require 'request'
|
6 | events = require 'eventemitter2'
|
7 | socketio = require 'socket.io'
|
8 | debug = require('debug')('linda')
|
9 |
|
10 | TupleSpace = require path.join(__dirname, 'tuplespace')
|
11 | Tuple = require path.join(__dirname, 'tuple')
|
12 | Client = require path.join(__dirname, 'linda-client')
|
13 |
|
14 | module.exports.TupleSpace = TupleSpace
|
15 | module.exports.Tuple = Tuple
|
16 | module.exports.Client = Client
|
17 |
|
18 | class Linda extends events.EventEmitter2
|
19 | constructor: ->
|
20 | @spaces = {}
|
21 |
|
22 | fs.readFile path.join(__dirname, 'linda-client.js'),
|
23 | (err, data) =>
|
24 | throw new Error "client js load error" if err
|
25 | @client_js_code = data
|
26 |
|
27 | setInterval =>
|
28 | debug "TupleSpace\tcheck expire"
|
29 | for name, space of @spaces
|
30 | if space?
|
31 | space.check_expire()
|
32 | debug "TupleSpace\tcheck expire done"
|
33 | , 60*3*1000
|
34 |
|
35 | @tuplespace('__linda').watch {type: 'keepalive'}, (err, tuple) ->
|
36 | if err or !tuple.data.to?
|
37 | return
|
38 | if /^https?:\/\/.+/.test tuple.data.to
|
39 | request "#{tuple.data.to}?keepalive=#{Date.now()}"
|
40 |
|
41 | tuplespace: (name) ->
|
42 | return @spaces[name] or
|
43 | @spaces[name] = new TupleSpace(name)
|
44 |
|
45 | listen: (opts = {io: null, server: null}) ->
|
46 | unless opts.io?
|
47 | throw new Error '"io" must be instance of Socket.IO'
|
48 | unless opts.server instanceof http.Server
|
49 | throw new Error '"server" must be instance of http.Server'
|
50 | @io = opts.io
|
51 | @server = opts.server
|
52 |
|
53 | @oldListeners = @server.listeners('request').splice(0)
|
54 | @server.removeAllListeners 'request'
|
55 | @server.on 'request', (req, res) =>
|
56 | _url = url.parse(decodeURI(req.url), true)
|
57 | if _url.pathname == "/linda/linda.js"
|
58 | debug "GET\t#{_url.pathname}"
|
59 | res.setHeader 'Content-Type', 'application/javascript'
|
60 | res.writeHead 200
|
61 | res.end @client_js_code
|
62 | return
|
63 | for listener in @oldListeners
|
64 | listener.call(@server, req, res)
|
65 |
|
66 | @io.sockets.on 'connection', (socket) =>
|
67 | cids = {}
|
68 | info = {
|
69 | from: (socket.handshake.headers['x-forwarded-for'] or
|
70 | socket.handshake.address?.address)
|
71 | }
|
72 |
|
73 | socket.on '__linda_write', (data) =>
|
74 | data.options?.from = info.from
|
75 | @tuplespace(data.tuplespace).write data.tuple, data.options
|
76 | debug "write\t#{JSON.stringify data} from #{info.from}"
|
77 | @emit 'write', data
|
78 |
|
79 | socket.on '__linda_take', (data) =>
|
80 | cid = @tuplespace(data.tuplespace).take data.tuple, (err, tuple) ->
|
81 | cid = null
|
82 | socket.emit "__linda_take_#{data.id}", err, tuple
|
83 | cids[data.id] = cid
|
84 | debug "take\t#{JSON.stringify data} from #{info.from}"
|
85 | @emit 'take', data
|
86 | socket.once 'disconnect', =>
|
87 | @tuplespace(data.tuplespace).cancel cid if cid
|
88 |
|
89 | socket.on '__linda_read', (data) =>
|
90 | cid = @tuplespace(data.tuplespace).read data.tuple, (err, tuple) ->
|
91 | cid = null
|
92 | socket.emit "__linda_read_#{data.id}", err, tuple
|
93 | cids[data.id] = cid
|
94 | debug "read\t#{JSON.stringify data} from #{info.from}"
|
95 | @emit 'read', data
|
96 | socket.once 'disconnect', =>
|
97 | @tuplespace(data.tuplespace).cancel cid if cid
|
98 |
|
99 | watch_cids = {}
|
100 | socket.on '__linda_watch', (data) =>
|
101 | debug "watch\t#{JSON.stringify data} from #{info.from}"
|
102 | @emit 'watch', data
|
103 | return if watch_cids[data.id]
|
104 | watch_cids[data.id] = true
|
105 | cid = @tuplespace(data.tuplespace).watch data.tuple, (err, tuple) ->
|
106 | socket.emit "__linda_watch_#{data.id}", err, tuple
|
107 | cids[data.id] = cid
|
108 | socket.once 'disconnect', =>
|
109 | @tuplespace(data.tuplespace).cancel cid if cid
|
110 |
|
111 | socket.on '__linda_cancel', (data) =>
|
112 | debug "cancel\t#{JSON.stringify data} from #{info.from}"
|
113 | @emit 'cancel', data
|
114 | @tuplespace(data.tuplespace).cancel cids[data.id]
|
115 | watch_cids[data.id] = false
|
116 |
|
117 | return @
|
118 |
|
119 |
|
120 | module.exports.Server = new Linda
|