UNPKG

4.11 kBtext/coffeescriptView Raw
1http = require 'http'
2path = require 'path'
3url = require 'url'
4fs = require 'fs'
5request = require 'request'
6events = require 'eventemitter2'
7socketio = require 'socket.io'
8debug = require('debug')('linda')
9
10TupleSpace = require path.join(__dirname, 'tuplespace')
11Tuple = require path.join(__dirname, 'tuple')
12Client = require path.join(__dirname, 'linda-client')
13
14module.exports.TupleSpace = TupleSpace
15module.exports.Tuple = Tuple
16module.exports.Client = Client
17
18class 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 # 3min
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) => ## intercept requests
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] # not watch if already watching
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
120module.exports.Server = new Linda