1 | path = require 'path'
|
2 | Tuple = require path.join(__dirname, 'tuple')
|
3 |
|
4 | module.exports = class TupleSpace
|
5 | constructor: (@name='noname') ->
|
6 | @tuples = []
|
7 | @callbacks = []
|
8 | @__defineGetter__ 'size', ->
|
9 | return @tuples.length
|
10 |
|
11 | write: (tuple, options={expire: Tuple.DEFAULT.expire}) ->
|
12 | return if !Tuple.isHash(tuple) and !(tuple instanceof Tuple)
|
13 | tuple = new Tuple(tuple) unless tuple instanceof Tuple
|
14 | tuple.expire =
|
15 | if typeof options.expire is 'number' and options.expire > 0
|
16 | options.expire
|
17 | else
|
18 | Tuple.DEFAULT.expire
|
19 | tuple.from = options.from
|
20 | called = []
|
21 | taked = false
|
22 | for i in [0...@callbacks.length]
|
23 | c = @callbacks[i]
|
24 | if c.tuple.match tuple
|
25 | called.push i if c.type is 'take' or c.type is 'read'
|
26 | do (c) ->
|
27 | setImmediate -> c.callback(null, tuple)
|
28 | if c.type is 'take'
|
29 | taked = true
|
30 | break
|
31 | for i in called by -1
|
32 | @callbacks.splice i, 1
|
33 | @tuples.push tuple unless taked
|
34 |
|
35 | create_callback_id: ->
|
36 | return Date.now() - Math.random()
|
37 |
|
38 | read: (tuple, callback) ->
|
39 | return unless typeof callback is 'function'
|
40 | if !Tuple.isHash(tuple) and !(tuple instanceof Tuple)
|
41 | setImmediate -> callback('argument_error')
|
42 | return null
|
43 | tuple = new Tuple(tuple) unless tuple instanceof Tuple
|
44 | for i in [@size-1..0]
|
45 | t = @tuples[i]
|
46 | if tuple.match t
|
47 | setImmediate -> callback(null, t)
|
48 | return
|
49 | id = @create_callback_id()
|
50 | @callbacks.push {type: 'read', callback: callback, tuple: tuple, id: id}
|
51 | return id
|
52 |
|
53 | take: (tuple, callback) ->
|
54 | return unless typeof callback is 'function'
|
55 | if !Tuple.isHash(tuple) and !(tuple instanceof Tuple)
|
56 | setImmediate -> callback('argument_error')
|
57 | return null
|
58 | tuple = new Tuple(tuple) unless tuple instanceof Tuple
|
59 | for i in [@size-1..0]
|
60 | t = @tuples[i]
|
61 | if tuple.match t
|
62 | setImmediate -> callback(null, t)
|
63 | @tuples.splice i, 1
|
64 | return
|
65 | id = @create_callback_id()
|
66 | @callbacks.push {type: 'take', callback: callback, tuple: tuple, id: id}
|
67 | return id
|
68 |
|
69 | watch: (tuple, callback) ->
|
70 | return unless typeof callback is 'function'
|
71 | if !Tuple.isHash(tuple) and !(tuple instance Tuple)
|
72 | setImmediate -> callback('argument_error')
|
73 | return
|
74 | tuple = new Tuple(tuple) unless tuple instanceof Tuple
|
75 | id = @create_callback_id()
|
76 | @callbacks.unshift
|
77 | id: id
|
78 | type: 'watch'
|
79 | tuple: tuple
|
80 | callback: callback
|
81 | return id
|
82 |
|
83 | cancel: (id) ->
|
84 | return unless id?
|
85 | for i in [0...@callbacks.length]
|
86 | c = @callbacks[i]
|
87 | if id is c.id
|
88 | setImmediate -> c.callback('cancel', null)
|
89 | @callbacks.splice i, 1
|
90 | return
|
91 |
|
92 | check_expire: ->
|
93 | expires = []
|
94 | for i in [0...@tuples.length]
|
95 | if @tuples[i].expire_at < Date.now() / 1000
|
96 | expires.push i
|
97 | for i in expires by -1
|
98 | @tuples.splice i, 1
|
99 | return expires.length
|