statebus 6.1.20 → 6.1.23

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 +135 -30
  2. package/package.json +1 -1
  3. package/server.js +16 -14
  4. package/statebus.js +7 -5
package/client.js CHANGED
@@ -37,7 +37,7 @@
37
37
  // link.href = url
38
38
  // url = link.href
39
39
  // }
40
- console.log('opening websocket to', url)
40
+
41
41
  return new WebSocket(url + '/' + websocket_prefix + '/websocket')
42
42
  // return new SockJS(url + '/' + websocket_prefix)
43
43
  }
@@ -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
 
@@ -453,11 +558,10 @@
453
558
  window.ignore_flashbacks = false
454
559
  if (statebus_server !== 'none') {
455
560
  if (clientjs_option('braid_mode')) {
456
- console.log('We socket-free!')
561
+ console.log('Using Braid-HTTP!')
457
562
  braid_http_mount ('/*', statebus_server)
458
563
  } else {
459
564
  bus.net_mount ('/*', statebus_server)
460
- console.log('We going websocket!')
461
565
  }
462
566
  }
463
567
 
@@ -587,7 +691,8 @@
587
691
  for (var k in this.props)
588
692
  if (this.props.hasOwnProperty(k))
589
693
  new_props[k] = this.props[k]
590
- if (this.state.value) new_props.value = this.state.value
694
+ if (this.state.hasOwnProperty('value'))
695
+ new_props.value = this.state.value
591
696
  new_props.onChange = this.onChange
592
697
  return element(new_props)
593
698
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "statebus",
3
- "version": "6.1.20",
3
+ "version": "6.1.23",
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
@@ -10,10 +10,12 @@
10
10
  // Fetch, Save, Forget, Delete
11
11
 
12
12
  function fetch (key, callback) {
13
+ if (typeof key !== 'string'
14
+ && !(typeof key === 'object' && typeof key.key === 'string'))
15
+ throw ('Error: fetch(key) called with key = '
16
+ + JSON.stringify(key))
13
17
  key = key.key || key // You can pass in an object instead of key
14
18
  // We should probably disable this in future
15
- if (typeof key !== 'string')
16
- throw ('Error: fetch(key) called with a non-string key: '+key)
17
19
  bogus_check(key)
18
20
 
19
21
  var called_from_reactive_funk = !callback
@@ -2177,13 +2179,13 @@
2177
2179
  if (a_array !== b_array) return ' = ' + JSON.stringify(b)
2178
2180
  if (a_array) {
2179
2181
  if (a.length === b.length-1
2180
- && !deep_equals(a[a.length], b[b.length])) {
2181
- return '.push(' +JSON.stringify(b[b.length]) + ')'
2182
+ && deep_equals(a[a.length-1], b[b.length-2])) {
2183
+ return '.push(' +JSON.stringify(b[b.length-1]) + ')'
2182
2184
  }
2183
2185
  for (var i=0; i < a.length; i++) {
2184
2186
  var tmp = sorta_diff (a[i], b[i])
2185
2187
  if (tmp)
2186
- return '['+i+'] = '+tmp
2188
+ return '['+i+']'+tmp
2187
2189
  }
2188
2190
  return null
2189
2191
  }