statebus 6.1.21 → 6.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/client.js +133 -27
  2. package/package.json +1 -1
  3. package/server.js +16 -14
  4. package/statebus.js +9 -6
package/client.js CHANGED
@@ -62,7 +62,8 @@
62
62
  var preprefix = prefix.slice(0,-1)
63
63
  var has_prefix = new RegExp('^' + preprefix)
64
64
  var is_absolute = /^https?:\/\//
65
- var client_fetched_keys = new bus.Set()
65
+ var subscriptions = {}
66
+ var put_counter = 0
66
67
  //if (url[url.length-1]=='/') url = url.substr(0,url.length-1)
67
68
  function add_prefix (key) {
68
69
  return is_absolute.test(key) ? key : preprefix + key }
@@ -73,45 +74,149 @@
73
74
  function rem_prefixes (obj) {
74
75
  return bus.translate_keys(bus.clone(obj), rem_prefix) }
75
76
 
77
+
78
+ var puts = new Map()
79
+ function enqueue_put (url, body) {
80
+ var id = put_counter++
81
+ puts.set(id, {url: url, body: body, id: id})
82
+ send_put(id)
83
+ }
84
+ function send_put (id) {
85
+ try {
86
+ puts.get(id).status = 'sending'
87
+ braid_fetch(
88
+ puts.get(id).url,
89
+ {
90
+ method: 'put',
91
+ headers: {
92
+ 'content-type': 'application/json',
93
+ 'put-order': id,
94
+ },
95
+ body: puts.get(id).body
96
+ }
97
+ ).then(function (res) {
98
+ if (res.status !== 200)
99
+ console.error('Server gave error on PUT:',
100
+ e, 'for', puts.get(id).body)
101
+ else
102
+ console.log('Successful put!', puts.get(id).body)
103
+ puts.delete(id)
104
+ }).catch(function (e) {
105
+ console.error('Error on PUT, waiting...', puts.get(id).url)
106
+ puts.get(id).status = 'waiting'
107
+ // console.error('Error on PUT:', e, 'for', puts.get(id).body)
108
+ // puts.delete(id)
109
+ })
110
+ } catch (e) {
111
+ console.error('Error on PUT, waiting...', puts.get(id).url)
112
+ puts.get(id).status = 'waiting'
113
+ }
114
+ }
115
+ function retry_put (id) {
116
+ setTimeout(function () {send_put(id)}, 1000)
117
+ }
118
+ function send_all_puts () {
119
+ puts.keys().forEach(function (id) {
120
+ if (puts.get(id).status === 'waiting') {
121
+ console.log('Sending waiting put', id)
122
+ send_put(id)
123
+ }
124
+ })
125
+ }
126
+
76
127
  bus(prefix).to_save = function (obj, t) {
77
128
  bus.save.fire(obj)
78
129
 
130
+ enqueue_put(url + rem_prefix(obj.key),
131
+ JSON.stringify(obj.val))
79
132
  // var x = {save: obj}
80
133
  // if (t.version) x.version = t.version
81
134
  // if (t.parents) x.parents = t.parents
82
135
  // if (t.patch) x.patch = t.patch
83
136
  // if (t.patch) x.save = rem_prefix(x.save.key)
84
-
85
- braid_fetch(url + rem_prefix(obj.key),
86
- {
87
- method: 'put',
88
- 'content-type': 'application/json',
89
- body: JSON.stringify(obj.val)
90
- })
91
137
  }
92
138
 
93
139
  bus(prefix).to_fetch = function (key, t) {
94
- try {
95
- braid_fetch(url + rem_prefix(key),
96
- {
97
- method: 'get',
98
- subscribe: true,
99
- headers: {accept: 'application/json'}
100
- }
101
- ).andThen( function (x) {
102
- t.return({
103
- key: key,
104
- val: add_prefixes(JSON.parse(x.body))
105
- })
106
- })
107
- } catch (e) {
108
- console.error('Braid-HTTP network error:', e)
140
+ // Subscription can be in states:
141
+ // - connecting
142
+ // - connected
143
+ // - reconnect
144
+ // - reconnecting
145
+ // - aborted
146
+
147
+ // If we have an outstanding fetch running, then let's tell it to
148
+ // re-activate!
149
+ if (subscriptions[key]) {
150
+ // We should only be here if an existing subscription was
151
+ // aborted, but hasn't cleared yet.
152
+ console.assert(subscriptions[key].status === 'aborted',
153
+ 'Refetching a subscription of status '
154
+ + subscriptions[key].status)
155
+
156
+ console.trace('foo')
157
+
158
+ // Let's tell it to reconnect when it tries to clear!
159
+ subscriptions[key].status = 'reconnect'
160
+ }
161
+
162
+ // Otherwise, create a new subscription
163
+ else
164
+ subscribe (key, t)
165
+
166
+ function subscribe (key, t) {
167
+ var aborter = new AbortController(),
168
+ reconnect_attempts = 0
169
+
170
+ // Start the subscription!
171
+ braid_fetch(
172
+ // URL
173
+ url + rem_prefix(key),
174
+
175
+ // Options
176
+ {
177
+ method: 'get',
178
+ subscribe: true,
179
+ headers: {accept: 'application/json'},
180
+ signal: aborter.signal
181
+ }
182
+ ).andThen( function (x) {
183
+ // New update received!
184
+ if (subscriptions[key].status === 'connecting') {
185
+ console.log('%c[*] opened ' + key,
186
+ 'color: blue')
187
+ reconnect_attempts = 0
188
+ subscriptions[key].status = 'connected'
189
+ send_all_puts()
190
+ }
191
+
192
+ // Return the update
193
+ t.return({
194
+ key: key,
195
+ val: add_prefixes(JSON.parse(x.body))
196
+ })
197
+ }).catch( function (e) {
198
+ if (subscriptions[key].status === 'aborted') {
199
+ // Then this fetch is over and done with!
200
+ delete subscriptions[key]
201
+ return
202
+ }
203
+
204
+ // Reconnect!
205
+ setTimeout(function () { subscribe(key, t) },
206
+ reconnect_attempts > 0 ? 5000 : 1500)
207
+ subscriptions[key].status = 'reconnecting'
208
+ })
209
+
210
+ // Remember this subscription
211
+ subscriptions[key] = {
212
+ aborter: aborter,
213
+ status: 'connecting'
214
+ }
109
215
  }
110
- client_fetched_keys.add(key)
111
216
  }
112
217
  bus(prefix).to_forget = function (key) {
113
- // send({forget: key}),
114
- client_fetched_keys.delete(key)
218
+ subscriptions[key].status = 'aborted'
219
+ subscriptions[key].aborter.abort()
115
220
  }
116
221
  }
117
222
 
@@ -586,7 +691,8 @@
586
691
  for (var k in this.props)
587
692
  if (this.props.hasOwnProperty(k))
588
693
  new_props[k] = this.props[k]
589
- if (this.state.value) new_props.value = this.state.value
694
+ if (this.state.hasOwnProperty('value'))
695
+ new_props.value = this.state.value
590
696
  new_props.onChange = this.onChange
591
697
  return element(new_props)
592
698
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "statebus",
3
- "version": "6.1.21",
3
+ "version": "6.1.24",
4
4
  "description": "Synchronize state.",
5
5
  "main": "statebus.js",
6
6
  "scripts": {
package/server.js CHANGED
@@ -219,24 +219,25 @@ function import_server (bus, options)
219
219
  cbus.fetch(key, cb = (o) => {
220
220
  var body = bus.to_http_body(o)
221
221
 
222
- // // Return 404 if the value is undefined
223
- // if (!body) {
224
- // console.log('no body! time to 404')
225
- // res.statusCode = 404
226
- // res.end()
227
- // }
228
-
229
- // Or if we're braid, send via subscription
230
- // else
222
+ // If we're braiding, send via subscription
231
223
  if (braidify)
224
+ // Note: if body === undefined, we need to send the
225
+ // equivalent of a 404. This is missing in braid spec:
226
+ // https://github.com/braid-org/braid-spec/issues/110
232
227
  res.sendVersion({body: body || 'null'})
233
228
 
234
229
  // Or just return the current version
235
- else
236
- res.send(body)
230
+ else {
231
+ if (body !== undefined)
232
+ res.send(body)
233
+ else {
234
+ res.statusCode = 404
235
+ res.end()
236
+ }
237
+ }
237
238
 
238
- // And shut down the connection if nothing's left to do
239
- if (!braidify || !req.subscribe || !body)
239
+ // And shut down the connection if there's no subscription
240
+ if (!braidify || !req.subscribe)
240
241
  end_it_all()
241
242
  })
242
243
  }
@@ -587,6 +588,7 @@ function import_server (bus, options)
587
588
  }
588
589
  })
589
590
 
591
+ // console.log('websocket listening on', '/' + bus.options.websocket_path)
590
592
  s.installHandlers(httpserver, {prefix:'/' + bus.options.websocket_path})
591
593
  },
592
594
 
@@ -595,7 +597,7 @@ function import_server (bus, options)
595
597
  url = url.replace(/^istate:\/\//, 'ws://')
596
598
  url = url.replace(/^statei:\/\//, 'ws://')
597
599
  WebSocket = require('websocket').w3cwebsocket
598
- return new WebSocket(url+'/'+bus.options.websocket_path+'/websocket')
600
+ return new WebSocket(url + '/' + bus.options.websocket_path + '/websocket')
599
601
  },
600
602
  client_creds: function client_creds (server_url) {
601
603
  // Right now the server just creates a different random id each time
package/statebus.js CHANGED
@@ -430,9 +430,11 @@
430
430
  statelog(key, yellow, 'v', 'Deleting ' + key)
431
431
  // Call the to_delete handlers
432
432
  var handlers_called = bus.route(key, 'to_delete', key)
433
- if (handlers_called === 0)
433
+ if (handlers_called === 0) {
434
434
  // And go ahead and delete if there aren't any!
435
435
  delete cache[key]
436
+ delete backup_cache[key]
437
+ }
436
438
 
437
439
  // Call the on_delete handlers
438
440
  bus.route(key, 'on_delete', cache[key] || {key: key}, t)
@@ -828,9 +830,10 @@
828
830
  // except through an explicit .revise() function.
829
831
  if (o) t.version = new_version()
830
832
 
831
- if (method === 'to_delete')
833
+ if (method === 'to_delete') {
832
834
  delete bus.cache[key]
833
- else if (method === 'to_save') {
835
+ delete bus.backup_cache[key]
836
+ } else if (method === 'to_save') {
834
837
  bus.save.fire(o || arg, t)
835
838
  bus.route(key, 'on_set_sync', o || arg, t)
836
839
  } else {
@@ -2179,13 +2182,13 @@
2179
2182
  if (a_array !== b_array) return ' = ' + JSON.stringify(b)
2180
2183
  if (a_array) {
2181
2184
  if (a.length === b.length-1
2182
- && !deep_equals(a[a.length], b[b.length])) {
2183
- return '.push(' +JSON.stringify(b[b.length]) + ')'
2185
+ && deep_equals(a[a.length-1], b[b.length-2])) {
2186
+ return '.push(' +JSON.stringify(b[b.length-1]) + ')'
2184
2187
  }
2185
2188
  for (var i=0; i < a.length; i++) {
2186
2189
  var tmp = sorta_diff (a[i], b[i])
2187
2190
  if (tmp)
2188
- return '['+i+'] = '+tmp
2191
+ return '['+i+']'+tmp
2189
2192
  }
2190
2193
  return null
2191
2194
  }