statebus 6.1.22 → 7.0.2
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.
- package/{client.js → clients.js} +184 -130
- package/extras/tests.js +292 -412
- package/package.json +10 -3
- package/{server.js → servers.js} +285 -333
- package/statebus.js +297 -620
- package/extras/coffee.js +0 -12
- package/extras/dash.coffee +0 -302
- package/extras/diffsync.js +0 -1462
- package/extras/getCaretCoordinates.js +0 -141
- package/extras/react.js +0 -18147
- package/extras/sockjs.js +0 -27
package/statebus.js
CHANGED
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
if (typeof module != 'undefined') module.exports = definition()
|
|
4
4
|
else if (typeof define == 'function' && typeof define.amd == 'object') define(definition)
|
|
5
5
|
else this[name] = definition()
|
|
6
|
-
}('statebus', function() {statelog_indent = 0; var busses = {}, executing_funk, global_funk, funks = {}, clean_timer, symbols, nodejs = typeof window === 'undefined'; function make_bus (options) {
|
|
7
|
-
|
|
6
|
+
}('statebus', function() {statelog_indent = 0; var busses = {}, bus_count = 0, executing_funk, global_funk, funks = {}, clean_timer, symbols, nodejs = typeof window === 'undefined'; function make_bus (options) {
|
|
7
|
+
|
|
8
8
|
|
|
9
9
|
// ****************
|
|
10
|
-
//
|
|
10
|
+
// Get, Set, Forget, Delete
|
|
11
11
|
|
|
12
|
-
function
|
|
12
|
+
function get (key, callback) {
|
|
13
13
|
if (typeof key !== 'string'
|
|
14
14
|
&& !(typeof key === 'object' && typeof key.key === 'string'))
|
|
15
|
-
throw ('Error:
|
|
15
|
+
throw ('Error: get(key) called with key = '
|
|
16
16
|
+ JSON.stringify(key))
|
|
17
17
|
key = key.key || key // You can pass in an object instead of key
|
|
18
18
|
// We should probably disable this in future
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
// Initialize callback
|
|
25
25
|
if (callback) {
|
|
26
26
|
(callback.defined = callback.defined || []
|
|
27
|
-
).push({as:'
|
|
27
|
+
).push({as:'get callback', key:key});
|
|
28
28
|
callback.has_seen = callback.has_seen || function (bus, key, version) {
|
|
29
29
|
callback.seen_keys = callback.seen_keys || {}
|
|
30
30
|
var bus_key = JSON.stringify([bus.id, key])
|
|
@@ -37,27 +37,27 @@
|
|
|
37
37
|
|
|
38
38
|
// ** Subscribe the calling funk **
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
gets_in.add(key, funk_key(funk))
|
|
41
41
|
if (to_be_forgotten[key]) {
|
|
42
42
|
clearTimeout(to_be_forgotten[key])
|
|
43
43
|
delete to_be_forgotten[key]
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
bind(key, '
|
|
46
|
+
bind(key, 'on_set', funk)
|
|
47
47
|
|
|
48
|
-
// ** Call
|
|
48
|
+
// ** Call getters upstream **
|
|
49
49
|
|
|
50
|
-
// TODO: checking
|
|
50
|
+
// TODO: checking gets_out[] doesn't count keys that we got which
|
|
51
51
|
// arrived nested within a bigger object, because we never explicity
|
|
52
|
-
//
|
|
52
|
+
// got those keys. But we don't need to get them now cause we
|
|
53
53
|
// already have them.
|
|
54
|
-
var
|
|
55
|
-
if (!
|
|
56
|
-
|
|
54
|
+
var to_getters = 0
|
|
55
|
+
if (!gets_out[key])
|
|
56
|
+
to_getters = bus.route(key, 'to_get', key)
|
|
57
57
|
|
|
58
58
|
// Now there might be a new value pubbed onto this bus.
|
|
59
|
-
// Or there might be a pending
|
|
60
|
-
// ... or there weren't any
|
|
59
|
+
// Or there might be a pending get.
|
|
60
|
+
// ... or there weren't any getters upstream.
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
// ** Return a value **
|
|
@@ -70,29 +70,29 @@
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
// Otherwise, we want to make sure that a pub gets called on the
|
|
73
|
-
// handler. If there's a pending
|
|
74
|
-
// If there was a
|
|
73
|
+
// handler. If there's a pending get, then it'll get called later.
|
|
74
|
+
// If there was a to_get, then it already got called. Otherwise,
|
|
75
75
|
// let's call it now.
|
|
76
|
-
else if (!
|
|
76
|
+
else if (!pending_gets[key] && to_getters === 0) {
|
|
77
77
|
// TODO: my intuition suggests that we might prefer to delay this
|
|
78
|
-
// .
|
|
79
|
-
// with other calls to .
|
|
78
|
+
// .on_set getting called in a setTimeout(f,0), to be consistent
|
|
79
|
+
// with other calls to .on_set.
|
|
80
80
|
backup_cache[key] = backup_cache[key] || {key: key}
|
|
81
|
-
run_handler(funk, '
|
|
81
|
+
run_handler(funk, 'on_set', cache[key] = cache[key] || {key: key})
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
function
|
|
84
|
+
function get_once (key, cb) {
|
|
85
85
|
function cb2 (o) { cb(o); forget(key, cb2) }
|
|
86
|
-
//
|
|
87
|
-
|
|
86
|
+
// get(key) // This prevents key from being forgotten
|
|
87
|
+
get(key, cb2)
|
|
88
88
|
}
|
|
89
|
-
|
|
90
|
-
var
|
|
91
|
-
var
|
|
92
|
-
var
|
|
89
|
+
get.once = get_once
|
|
90
|
+
var pending_gets = {}
|
|
91
|
+
var gets_out = {} // Maps `key' to `func' iff we've got `key'
|
|
92
|
+
var gets_in = new One_To_Many() // Maps `key' to `pub_funcs' subscribed to our key
|
|
93
93
|
|
|
94
94
|
var currently_saving
|
|
95
|
-
function
|
|
95
|
+
function set (obj, t) {
|
|
96
96
|
// First let's handle diffs
|
|
97
97
|
if (typeof obj === 'string' && t && t.patch) {
|
|
98
98
|
if (typeof t.patch == 'string') t.patch = [t.patch]
|
|
@@ -101,8 +101,8 @@
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
if (!('key' in obj) || typeof obj.key !== 'string') {
|
|
104
|
-
console.error('Error:
|
|
105
|
-
console.trace('Bad
|
|
104
|
+
console.error('Error: set(obj) called on object without a key: ', obj)
|
|
105
|
+
console.trace('Bad set(obj)')
|
|
106
106
|
}
|
|
107
107
|
bogus_check(obj.key)
|
|
108
108
|
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
if (honking_at(obj.key))
|
|
119
|
-
var message =
|
|
119
|
+
var message = set_msg(obj, t, 'set')
|
|
120
120
|
|
|
121
121
|
// Ignore if nothing happened
|
|
122
122
|
if (obj.key && !changed(obj)) {
|
|
@@ -130,11 +130,11 @@
|
|
|
130
130
|
var was_saving = currently_saving
|
|
131
131
|
currently_saving = obj.key
|
|
132
132
|
|
|
133
|
-
// Call the
|
|
134
|
-
var num_handlers = bus.route(obj.key, '
|
|
133
|
+
// Call the to_set() handlers!
|
|
134
|
+
var num_handlers = bus.route(obj.key, 'to_set', obj, t)
|
|
135
135
|
if (num_handlers === 0) {
|
|
136
136
|
// And fire if there weren't any!
|
|
137
|
-
|
|
137
|
+
set.fire(obj, t)
|
|
138
138
|
bus.route(obj.key, 'on_set_sync', obj, t)
|
|
139
139
|
}
|
|
140
140
|
}
|
|
@@ -143,13 +143,13 @@
|
|
|
143
143
|
currently_saving = was_saving
|
|
144
144
|
}
|
|
145
145
|
// TODO: Here's an alternative. Instead of counting the handlers and
|
|
146
|
-
// seeing if there are zero, I could just make a
|
|
146
|
+
// seeing if there are zero, I could just make a to_set handler that
|
|
147
147
|
// is shadowed by other handlers if I can get later handlers to shadow
|
|
148
148
|
// earlier ones.
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
//
|
|
152
|
-
|
|
151
|
+
// set.sync() will set with the version of the current executing reaction
|
|
152
|
+
set.sync = function set_sync (obj, t) {
|
|
153
153
|
t = bus.clone(t || {})
|
|
154
154
|
// t.version: executing_funk?.transaction?.version
|
|
155
155
|
// || executing_funk?.latest_reaction_at
|
|
@@ -158,13 +158,13 @@
|
|
|
158
158
|
&& executing_funk.transaction.version)
|
|
159
159
|
|| (executing_funk
|
|
160
160
|
&& executing_funk.latest_reaction_at))
|
|
161
|
-
|
|
161
|
+
set(obj, t)
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
// We might eventually want a
|
|
164
|
+
// We might eventually want a set.fire.sync() too, which defaults the
|
|
165
165
|
// version to `executing_funk?.transaction?.version`
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
set.fire = fire
|
|
168
168
|
function fire (obj, t) {
|
|
169
169
|
t = t || {}
|
|
170
170
|
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
// Warning: Changes to *nested* objects will *not* be printed out!
|
|
179
179
|
// In the future, we'll remove the recursion from fire() so that
|
|
180
180
|
// nested objects aren't even changed.
|
|
181
|
-
var message =
|
|
181
|
+
var message = set_msg(obj, t, 'set.fire')
|
|
182
182
|
var color, icon
|
|
183
183
|
if (currently_saving === obj.key &&
|
|
184
184
|
!(obj.key && !changed(obj))) {
|
|
@@ -191,18 +191,18 @@
|
|
|
191
191
|
if (obj.key && !changed(obj)) {
|
|
192
192
|
color = grey
|
|
193
193
|
icon = 'x'
|
|
194
|
-
if (t.
|
|
195
|
-
message = (t.m) || '
|
|
194
|
+
if (t.to_get)
|
|
195
|
+
message = (t.m) || 'Got ' + bus + "('"+obj.key+"')"
|
|
196
196
|
if (t.version) message += ' [' + t.version + ']'
|
|
197
197
|
statelog(obj.key, color, icon, message)
|
|
198
198
|
return
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
color = red, icon = '•'
|
|
202
|
-
if (t.
|
|
202
|
+
if (t.to_get || pending_gets[obj.key]) {
|
|
203
203
|
color = green
|
|
204
204
|
icon = '^'
|
|
205
|
-
message = add_diff_msg((t.m)||'
|
|
205
|
+
message = add_diff_msg((t.m)||'Got '+bus+"('"+obj.key+"')",
|
|
206
206
|
obj)
|
|
207
207
|
if (t.version) message += ' [' + t.version + ']'
|
|
208
208
|
}
|
|
@@ -215,7 +215,7 @@
|
|
|
215
215
|
// Recursively add all of obj, and its sub-objects, into the cache
|
|
216
216
|
var modified_keys = update_cache(obj, cache)
|
|
217
217
|
|
|
218
|
-
delete
|
|
218
|
+
delete pending_gets[obj.key]
|
|
219
219
|
|
|
220
220
|
if ((executing_funk !== global_funk) && executing_funk.loading()) {
|
|
221
221
|
abort_changes(modified_keys)
|
|
@@ -236,7 +236,7 @@
|
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
set.abort = function (obj, t) {
|
|
240
240
|
if (!obj) console.error('No obj', obj)
|
|
241
241
|
abort_changes([obj.key])
|
|
242
242
|
statelog(obj.key, yellow, '<', 'Aborting ' + obj.key)
|
|
@@ -249,19 +249,19 @@
|
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
// Now create the statebus object
|
|
252
|
-
function bus (
|
|
252
|
+
function bus (arg1, arg2) {
|
|
253
253
|
// Called with a function to react to
|
|
254
|
-
if (typeof
|
|
255
|
-
var f = reactive(
|
|
254
|
+
if (typeof arg1 === 'function') {
|
|
255
|
+
var f = reactive(arg1)
|
|
256
256
|
f()
|
|
257
257
|
return f
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
// Called with a key to produce a subspace
|
|
261
|
-
else return subspace(
|
|
261
|
+
else return subspace(arg1, arg2)
|
|
262
262
|
}
|
|
263
|
-
var id = 'bus
|
|
264
|
-
bus.toString = function () { return bus.label || id }
|
|
263
|
+
var id = 'bus-' + Math.random().toString(36).substring(7)
|
|
264
|
+
bus.toString = function () { return bus.label || 'bus'+this_bus_num || id }
|
|
265
265
|
bus.delete_bus = function () {
|
|
266
266
|
// // Forget all wildcard handlers
|
|
267
267
|
// for (var i=0; i<wildcard_handlers.length; i++) {
|
|
@@ -297,7 +297,7 @@
|
|
|
297
297
|
// time they are pubbed into the cache. After that, we can
|
|
298
298
|
// trust that they aren't referenced elsewhere. (We make it
|
|
299
299
|
// the programmer's responsibility to clone data if necessary
|
|
300
|
-
// on
|
|
300
|
+
// on get, but not when on pub.)
|
|
301
301
|
//
|
|
302
302
|
// We'll optimize this once we have history. We can look at
|
|
303
303
|
// the old version to see if an object/array existed already
|
|
@@ -305,7 +305,7 @@
|
|
|
305
305
|
//
|
|
306
306
|
// 2. Don't go infinitely deep.
|
|
307
307
|
//
|
|
308
|
-
// Eventually, each
|
|
308
|
+
// Eventually, each set/pub will be limited to the scope
|
|
309
309
|
// underneath nested keyed objects. Right now I'm just
|
|
310
310
|
// recursing infinitely on the whole data structure with each
|
|
311
311
|
// pub.
|
|
@@ -365,7 +365,7 @@
|
|
|
365
365
|
}
|
|
366
366
|
|
|
367
367
|
function changed (object) {
|
|
368
|
-
return
|
|
368
|
+
return pending_gets[object.key]
|
|
369
369
|
|| ! cache.hasOwnProperty(object.key)
|
|
370
370
|
|| !backup_cache.hasOwnProperty(object.key)
|
|
371
371
|
|| !(deep_equals(object, backup_cache[object.key]))
|
|
@@ -376,7 +376,7 @@
|
|
|
376
376
|
}
|
|
377
377
|
|
|
378
378
|
|
|
379
|
-
function forget (key,
|
|
379
|
+
function forget (key, set_handler, t) {
|
|
380
380
|
if (arguments.length === 0) {
|
|
381
381
|
// Then we're forgetting the executing funk
|
|
382
382
|
console.assert(executing_funk !== global_funk,
|
|
@@ -386,26 +386,26 @@
|
|
|
386
386
|
}
|
|
387
387
|
bogus_check(key)
|
|
388
388
|
|
|
389
|
-
//log('forget:', key, funk_name(
|
|
390
|
-
|
|
391
|
-
var fkey = funk_key(
|
|
392
|
-
//console.log('
|
|
393
|
-
if (!
|
|
389
|
+
//log('forget:', key, funk_name(set_handler), funk_name(executing_funk))
|
|
390
|
+
set_handler = set_handler || executing_funk
|
|
391
|
+
var fkey = funk_key(set_handler)
|
|
392
|
+
//console.log('Gets in is', gets_in.hash)
|
|
393
|
+
if (!gets_in.has(key, fkey)) {
|
|
394
394
|
console.error("***\n****\nTrying to forget lost key", key,
|
|
395
|
-
'from', funk_name(
|
|
396
|
-
"that hasn't
|
|
395
|
+
'from', funk_name(set_handler), fkey,
|
|
396
|
+
"that hasn't got that key.")
|
|
397
397
|
console.trace()
|
|
398
398
|
return
|
|
399
399
|
// throw Error('asdfalsdkfajsdf')
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
-
|
|
403
|
-
unbind(key, '
|
|
402
|
+
gets_in.delete(key, fkey)
|
|
403
|
+
unbind(key, 'on_set', set_handler)
|
|
404
404
|
|
|
405
405
|
// If this is the last handler listening to this key, then we can
|
|
406
406
|
// delete the cache entry, send a forget upstream, and de-activate the
|
|
407
|
-
// .
|
|
408
|
-
if (!
|
|
407
|
+
// .on_get handler.
|
|
408
|
+
if (!gets_in.has_any(key)) {
|
|
409
409
|
clearTimeout(to_be_forgotten[key])
|
|
410
410
|
to_be_forgotten[key] = setTimeout(function () {
|
|
411
411
|
// Send a forget upstream
|
|
@@ -413,7 +413,7 @@
|
|
|
413
413
|
|
|
414
414
|
// Delete the cache entry...?
|
|
415
415
|
// delete cache[key]
|
|
416
|
-
delete
|
|
416
|
+
delete gets_out[key]
|
|
417
417
|
delete to_be_forgotten[key]
|
|
418
418
|
}, 200)
|
|
419
419
|
}
|
|
@@ -445,7 +445,7 @@
|
|
|
445
445
|
// etc.
|
|
446
446
|
// - NOTE: I did a crappy implementation of abort just now above!
|
|
447
447
|
// But it doesn't work if called after the to_delete handler returns.
|
|
448
|
-
// - Generalize the code across
|
|
448
|
+
// - Generalize the code across set and del with a "mutate"
|
|
449
449
|
// operation
|
|
450
450
|
//
|
|
451
451
|
// - Right now we fire the to_delete handlers right here.
|
|
@@ -460,18 +460,18 @@
|
|
|
460
460
|
}
|
|
461
461
|
|
|
462
462
|
var changed_keys = new Set()
|
|
463
|
-
var
|
|
463
|
+
var dirty_getters = {} // Maps funk_key => version dirtied at
|
|
464
464
|
function dirty (key, t) {
|
|
465
465
|
statelog(key, brown, '*', bus + ".dirty('"+key+"')")
|
|
466
466
|
bogus_check(key)
|
|
467
467
|
|
|
468
468
|
var version = (t && t.version) || 'dirty-' + new_version()
|
|
469
469
|
|
|
470
|
-
// Find any .
|
|
470
|
+
// Find any .to_get, and mark as dirty so that it re-runs
|
|
471
471
|
var found = false
|
|
472
|
-
if (
|
|
473
|
-
for (var i=0; i<
|
|
474
|
-
|
|
472
|
+
if (gets_out.hasOwnProperty(key))
|
|
473
|
+
for (var i=0; i<gets_out[key].length; i++) {
|
|
474
|
+
dirty_getters[funk_key(gets_out[key][i])] = version
|
|
475
475
|
found = true
|
|
476
476
|
}
|
|
477
477
|
clean_timer = clean_timer || setTimeout(clean)
|
|
@@ -488,7 +488,7 @@
|
|
|
488
488
|
}
|
|
489
489
|
|
|
490
490
|
function clean () {
|
|
491
|
-
// 1. Collect all functions for all keys and dirtied
|
|
491
|
+
// 1. Collect all functions for all keys and dirtied getters
|
|
492
492
|
var dirty_funks = {}
|
|
493
493
|
for (var b in busses) {
|
|
494
494
|
var fs = busses[b].rerunnable_funks()
|
|
@@ -497,7 +497,7 @@
|
|
|
497
497
|
}
|
|
498
498
|
clean_timer = null
|
|
499
499
|
|
|
500
|
-
// 2. Run any priority function first (e.g. file_store's
|
|
500
|
+
// 2. Run any priority function first (e.g. file_store's on_set)
|
|
501
501
|
log(bus.label, 'Cleaning up', Object.keys(dirty_funks).length, 'funks')
|
|
502
502
|
for (var k in dirty_funks) {
|
|
503
503
|
var funk = funks[k],
|
|
@@ -537,19 +537,19 @@
|
|
|
537
537
|
var result = []
|
|
538
538
|
var keys = changed_keys.values()
|
|
539
539
|
|
|
540
|
-
//log(bus+' Cleaning up!', keys, 'keys, and',
|
|
540
|
+
//log(bus+' Cleaning up!', keys, 'keys, and', getters.length, 'getters')
|
|
541
541
|
for (var i=0; i<keys.length; i++) { // Collect all keys
|
|
542
542
|
// if (to_be_forgotten[keys[i]])
|
|
543
543
|
// // Ignore changes to keys that have been forgotten, but not
|
|
544
544
|
// // processed yet
|
|
545
545
|
// continue
|
|
546
|
-
var fs = bindings(keys[i], '
|
|
546
|
+
var fs = bindings(keys[i], 'on_set')
|
|
547
547
|
for (var j=0; j<fs.length; j++) {
|
|
548
548
|
var f = fs[j].func
|
|
549
549
|
if (f.react) {
|
|
550
550
|
// Skip if it's already up to date
|
|
551
|
-
var v = f.
|
|
552
|
-
//log('re-run:', keys[i], f.statebus_id, f.
|
|
551
|
+
var v = f.getted_keys[JSON.stringify([this.id, keys[i]])]
|
|
552
|
+
//log('re-run:', keys[i], f.statebus_id, f.getted_keys)
|
|
553
553
|
if (v && v.indexOf(versions[keys[i]]) !== -1) {
|
|
554
554
|
log('skipping', funk_name(f), 'already at version', versions[keys[i]], 'proof:', v)
|
|
555
555
|
continue
|
|
@@ -566,19 +566,19 @@
|
|
|
566
566
|
continue
|
|
567
567
|
}
|
|
568
568
|
autodetect_args(f)
|
|
569
|
-
f = run_handler(f, '
|
|
570
|
-
|
|
569
|
+
f = run_handler(f, 'on_set', cache[keys[i]], {dont_run: true,
|
|
570
|
+
binding: keys[i]})
|
|
571
571
|
}
|
|
572
572
|
result.push({funk_key: funk_key(f),
|
|
573
573
|
at_version: versions[keys[i]]})
|
|
574
574
|
}
|
|
575
575
|
}
|
|
576
|
-
for (var k in
|
|
576
|
+
for (var k in dirty_getters) // Collect all getters
|
|
577
577
|
result.push({funk_key: k,
|
|
578
|
-
at_version:
|
|
578
|
+
at_version: dirty_getters[k]})
|
|
579
579
|
|
|
580
580
|
changed_keys.clear()
|
|
581
|
-
|
|
581
|
+
dirty_getters = {}
|
|
582
582
|
|
|
583
583
|
//log('found', result.length, 'funks to re run')
|
|
584
584
|
|
|
@@ -587,28 +587,43 @@
|
|
|
587
587
|
|
|
588
588
|
// ****************
|
|
589
589
|
// Connections
|
|
590
|
-
function subspace (key) {
|
|
591
|
-
var
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
590
|
+
function subspace (key, params) {
|
|
591
|
+
var methods = {to_get:null, to_set:null, on_set:null, on_set_sync:null,
|
|
592
|
+
on_delete:null, to_delete:null, to_forget:null}
|
|
593
|
+
|
|
594
|
+
if (params) {
|
|
595
|
+
for (var method in params) {
|
|
596
|
+
console.assert(method in methods)
|
|
597
|
+
var func = params[method]
|
|
598
|
+
autodetect_args(func)
|
|
599
|
+
func.defined = func.defined || []
|
|
600
|
+
func.defined.push({bus, method, key, as: 'handler'})
|
|
601
|
+
func.use_linked_json = true
|
|
602
|
+
bind(key, method, func, 'allow_wildcards')
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
else {
|
|
606
|
+
var result = {}
|
|
607
|
+
for (var method in methods)
|
|
608
|
+
(function (method) {
|
|
609
|
+
Object.defineProperty(result, method, {
|
|
610
|
+
set: function (func) {
|
|
611
|
+
autodetect_args(func)
|
|
612
|
+
func.defined = func.defined || []
|
|
613
|
+
func.defined.push(
|
|
614
|
+
{as:'handler', bus:bus, method:method, key:key})
|
|
615
|
+
bind(key, method, func, 'allow_wildcards')
|
|
616
|
+
},
|
|
617
|
+
get: function () {
|
|
618
|
+
var result = bindings(key, method)
|
|
619
|
+
for (var i=0; i<result.length; i++) result[i] = result[i].func
|
|
620
|
+
result.delete = function (func) { unbind (key, method, func, 'allow_wildcards') }
|
|
621
|
+
return result
|
|
622
|
+
}
|
|
623
|
+
})
|
|
624
|
+
})(method)
|
|
625
|
+
return result
|
|
626
|
+
}
|
|
612
627
|
}
|
|
613
628
|
|
|
614
629
|
function autodetect_args (handler) {
|
|
@@ -632,6 +647,7 @@
|
|
|
632
647
|
case 'star':
|
|
633
648
|
case 'rest':
|
|
634
649
|
handler.args['rest'] = i; break
|
|
650
|
+
case 'cb':
|
|
635
651
|
case 't':
|
|
636
652
|
case 'transaction':
|
|
637
653
|
handler.args['t'] = i; break
|
|
@@ -646,7 +662,7 @@
|
|
|
646
662
|
}
|
|
647
663
|
}
|
|
648
664
|
|
|
649
|
-
// The funks attached to each key, maps e.g. '
|
|
665
|
+
// The funks attached to each key, maps e.g. 'get /point/3' to '/30'
|
|
650
666
|
var handlers = new One_To_Many()
|
|
651
667
|
var wildcard_handlers = [] // An array of {prefix, method, funk}
|
|
652
668
|
|
|
@@ -661,7 +677,7 @@
|
|
|
661
677
|
else
|
|
662
678
|
handlers.add(method + ' ' + key, funk_key(func))
|
|
663
679
|
|
|
664
|
-
// Now check if the method is a
|
|
680
|
+
// Now check if the method is a get and there's a getted
|
|
665
681
|
// key in this space, and if so call the handler.
|
|
666
682
|
}
|
|
667
683
|
function unbind (key, method, funk, allow_wildcards) {
|
|
@@ -728,9 +744,9 @@
|
|
|
728
744
|
just_make_it = options.dont_run,
|
|
729
745
|
binding = options.binding
|
|
730
746
|
|
|
731
|
-
// When we first run a handler (e.g. a
|
|
732
|
-
// reactive() funk that calls it with its arg. Then if it
|
|
733
|
-
//
|
|
747
|
+
// When we first run a handler (e.g. a get or set), we wrap it in a
|
|
748
|
+
// reactive() funk that calls it with its arg. Then if it gets or
|
|
749
|
+
// sets, it'll register a .on_set handler with this funk.
|
|
734
750
|
|
|
735
751
|
// Is it reactive already? Let's distinguish it.
|
|
736
752
|
var funk = funck.react && funck, // Funky! So reactive!
|
|
@@ -740,7 +756,7 @@
|
|
|
740
756
|
|
|
741
757
|
if (false && !funck.global_funk) {
|
|
742
758
|
// \u26A1
|
|
743
|
-
var event = {'
|
|
759
|
+
var event = {'to_set':'set','on_set':'set.fire','to_get':'get',
|
|
744
760
|
'to_delete':'delete','to_forget':'forget'}[method],
|
|
745
761
|
triggering = funk ? 're-running' : 'initiating'
|
|
746
762
|
console.log(' > a', bus+'.'+event + "('" + (arg.key||arg) + "') is " + triggering
|
|
@@ -748,43 +764,50 @@
|
|
|
748
764
|
}
|
|
749
765
|
|
|
750
766
|
if (funk) {
|
|
751
|
-
// Then this is an
|
|
767
|
+
// Then this is an on_set event re-triggering an already-wrapped
|
|
752
768
|
// funk. It has its own arg internally that it's calling itself
|
|
753
769
|
// with. Let's tell it to re-trigger itself with that arg.
|
|
754
770
|
|
|
755
|
-
if (method !== '
|
|
756
|
-
console.error(method === '
|
|
771
|
+
if (method !== 'on_set') {
|
|
772
|
+
console.error(method === 'on_set', 'Funk is being re-triggered, but isn\'t on_set. It is: "' + method + '", oh and funk: ' + funk_name(funk))
|
|
757
773
|
return
|
|
758
774
|
}
|
|
759
775
|
return funk.react()
|
|
760
776
|
|
|
761
777
|
// Hmm... does this do the right thing? Example:
|
|
762
778
|
//
|
|
763
|
-
// bus('foo').
|
|
764
|
-
//
|
|
765
|
-
//
|
|
766
|
-
//
|
|
779
|
+
// bus('foo').on_set = function (o) {...}
|
|
780
|
+
// set({key: 'foo'})
|
|
781
|
+
// set({key: 'foo'})
|
|
782
|
+
// set({key: 'foo'})
|
|
767
783
|
//
|
|
768
784
|
// Does this spin up 3 reactive functions? Hmm...
|
|
769
785
|
// Well, I think it does, but they all get forgotten once
|
|
770
786
|
// they run once, and then are garbage collected.
|
|
771
787
|
//
|
|
772
|
-
// bus('foo*').
|
|
773
|
-
//
|
|
774
|
-
//
|
|
775
|
-
//
|
|
776
|
-
//
|
|
788
|
+
// bus('foo*').on_set = function (o) {...}
|
|
789
|
+
// set({key: 'foo1'})
|
|
790
|
+
// set({key: 'foo2'})
|
|
791
|
+
// set({key: 'foo1'})
|
|
792
|
+
// set({key: 'foo3'})
|
|
777
793
|
//
|
|
778
794
|
// Does this work ok? Yeah, I think so.
|
|
779
795
|
}
|
|
780
796
|
|
|
781
797
|
// Alright then. Let's wrap this func with some funk.
|
|
782
798
|
|
|
783
|
-
// Fresh
|
|
799
|
+
// Fresh get/set/forget/delete handlers will just be regular
|
|
784
800
|
// functions. We'll store their arg and transaction and let them
|
|
785
801
|
// re-run until they are done re-running.
|
|
786
802
|
function key_arg () { return ((typeof arg.key) == 'string') ? arg.key : arg }
|
|
787
803
|
function rest_arg () { return (key_arg()).substr(binding.length-1) }
|
|
804
|
+
function val_arg () {
|
|
805
|
+
console.assert(method === 'to_set' || method === 'on_set' || method === 'on_set_sync')
|
|
806
|
+
// Is there a time I am supposed to return bus.cache[arg]? It used to say:
|
|
807
|
+
// arg.key ? arg : bus.cache[arg]
|
|
808
|
+
|
|
809
|
+
return arg.key ? (func.use_linked_json ? arg.val : arg) : undefined
|
|
810
|
+
}
|
|
788
811
|
function vars_arg () {
|
|
789
812
|
var r = rest_arg()
|
|
790
813
|
try {
|
|
@@ -794,49 +817,50 @@
|
|
|
794
817
|
}
|
|
795
818
|
}
|
|
796
819
|
var f = reactive(function () {
|
|
797
|
-
|
|
798
820
|
// Initialize transaction
|
|
799
821
|
t = clone(t || {})
|
|
800
822
|
|
|
801
823
|
// Add .abort() method
|
|
802
|
-
if (method === '
|
|
824
|
+
if (method === 'to_set' || method === 'to_delete')
|
|
803
825
|
t.abort = function () {
|
|
804
|
-
var key = method === '
|
|
826
|
+
var key = method === 'to_set' ? arg.key : arg
|
|
805
827
|
if (f.loading()) return
|
|
806
828
|
bus.cache[key] = bus.cache[key] || {key: key}
|
|
807
829
|
bus.backup_cache[key] = bus.backup_cache[key] || {key: key}
|
|
808
|
-
bus.
|
|
830
|
+
bus.set.abort(bus.cache[key])
|
|
809
831
|
}
|
|
810
832
|
|
|
811
833
|
// Add .done() method
|
|
812
834
|
if (method !== 'to_forget')
|
|
813
835
|
t.done = function (o) {
|
|
814
|
-
var key = method === '
|
|
836
|
+
var key = method === 'to_set' ? arg.key : arg
|
|
837
|
+
if (func.use_linked_json)
|
|
838
|
+
o = {key, val: o}
|
|
815
839
|
bus.log('We are DONE()ing', method, key, o||arg)
|
|
816
840
|
|
|
817
841
|
// We use a simple (and crappy?) heuristic to know if the
|
|
818
|
-
//
|
|
842
|
+
// to_set handler has changed the state: whether the
|
|
819
843
|
// programmer passed (o) to the t.done(o) handler. If
|
|
820
844
|
// not, we assume it hasn't changed. If so, we assume it
|
|
821
845
|
// *has* changed, and thus we change the version of the
|
|
822
846
|
// state. I imagine it would be more accurate to diff
|
|
823
|
-
// from before the
|
|
847
|
+
// from before the to_set handler began with when
|
|
824
848
|
// t.done(o) ran.
|
|
825
849
|
//
|
|
826
850
|
// Note: We will likely solve this in the future by
|
|
827
|
-
// preventing .
|
|
851
|
+
// preventing .to_set() from changing the incoming state,
|
|
828
852
|
// except through an explicit .revise() function.
|
|
829
853
|
if (o) t.version = new_version()
|
|
830
854
|
|
|
831
855
|
if (method === 'to_delete')
|
|
832
856
|
delete bus.cache[key]
|
|
833
|
-
else if (method === '
|
|
834
|
-
bus.
|
|
857
|
+
else if (method === 'to_set') {
|
|
858
|
+
bus.set.fire(o || arg, t)
|
|
835
859
|
bus.route(key, 'on_set_sync', o || arg, t)
|
|
836
860
|
} else {
|
|
837
|
-
// Now method === '
|
|
861
|
+
// Now method === 'to_get'
|
|
838
862
|
o.key = key
|
|
839
|
-
bus.
|
|
863
|
+
bus.set.fire(o, t)
|
|
840
864
|
// And now reset the version cause it could get called again
|
|
841
865
|
delete t.version
|
|
842
866
|
}
|
|
@@ -845,14 +869,14 @@
|
|
|
845
869
|
// Alias .return() to .done(), in case that feels better to you
|
|
846
870
|
t.return = t.done
|
|
847
871
|
|
|
848
|
-
// Alias t.
|
|
849
|
-
if (method === '
|
|
850
|
-
t.
|
|
872
|
+
// Alias t.reget() to bus.dirty()
|
|
873
|
+
if (method === 'to_set')
|
|
874
|
+
t.reget = function () { bus.dirty(arg.key) }
|
|
851
875
|
|
|
852
876
|
// Now to call the handler, let's line up the function's special
|
|
853
877
|
// named arguemnts like key, o, t, rest, vars, etc.
|
|
854
878
|
var args = []
|
|
855
|
-
args[0] = arg
|
|
879
|
+
args[0] = (method in {to_set:1, on_set:1, on_set_sync:1}) ? val_arg() : arg
|
|
856
880
|
args[1] = t
|
|
857
881
|
for (var k in (func.args||{})) {
|
|
858
882
|
switch (k) {
|
|
@@ -866,7 +890,7 @@
|
|
|
866
890
|
case 't':
|
|
867
891
|
args[func.args[k]] = t; break
|
|
868
892
|
case 'obj':
|
|
869
|
-
args[func.args[k]] =
|
|
893
|
+
args[func.args[k]] = val_arg(); break
|
|
870
894
|
case 'old':
|
|
871
895
|
var key = key_arg()
|
|
872
896
|
args[func.args[k]] = bus.cache[key] || (bus.cache[key] = {key:key})
|
|
@@ -883,35 +907,45 @@
|
|
|
883
907
|
// arr[func.args[k]] = <compute_blah(k)>
|
|
884
908
|
|
|
885
909
|
// Trigger done() or abort() by return value
|
|
886
|
-
console.assert(!(result === '
|
|
910
|
+
console.assert(!(result === 'to_get' &&
|
|
887
911
|
(result === 'done' || result === 'abort')),
|
|
888
|
-
'Returning "done" or "abort" is not allowed from
|
|
912
|
+
'Returning "done" or "abort" is not allowed from to_get handlers')
|
|
889
913
|
if (result === 'done') t.done()
|
|
890
914
|
if (result === 'abort') t.abort()
|
|
891
915
|
|
|
892
|
-
// For
|
|
893
|
-
if (
|
|
894
|
-
&& !f.loading()
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
916
|
+
// For get
|
|
917
|
+
if (func.use_linked_json) {
|
|
918
|
+
if (method === 'to_get' && result !== undefined && !f.loading()) {
|
|
919
|
+
var obj = {key: arg, val: result}
|
|
920
|
+
var new_t = clone(t || {})
|
|
921
|
+
new_t.to_get = true
|
|
922
|
+
set.fire(obj, new_t)
|
|
923
|
+
return result
|
|
924
|
+
}
|
|
925
|
+
} else {
|
|
926
|
+
if (method === 'to_get' && result instanceof Object
|
|
927
|
+
&& !f.loading() // Experimental.
|
|
928
|
+
) {
|
|
929
|
+
result.key = arg
|
|
930
|
+
var new_t = clone(t || {})
|
|
931
|
+
new_t.to_get = true
|
|
932
|
+
set.fire(result, new_t)
|
|
933
|
+
return result
|
|
934
|
+
}
|
|
901
935
|
}
|
|
902
936
|
|
|
903
|
-
//
|
|
937
|
+
// Set, forget and delete handlers stop re-running once they've
|
|
904
938
|
// completed without anything loading.
|
|
905
939
|
// ... with f.forget()
|
|
906
|
-
if (method !== '
|
|
940
|
+
if (method !== 'to_get' && !f.loading())
|
|
907
941
|
f.forget()
|
|
908
942
|
})
|
|
909
943
|
f.proxies_for = func
|
|
910
944
|
f.arg = arg
|
|
911
945
|
f.transaction = t || {}
|
|
912
946
|
|
|
913
|
-
//
|
|
914
|
-
if (method === '
|
|
947
|
+
// to_get handlers stop re-running when the key is forgotten
|
|
948
|
+
if (method === 'to_get') {
|
|
915
949
|
var key = arg
|
|
916
950
|
function handler_done () {
|
|
917
951
|
f.forget()
|
|
@@ -920,13 +954,13 @@
|
|
|
920
954
|
bind(key, 'to_forget', handler_done)
|
|
921
955
|
|
|
922
956
|
// // Check if it's doubled-up
|
|
923
|
-
// if (
|
|
924
|
-
// console.error('Two .
|
|
925
|
-
// key+'!', funk_name(funck), funk_name(
|
|
957
|
+
// if (gets_out[key])
|
|
958
|
+
// console.error('Two .to_get functions are running on the same key',
|
|
959
|
+
// key+'!', funk_name(funck), funk_name(gets_out[key]))
|
|
926
960
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
961
|
+
gets_out[key] = gets_out[key] || []
|
|
962
|
+
gets_out[key].push(f) // Record active to_get handler
|
|
963
|
+
pending_gets[key] = f // Record that the get is pending
|
|
930
964
|
}
|
|
931
965
|
|
|
932
966
|
if (just_make_it)
|
|
@@ -945,9 +979,9 @@
|
|
|
945
979
|
for (var i=0; i<handlers.length; i++)
|
|
946
980
|
bus.run_handler(handlers[i].func, method, arg, {t: t, binding: handlers[i].key})
|
|
947
981
|
|
|
948
|
-
// if (method === '
|
|
982
|
+
// if (method === 'to_get')
|
|
949
983
|
// console.assert(handlers.length<2,
|
|
950
|
-
// 'Two
|
|
984
|
+
// 'Two to_get functions are registered for the same key '+key,
|
|
951
985
|
// handlers)
|
|
952
986
|
return handlers.length
|
|
953
987
|
}
|
|
@@ -957,7 +991,7 @@
|
|
|
957
991
|
// Reactive functions
|
|
958
992
|
//
|
|
959
993
|
// We wrap any function with a reactive wrapper that re-calls it whenever
|
|
960
|
-
// state it's
|
|
994
|
+
// state it's got changes.
|
|
961
995
|
|
|
962
996
|
if (!global_funk) {
|
|
963
997
|
global_funk = reactive(function global_funk () {})
|
|
@@ -972,7 +1006,7 @@
|
|
|
972
1006
|
// f = reactive(func)
|
|
973
1007
|
// f(arg1, arg2)
|
|
974
1008
|
//
|
|
975
|
-
// This will remember every
|
|
1009
|
+
// This will remember every get it depends on, and make it re-call
|
|
976
1010
|
// itself whenever that state changes. It will remember arg1 and arg2
|
|
977
1011
|
// and use those again. You can also trigger a re-action manually
|
|
978
1012
|
// with:
|
|
@@ -1031,14 +1065,14 @@
|
|
|
1031
1065
|
|
|
1032
1066
|
funk.func = func // just for debugging
|
|
1033
1067
|
funk.called_directly = true
|
|
1034
|
-
funk.
|
|
1068
|
+
funk.getted_keys = {} // maps [bus,key] to version
|
|
1035
1069
|
// version will be undefined until loaded
|
|
1036
1070
|
funk.abortable_keys = []
|
|
1037
1071
|
funk.has_seen = function (bus, key, version) {
|
|
1038
1072
|
//console.log('depend:', bus, key, versions[key])
|
|
1039
1073
|
var bus_key = JSON.stringify([bus.id, key])
|
|
1040
1074
|
var seen_versions =
|
|
1041
|
-
this.
|
|
1075
|
+
this.getted_keys[bus_key] = this.getted_keys[bus_key] || []
|
|
1042
1076
|
seen_versions.push(version)
|
|
1043
1077
|
if (seen_versions.length > 50) seen_versions.shift()
|
|
1044
1078
|
}
|
|
@@ -1053,29 +1087,29 @@
|
|
|
1053
1087
|
return result
|
|
1054
1088
|
}
|
|
1055
1089
|
funk.forget = function () {
|
|
1056
|
-
// Todo: This will bug out if an .
|
|
1057
|
-
//
|
|
1058
|
-
// when it
|
|
1059
|
-
//
|
|
1060
|
-
// re-run, and doesn't
|
|
1061
|
-
// defined as an .
|
|
1090
|
+
// Todo: This will bug out if an .on_set handler for a key also
|
|
1091
|
+
// gets that key once, and then doesn't get it again, because
|
|
1092
|
+
// when it gets the key, that key will end up being a
|
|
1093
|
+
// getted_key, and will then be forgotten as soon as the funk is
|
|
1094
|
+
// re-run, and doesn't get it again, and the fact that it is
|
|
1095
|
+
// defined as an .on_set .on_set handler won't matter anymore.
|
|
1062
1096
|
|
|
1063
1097
|
if (funk.statebus_id === 'global funk') return
|
|
1064
1098
|
|
|
1065
|
-
for (var hash in funk.
|
|
1099
|
+
for (var hash in funk.getted_keys) {
|
|
1066
1100
|
var tmp = JSON.parse(hash),
|
|
1067
1101
|
bus = busses[tmp[0]], key = tmp[1]
|
|
1068
1102
|
if (bus) // Cause it might have been deleted
|
|
1069
1103
|
bus.forget(key, funk)
|
|
1070
1104
|
}
|
|
1071
|
-
funk.
|
|
1105
|
+
funk.getted_keys = {}
|
|
1072
1106
|
}
|
|
1073
1107
|
funk.loading = function () {
|
|
1074
|
-
for (var hash in funk.
|
|
1108
|
+
for (var hash in funk.getted_keys) {
|
|
1075
1109
|
var tmp = JSON.parse(hash),
|
|
1076
1110
|
bus = busses[tmp[0]], key = tmp[1]
|
|
1077
1111
|
if (bus // Cause it might have been deleted
|
|
1078
|
-
&& bus.
|
|
1112
|
+
&& bus.pending_gets[key])
|
|
1079
1113
|
return true
|
|
1080
1114
|
}
|
|
1081
1115
|
return false
|
|
@@ -1089,9 +1123,9 @@
|
|
|
1089
1123
|
|
|
1090
1124
|
function loading_keys (keys) {
|
|
1091
1125
|
// Do any of these keys have outstanding gets?
|
|
1092
|
-
//console.log('Loading: pending_keys is',
|
|
1126
|
+
//console.log('Loading: pending_keys is', pending_gets)
|
|
1093
1127
|
for (var i=0; i<keys.length; i++)
|
|
1094
|
-
if (
|
|
1128
|
+
if (pending_gets[keys[i]]) return true
|
|
1095
1129
|
return false
|
|
1096
1130
|
}
|
|
1097
1131
|
|
|
@@ -1125,7 +1159,8 @@
|
|
|
1125
1159
|
var red = '', normal = '', grey = '',
|
|
1126
1160
|
green = '', brown = ''
|
|
1127
1161
|
function add_diff_msg (message, obj) {
|
|
1128
|
-
var diff = sorta_diff(backup_cache[obj.key]
|
|
1162
|
+
var diff = sorta_diff(backup_cache[obj.key] && backup_cache[obj.key].val,
|
|
1163
|
+
obj && obj.val)
|
|
1129
1164
|
if (diff) {
|
|
1130
1165
|
var end_col = message.length + 2 + statelog_indent * 3
|
|
1131
1166
|
for (var i=0; i<40-end_col; i++) message += ' '
|
|
@@ -1134,7 +1169,7 @@
|
|
|
1134
1169
|
else message += ' <no diff>'
|
|
1135
1170
|
return message
|
|
1136
1171
|
}
|
|
1137
|
-
function
|
|
1172
|
+
function set_msg (obj, t, meth) {
|
|
1138
1173
|
if (!honking_at(obj.key)) return
|
|
1139
1174
|
var message = (t && t.m) || bus + "."+meth+"('"+obj.key+"')"
|
|
1140
1175
|
message = add_diff_msg(message, obj)
|
|
@@ -1152,14 +1187,14 @@
|
|
|
1152
1187
|
if (!name) throw 'Uncallback function needs a name'
|
|
1153
1188
|
var watching = {}
|
|
1154
1189
|
var prefix = 'uncallback/' + name
|
|
1155
|
-
bus(prefix + '/*').
|
|
1190
|
+
bus(prefix + '/*').to_get = function (key, json) {
|
|
1156
1191
|
var args = json
|
|
1157
1192
|
function cb (err, result) {
|
|
1158
1193
|
if (err) {
|
|
1159
1194
|
console.trace('have err:', err, 'and result is', JSON.stringify(result))
|
|
1160
1195
|
throw err
|
|
1161
1196
|
} else
|
|
1162
|
-
bus.
|
|
1197
|
+
bus.set.fire({key: key, _: result})
|
|
1163
1198
|
}
|
|
1164
1199
|
|
|
1165
1200
|
// Inject the callback into the right place
|
|
@@ -1186,7 +1221,7 @@
|
|
|
1186
1221
|
}
|
|
1187
1222
|
return function () {
|
|
1188
1223
|
var args = [].slice.call(arguments)
|
|
1189
|
-
return bus.
|
|
1224
|
+
return bus.get(prefix + '/' + JSON.stringify(args))._
|
|
1190
1225
|
}
|
|
1191
1226
|
}
|
|
1192
1227
|
|
|
@@ -1200,392 +1235,31 @@
|
|
|
1200
1235
|
}
|
|
1201
1236
|
|
|
1202
1237
|
|
|
1203
|
-
//
|
|
1204
|
-
|
|
1205
|
-
var sb = (function sb () {
|
|
1206
|
-
// I have the cache behind the scenes
|
|
1207
|
-
// Each proxy has a target object -- the raw data on cache
|
|
1208
|
-
// If we're proxying a {_: ...} singleton then ...
|
|
1209
|
-
|
|
1210
|
-
function item_proxy (base, o) {
|
|
1211
|
-
if (typeof o === 'number'
|
|
1212
|
-
|| typeof o === 'string'
|
|
1213
|
-
|| typeof o === 'boolean'
|
|
1214
|
-
|| o === undefined
|
|
1215
|
-
|| o === null
|
|
1216
|
-
|| typeof o === 'function') return o
|
|
1217
|
-
|
|
1218
|
-
return new Proxy(o, {
|
|
1219
|
-
get: function get(o, k) {
|
|
1220
|
-
if (k === 'inspect' || k === 'valueOf' || typeof k === 'symbol')
|
|
1221
|
-
return undefined
|
|
1222
|
-
k = escape_keys(k)
|
|
1223
|
-
return item_proxy(base, o[k])
|
|
1224
|
-
},
|
|
1225
|
-
set: function set(o, k, v) {
|
|
1226
|
-
var result = o[escape_keys(k)] = v
|
|
1227
|
-
bus.save(base)
|
|
1228
|
-
return result
|
|
1229
|
-
},
|
|
1230
|
-
has: function has(o, k) {
|
|
1231
|
-
return o.hasOwnProperty(escape_keys(k))
|
|
1232
|
-
},
|
|
1233
|
-
deleteProperty: function del (o, k) {
|
|
1234
|
-
delete o[escape_keys(k)]
|
|
1235
|
-
},
|
|
1236
|
-
apply: function apply (o, This, args) {
|
|
1237
|
-
return o
|
|
1238
|
-
}
|
|
1239
|
-
})}
|
|
1240
|
-
|
|
1241
|
-
return new Proxy(cache, {
|
|
1242
|
-
get: function get(o, k) {
|
|
1243
|
-
if (k in bogus_keys) return o[k]
|
|
1244
|
-
if (k === 'inspect' || k === 'valueOf' || typeof k === 'symbol')
|
|
1245
|
-
return undefined
|
|
1246
|
-
var raw = bus.fetch(k),
|
|
1247
|
-
obj = raw
|
|
1248
|
-
while (typeof obj == 'object' && '_' in obj) obj = obj._
|
|
1249
|
-
return item_proxy(raw, obj)
|
|
1250
|
-
},
|
|
1251
|
-
set: function set(o, k, v) {
|
|
1252
|
-
if (typeof v === 'number'
|
|
1253
|
-
|| typeof v === 'string'
|
|
1254
|
-
|| typeof v === 'boolean'
|
|
1255
|
-
|| v === undefined
|
|
1256
|
-
|| v === null
|
|
1257
|
-
|| typeof v === 'function'
|
|
1258
|
-
|| Array.isArray(v))
|
|
1259
|
-
v = {_:v}
|
|
1260
|
-
else
|
|
1261
|
-
v = bus.clone(v)
|
|
1262
|
-
v.key = k
|
|
1263
|
-
bus.save(v)
|
|
1264
|
-
},
|
|
1265
|
-
// In future, this might check if there's a .to_fetch function OR
|
|
1266
|
-
// something in the cache:
|
|
1267
|
-
//
|
|
1268
|
-
// has: function has(o, k) {
|
|
1269
|
-
// return k in o
|
|
1270
|
-
// },
|
|
1271
|
-
// ... but I haven't had a need yet.
|
|
1272
|
-
deleteProperty: function del (o, k) {
|
|
1273
|
-
bus.delete(escape_keys(k))
|
|
1274
|
-
}
|
|
1275
|
-
})
|
|
1276
|
-
})()
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
// ******** State (Proxy) API *********
|
|
1280
|
-
//
|
|
1281
|
-
// The top-level state[..] object translates pointers of the
|
|
1282
|
-
// special form:
|
|
1283
|
-
//
|
|
1284
|
-
// {key: <s>, _: *}
|
|
1285
|
-
//
|
|
1286
|
-
// Examples:
|
|
1287
|
-
//
|
|
1288
|
-
// state['uninitialized']
|
|
1289
|
-
// >> undefined
|
|
1290
|
-
//
|
|
1291
|
-
// state['uninitialized'] = {}
|
|
1292
|
-
// >> {key: 'uninitialized'}
|
|
1293
|
-
//
|
|
1294
|
-
// state['uninitialized'] = {a: 3}
|
|
1295
|
-
// >> {key: 'uninitialized', a: 3}
|
|
1296
|
-
//
|
|
1297
|
-
// state['uninitialized'] = []
|
|
1298
|
-
// >> {key: 'uninitialized', _: []}
|
|
1299
|
-
//
|
|
1300
|
-
// delete state['uninitialized']
|
|
1301
|
-
// state['uninitialized']
|
|
1302
|
-
// >> undefined
|
|
1303
|
-
//
|
|
1304
|
-
// ** Rules
|
|
1305
|
-
// Setting:
|
|
1306
|
-
// - Escape-translate each field recursively
|
|
1307
|
-
// - If setting an object, put each field directly on it
|
|
1308
|
-
// - If setting anything else, put it into ._
|
|
1309
|
-
//
|
|
1310
|
-
// Getting:
|
|
1311
|
-
// - If it has unescaped fields other than ._, return object with them
|
|
1312
|
-
// - Otherwise, return ._
|
|
1313
|
-
// - Unescape all fields
|
|
1314
|
-
|
|
1315
|
-
var strict_mode = (function () {return !this})()
|
|
1316
|
-
function pget (base, o, k) {
|
|
1317
|
-
// console.log('pget:', {base, o, k})
|
|
1318
|
-
|
|
1319
|
-
if (base) {
|
|
1320
|
-
o = o[k]
|
|
1321
|
-
|
|
1322
|
-
// If new base, update and subscribe
|
|
1323
|
-
if (typeof o == 'object' && 'key' in o) {
|
|
1324
|
-
base = o
|
|
1325
|
-
bus.fetch(o.key)
|
|
1326
|
-
}
|
|
1327
|
-
} else {
|
|
1328
|
-
// We are getting from the Root
|
|
1329
|
-
o = bus.fetch(k)
|
|
1330
|
-
// console.log('pget: fetched', k, 'and got', o)
|
|
1331
|
-
base = o
|
|
1332
|
-
if (bus.validate(o, {key: '*', '?_': '*'})) {
|
|
1333
|
-
// console.log('pget: jumping into the _')
|
|
1334
|
-
o = o._
|
|
1335
|
-
}
|
|
1336
|
-
if (typeof o === 'object' && o.key)
|
|
1337
|
-
base = o
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
// Follow symlinks
|
|
1341
|
-
if (typeof o == 'object' && 'key' in o && '_' in o) {
|
|
1342
|
-
// Note: I don't actually need this recursion here, because
|
|
1343
|
-
// recursively linked state cannot be created by the proxy API.
|
|
1344
|
-
// So it can be undefined behavior.
|
|
1345
|
-
var tmp = pget(base, o, '_')
|
|
1346
|
-
base = tmp[0]
|
|
1347
|
-
o = tmp[1]
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
return [base, o]
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
function proxy_encode_val (x) {
|
|
1354
|
-
// Arrays
|
|
1355
|
-
if (Array.isArray(x)) {
|
|
1356
|
-
var result = []
|
|
1357
|
-
for (var i=0; i < x.length; i++)
|
|
1358
|
-
result[i] = proxy_encode_val(x[i])
|
|
1359
|
-
return result
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
// Objects
|
|
1363
|
-
else if (typeof x === 'object') {
|
|
1364
|
-
// Actual objects need their keys translated
|
|
1365
|
-
var result = {}
|
|
1366
|
-
for (var k in x)
|
|
1367
|
-
result[escape_keys(k)] = proxy_encode_val(x[k])
|
|
1368
|
-
return result
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
// Proxieds: already have JSON, stored inside. Return it.
|
|
1372
|
-
else if (typeof x === 'function' && x[symbols.is_proxy]) {
|
|
1373
|
-
return x()
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
|
-
// Everything else return
|
|
1377
|
-
return x
|
|
1378
|
-
}
|
|
1379
|
-
function proxy_decode_json (json) {
|
|
1380
|
-
// Returns data for proxies
|
|
1381
|
-
// - Remove keys
|
|
1382
|
-
// - Translate
|
|
1383
|
-
|
|
1384
|
-
// Root objects of special form
|
|
1385
|
-
if (bus.validate(json, {key: '*', '_': '*'}))
|
|
1386
|
-
return proxy_decode_json(json._)
|
|
1387
|
-
|
|
1388
|
-
// Arrays
|
|
1389
|
-
if (Array.isArray(json)) {
|
|
1390
|
-
var arr = json.slice()
|
|
1391
|
-
for (var i=0; i<arr.length; i++)
|
|
1392
|
-
arr[i] = proxy_decode_json(arr[i])
|
|
1393
|
-
return arr
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
// Objects
|
|
1397
|
-
if (typeof json === 'object' && json !== null) {
|
|
1398
|
-
var obj = {}
|
|
1399
|
-
for (var k in json)
|
|
1400
|
-
if (k !== 'key')
|
|
1401
|
-
obj[unescape_keys(k)] = proxy_decode_json(json[k])
|
|
1402
|
-
return obj
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
// Other primitives just return
|
|
1406
|
-
return json
|
|
1407
|
-
}
|
|
1408
|
-
|
|
1409
|
-
if (nodejs) var util = require('util')
|
|
1410
|
-
function make_proxy (base, o) {
|
|
1411
|
-
if (!symbols)
|
|
1412
|
-
symbols = {is_proxy: Symbol('is_proxy'),
|
|
1413
|
-
get_json: Symbol('get_json'),
|
|
1414
|
-
get_base: Symbol('get_base')}
|
|
1415
|
-
|
|
1416
|
-
if (typeof o !== 'object' || o === null) return o
|
|
1417
|
-
|
|
1418
|
-
function get_json() {
|
|
1419
|
-
// Pop up to parent if this is a singleton array.
|
|
1420
|
-
// We know it's a singleton array if base._ === x(), and base is
|
|
1421
|
-
// of the form {key: *, _: x}
|
|
1422
|
-
if (base && base._ && Object.keys(base).length === 2
|
|
1423
|
-
&& base._ === o)
|
|
1424
|
-
return base
|
|
1425
|
-
|
|
1426
|
-
// Otherwise return x's JSON.
|
|
1427
|
-
return o
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
// Javascript won't let us function call a proxy unless the "target"
|
|
1431
|
-
// is a function. So we make a dummy target, and don't use it.
|
|
1432
|
-
var dummy_obj = function () {}
|
|
1433
|
-
return new Proxy(dummy_obj, {
|
|
1434
|
-
get: function (dummy_obj, k) {
|
|
1435
|
-
// console.log('get:', k, '::'+typeof k, 'on', o)
|
|
1436
|
-
|
|
1437
|
-
// Print something nice for Node console inspector
|
|
1438
|
-
if (nodejs && k === util.inspect.custom) {
|
|
1439
|
-
if (o == bus.cache)
|
|
1440
|
-
return function () {return 'state'+bus.toString().substr(3)}
|
|
1441
|
-
return function () {return 'p: '+util.format(proxy_decode_json(o))}
|
|
1442
|
-
}
|
|
1443
|
-
if (k in bogus_keys) return o[k]
|
|
1444
|
-
// Proxies distinguish themselves via proxy.is_proxy == true
|
|
1445
|
-
if (k === symbols.is_proxy) return true
|
|
1446
|
-
if (k === symbols.get_json) return get_json()
|
|
1447
|
-
if (k === symbols.get_base) return base
|
|
1448
|
-
if (k === Symbol.isConcatSpreadable) return Array.isArray(o)
|
|
1449
|
-
if (k === Symbol.toPrimitive) return function () {
|
|
1450
|
-
return JSON.stringify(proxy_decode_json(o))
|
|
1451
|
-
}
|
|
1452
|
-
if (typeof k === 'symbol') {
|
|
1453
|
-
console.warn('Got request for weird symbol', k)
|
|
1454
|
-
return undefined
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
var tmp2 = pget(base, o, escape_keys(k))
|
|
1458
|
-
var base2 = tmp2[0]
|
|
1459
|
-
var o2 = tmp2[1]
|
|
1460
|
-
|
|
1461
|
-
// console.log('returning proxy on', base2, o2)
|
|
1462
|
-
return make_proxy(base2, o2)
|
|
1463
|
-
},
|
|
1464
|
-
set: function (dummy_obj, k, v) {
|
|
1465
|
-
// console.log('set:', {base, o, k, v})
|
|
1466
|
-
|
|
1467
|
-
if (base) {
|
|
1468
|
-
var encoded_v = o[escape_keys(k)] = proxy_encode_val(v)
|
|
1469
|
-
// console.log(' set: saving', encoded_v, 'into', base)
|
|
1470
|
-
|
|
1471
|
-
// Collapse state of the form:
|
|
1472
|
-
// {key: '*', _: {foo: bar, ...}}
|
|
1473
|
-
// down to:
|
|
1474
|
-
// {key: '*', foo: bar}
|
|
1475
|
-
if (base._
|
|
1476
|
-
&& Object.keys(base).length === 2
|
|
1477
|
-
&& typeof base._ === 'object'
|
|
1478
|
-
&& base._ !== null
|
|
1479
|
-
&& !Array.isArray(base._)
|
|
1480
|
-
&& !base._.key
|
|
1481
|
-
&& Object.keys(base._).length !== 0) {
|
|
1482
|
-
// console.log('Collapsing', JSON.stringify(base))
|
|
1483
|
-
for (var k2 in base._)
|
|
1484
|
-
base[k2] = base._[k2]
|
|
1485
|
-
delete base._
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
bus.save(base)
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
// Saving into top-level state
|
|
1492
|
-
else {
|
|
1493
|
-
var encoded_v = proxy_encode_val(v)
|
|
1494
|
-
// console.log(' set top-level:', {v, encoded_v})
|
|
1495
|
-
|
|
1496
|
-
// Setting a top-level object to undefined wipes it out
|
|
1497
|
-
if (v === undefined)
|
|
1498
|
-
encoded_v = {key: k}
|
|
1499
|
-
|
|
1500
|
-
// Prefix with _: anything that is:
|
|
1501
|
-
else if (// A proxy to another state
|
|
1502
|
-
(typeof v === 'object' && v[symbols.is_proxy])
|
|
1503
|
-
// An empty {} object
|
|
1504
|
-
|| (typeof v === 'object' && Object.keys(v).length === 0)
|
|
1505
|
-
// A number, bool, string, function, etc
|
|
1506
|
-
|| typeof v !== 'object' || v === null
|
|
1507
|
-
// An array
|
|
1508
|
-
|| Array.isArray(v))
|
|
1509
|
-
encoded_v = {_: encoded_v}
|
|
1510
|
-
encoded_v.key = k
|
|
1511
|
-
|
|
1512
|
-
// console.log(' set top-level: now encoded_v is', encoded_v)
|
|
1513
|
-
bus.save(encoded_v)
|
|
1514
|
-
}
|
|
1238
|
+
// ******************
|
|
1239
|
+
// Proxy
|
|
1515
1240
|
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
//
|
|
1522
|
-
// - Do I want this to return true if there's a .to_fetch()
|
|
1523
|
-
// function for this o, k?
|
|
1524
|
-
//
|
|
1525
|
-
// - Does this need to do a fetch as well?
|
|
1526
|
-
//
|
|
1527
|
-
// - For a keyed object, should this do a loading() check?
|
|
1528
|
-
return o.hasOwnProperty(escape_keys(k))
|
|
1529
|
-
},
|
|
1530
|
-
deleteProperty: function del (O, k) {
|
|
1531
|
-
if (base) {
|
|
1532
|
-
// console.log(' deleting:', escape_keys(k), 'of', o)
|
|
1533
|
-
delete o[escape_keys(k)] // Deleting innards
|
|
1534
|
-
if (Object.keys(o).length === 1 && o.key)
|
|
1535
|
-
o._ = {}
|
|
1536
|
-
bus.save(base)
|
|
1537
|
-
}
|
|
1538
|
-
else
|
|
1539
|
-
bus.delete(escape_keys(k)) // Deleting top-level
|
|
1540
|
-
},
|
|
1541
|
-
apply: function apply (f, This, args) { return get_json() }
|
|
1542
|
-
})
|
|
1543
|
-
}
|
|
1544
|
-
if (nodejs || window.Proxy)
|
|
1545
|
-
var state = make_proxy(null, cache)
|
|
1546
|
-
|
|
1547
|
-
// So chrome can print out proxy objects decently
|
|
1548
|
-
if (!nodejs)
|
|
1549
|
-
window.devtoolsFormatters = [{
|
|
1550
|
-
header: function (x) {
|
|
1551
|
-
if (x[symbols.is_proxy])
|
|
1552
|
-
return ['span', {style: 'background-color: #feb; padding: 3px;'},
|
|
1553
|
-
JSON.stringify(proxy_decode_json(x()))]
|
|
1554
|
-
else if (x[symbols.is_braid_proxy])
|
|
1555
|
-
return ['span', {style: 'background-color: #fffbe5; padding: 3px;'},
|
|
1556
|
-
JSON.stringify(x)]
|
|
1557
|
-
// For function proxies:
|
|
1558
|
-
// JSON.stringify(x(), null, 2)]
|
|
1559
|
-
},
|
|
1560
|
-
hasBody: function (x) {return false}
|
|
1561
|
-
}]
|
|
1241
|
+
var symbols = {
|
|
1242
|
+
is_proxy: Symbol('is_proxy'),
|
|
1243
|
+
is_link: Symbol('is_link'),
|
|
1244
|
+
get_json: Symbol('get_json'),
|
|
1245
|
+
get_base: Symbol('get_base')
|
|
1562
1246
|
}
|
|
1563
|
-
|
|
1564
|
-
// ******************
|
|
1565
|
-
// Braid Test Mode Proxy
|
|
1566
|
-
|
|
1567
|
-
var symbols = {is_braid_proxy: Symbol('is_braid_proxy'),
|
|
1568
|
-
is_proxy: Symbol('is_proxy'),
|
|
1569
|
-
is_link: Symbol('is_link'),
|
|
1570
|
-
get_json: Symbol('get_json'),
|
|
1571
|
-
get_base: Symbol('get_base')
|
|
1572
|
-
}
|
|
1573
|
-
function braid_proxy () {
|
|
1247
|
+
function make_proxy () {
|
|
1574
1248
|
function item_proxy (base, o) {
|
|
1575
1249
|
|
|
1576
|
-
//
|
|
1250
|
+
// Primitives pass through unscathed
|
|
1577
1251
|
if (typeof o === 'number'
|
|
1578
1252
|
|| typeof o === 'string'
|
|
1579
1253
|
|| typeof o === 'boolean'
|
|
1580
1254
|
|| o === undefined
|
|
1581
1255
|
|| o === null
|
|
1582
1256
|
|| typeof o === 'function')
|
|
1583
|
-
|
|
1257
|
+
|
|
1584
1258
|
return o
|
|
1585
1259
|
|
|
1586
1260
|
// We recursively descend through {key: ...} links
|
|
1587
1261
|
if (typeof o === 'object' && 'key' in o) {
|
|
1588
|
-
var new_base = bus.
|
|
1262
|
+
var new_base = bus.get(o.key)
|
|
1589
1263
|
return item_proxy(new_base, new_base.val)
|
|
1590
1264
|
}
|
|
1591
1265
|
|
|
@@ -1602,7 +1276,7 @@
|
|
|
1602
1276
|
get: function get(o, k) {
|
|
1603
1277
|
if (k === 'inspect' || k === 'valueOf')
|
|
1604
1278
|
return undefined
|
|
1605
|
-
if (k === symbols.
|
|
1279
|
+
if (k === symbols.is_proxy)
|
|
1606
1280
|
return true
|
|
1607
1281
|
if (typeof k === 'symbol')
|
|
1608
1282
|
return undefined
|
|
@@ -1611,7 +1285,7 @@
|
|
|
1611
1285
|
set: function set(o, k, v) {
|
|
1612
1286
|
var value = translate_fields(v, proxied_2_keyed)
|
|
1613
1287
|
o[proxied_2_keyed(k)] = value
|
|
1614
|
-
bus.
|
|
1288
|
+
bus.set(base)
|
|
1615
1289
|
return true
|
|
1616
1290
|
},
|
|
1617
1291
|
has: function has(o, k) {
|
|
@@ -1637,11 +1311,11 @@
|
|
|
1637
1311
|
if (k === 'inspect' || k === 'valueOf' || typeof k === 'symbol')
|
|
1638
1312
|
return undefined
|
|
1639
1313
|
bogus_check(k)
|
|
1640
|
-
var base = bus.
|
|
1314
|
+
var base = bus.get(k)
|
|
1641
1315
|
return item_proxy(base, base.val)
|
|
1642
1316
|
},
|
|
1643
1317
|
set: function set(o, key, val) {
|
|
1644
|
-
bus.
|
|
1318
|
+
bus.set({key: key,
|
|
1645
1319
|
val: translate_fields(val, proxied_2_keyed)})
|
|
1646
1320
|
return true
|
|
1647
1321
|
},
|
|
@@ -1654,17 +1328,27 @@
|
|
|
1654
1328
|
// }
|
|
1655
1329
|
})
|
|
1656
1330
|
}
|
|
1331
|
+
bus.state = make_proxy()
|
|
1657
1332
|
|
|
1658
1333
|
function link (url) {
|
|
1659
|
-
var result =
|
|
1334
|
+
var result = bus.get(url)
|
|
1660
1335
|
result[symbols.is_link] = true
|
|
1661
1336
|
return result
|
|
1662
1337
|
}
|
|
1663
1338
|
|
|
1664
|
-
if ((nodejs && bus.options && bus.options.braid_mode)
|
|
1665
|
-
|| (!nodejs && window.Proxy && clientjs_option('braid_mode')))
|
|
1666
|
-
state = braid_proxy()
|
|
1667
1339
|
|
|
1340
|
+
// So chrome can print out proxy objects decently
|
|
1341
|
+
if (!nodejs)
|
|
1342
|
+
window.devtoolsFormatters = [{
|
|
1343
|
+
header: function (x) {
|
|
1344
|
+
if (x[symbols.is_proxy])
|
|
1345
|
+
return ['span', {style: 'background-color: #fffbe5; padding: 3px;'},
|
|
1346
|
+
JSON.stringify(x)]
|
|
1347
|
+
// For function proxies:
|
|
1348
|
+
// JSON.stringify(x(), null, 2)]
|
|
1349
|
+
},
|
|
1350
|
+
hasBody: function (x) {return false}
|
|
1351
|
+
}]
|
|
1668
1352
|
|
|
1669
1353
|
// ******************
|
|
1670
1354
|
// Network client
|
|
@@ -1673,13 +1357,13 @@
|
|
|
1673
1357
|
return m && m[0]
|
|
1674
1358
|
}
|
|
1675
1359
|
function message_method (m) {
|
|
1676
|
-
return (m.
|
|
1677
|
-
|| (m.
|
|
1360
|
+
return (m.get && 'get')
|
|
1361
|
+
|| (m.set && 'set')
|
|
1678
1362
|
|| (m['delete'] && 'delete')
|
|
1679
1363
|
|| (m.forget && 'forget')
|
|
1680
1364
|
}
|
|
1681
1365
|
|
|
1682
|
-
function
|
|
1366
|
+
function ws_mount (prefix, url, client_creds) {
|
|
1683
1367
|
// Local: state://foo.com/* or /*
|
|
1684
1368
|
var preprefix = prefix.slice(0,-1)
|
|
1685
1369
|
var is_absolute = /^i?statei?:\/\//
|
|
@@ -1688,7 +1372,7 @@
|
|
|
1688
1372
|
var sock
|
|
1689
1373
|
var attempts = 0
|
|
1690
1374
|
var outbox = []
|
|
1691
|
-
var
|
|
1375
|
+
var client_getted_keys = new bus.Set()
|
|
1692
1376
|
var heartbeat
|
|
1693
1377
|
if (url[url.length-1]=='/') url = url.substr(0,url.length-1)
|
|
1694
1378
|
function nlog (s) {
|
|
@@ -1698,9 +1382,9 @@
|
|
|
1698
1382
|
pushpop = pushpop || 'push'
|
|
1699
1383
|
o = rem_prefixes(o)
|
|
1700
1384
|
var m = message_method(o)
|
|
1701
|
-
if (m == '
|
|
1385
|
+
if (m == 'get' || m == 'delete' || m == 'forget')
|
|
1702
1386
|
o[m] = rem_prefix(o[m])
|
|
1703
|
-
bus.log('
|
|
1387
|
+
bus.log('ws_mount.send:', JSON.stringify(o))
|
|
1704
1388
|
outbox[pushpop](JSON.stringify(o))
|
|
1705
1389
|
flush_outbox()
|
|
1706
1390
|
}
|
|
@@ -1729,19 +1413,19 @@
|
|
|
1729
1413
|
function rem_prefixes (obj) {
|
|
1730
1414
|
return bus.translate_keys(bus.clone(obj), rem_prefix) }
|
|
1731
1415
|
|
|
1732
|
-
bus(prefix).
|
|
1733
|
-
bus.
|
|
1734
|
-
var x = {
|
|
1416
|
+
bus(prefix).to_set = function (obj, t) {
|
|
1417
|
+
bus.set.fire(obj)
|
|
1418
|
+
var x = {set: obj}
|
|
1735
1419
|
if (t.version) x.version = t.version
|
|
1736
1420
|
if (t.parents) x.parents = t.parents
|
|
1737
1421
|
if (t.patch) x.patch = t.patch
|
|
1738
|
-
if (t.patch) x.
|
|
1422
|
+
if (t.patch) x.set = rem_prefix(x.set.key)
|
|
1739
1423
|
send(x)
|
|
1740
1424
|
}
|
|
1741
|
-
bus(prefix).
|
|
1742
|
-
|
|
1425
|
+
bus(prefix).to_get = function (key) { send({get: key}),
|
|
1426
|
+
client_getted_keys.add(key) }
|
|
1743
1427
|
bus(prefix).to_forget = function (key) { send({forget: key}),
|
|
1744
|
-
|
|
1428
|
+
client_getted_keys.delete(key) }
|
|
1745
1429
|
bus(prefix).to_delete = function (key) { send({'delete': key}) }
|
|
1746
1430
|
|
|
1747
1431
|
function connect () {
|
|
@@ -1751,16 +1435,16 @@
|
|
|
1751
1435
|
nlog('[*] opened ' + url)
|
|
1752
1436
|
|
|
1753
1437
|
// Update state
|
|
1754
|
-
var peers = bus.
|
|
1438
|
+
var peers = bus.get('peers')
|
|
1755
1439
|
peers[url] = peers[url] || {}
|
|
1756
1440
|
peers[url].connected = true
|
|
1757
|
-
|
|
1441
|
+
set(peers)
|
|
1758
1442
|
|
|
1759
1443
|
// Login
|
|
1760
1444
|
var creds = client_creds || (bus.client_creds && bus.client_creds(url))
|
|
1761
1445
|
if (creds) {
|
|
1762
1446
|
var i = []
|
|
1763
|
-
function intro (o) {i.push(JSON.stringify({
|
|
1447
|
+
function intro (o) {i.push(JSON.stringify({set: o}))}
|
|
1764
1448
|
if (creds.clientid)
|
|
1765
1449
|
intro({key: 'current_user', client: creds.clientid})
|
|
1766
1450
|
if (creds.name && creds.pass)
|
|
@@ -1779,11 +1463,11 @@
|
|
|
1779
1463
|
|
|
1780
1464
|
// Reconnect
|
|
1781
1465
|
if (attempts > 0) {
|
|
1782
|
-
// Then we need to
|
|
1466
|
+
// Then we need to reget everything, cause it
|
|
1783
1467
|
// might have changed
|
|
1784
|
-
var keys =
|
|
1468
|
+
var keys = client_getted_keys.values()
|
|
1785
1469
|
for (var i=0; i<keys.length; i++)
|
|
1786
|
-
send({
|
|
1470
|
+
send({get: keys[i]})
|
|
1787
1471
|
}
|
|
1788
1472
|
|
|
1789
1473
|
attempts = 0
|
|
@@ -1799,14 +1483,14 @@
|
|
|
1799
1483
|
setTimeout(connect, attempts++ < 3 ? 1500 : 5000)
|
|
1800
1484
|
|
|
1801
1485
|
// Update state
|
|
1802
|
-
var peers = bus.
|
|
1486
|
+
var peers = bus.get('peers')
|
|
1803
1487
|
peers[url] = peers[url] || {}
|
|
1804
1488
|
peers[url].connected = false
|
|
1805
|
-
|
|
1489
|
+
set(peers)
|
|
1806
1490
|
|
|
1807
|
-
// Remove all
|
|
1491
|
+
// Remove all gets and forgets from queue
|
|
1808
1492
|
var new_outbox = []
|
|
1809
|
-
var bad = {'
|
|
1493
|
+
var bad = {'get':1, 'forget':1}
|
|
1810
1494
|
for (var i=0; i<outbox.length; i++)
|
|
1811
1495
|
if (!bad[JSON.parse(outbox[i]).method])
|
|
1812
1496
|
new_outbox.push(outbox[i])
|
|
@@ -1828,18 +1512,18 @@
|
|
|
1828
1512
|
var message = JSON.parse(event.data)
|
|
1829
1513
|
var method = message_method(message)
|
|
1830
1514
|
|
|
1831
|
-
// We only take
|
|
1832
|
-
if (method !== '
|
|
1515
|
+
// We only take sets from the server for now
|
|
1516
|
+
if (method !== 'set' && method !== 'pong') throw 'barf'
|
|
1833
1517
|
bus.log('net client received', message)
|
|
1834
1518
|
var t = {version: message.version,
|
|
1835
1519
|
parents: message.parents,
|
|
1836
1520
|
patch: message.patch}
|
|
1837
1521
|
if (t.patch)
|
|
1838
|
-
msg.
|
|
1522
|
+
msg.set = apply_patch(bus.cache[msg.set] || {key: msg.set},
|
|
1839
1523
|
message.patch[0])
|
|
1840
1524
|
if (!(t.version||t.parents||t.patch))
|
|
1841
1525
|
t = undefined
|
|
1842
|
-
bus.
|
|
1526
|
+
bus.set.fire(add_prefixes(message.set), t)
|
|
1843
1527
|
} catch (err) {
|
|
1844
1528
|
console.error('Received bad network message from '
|
|
1845
1529
|
+url+': ', event.data, err)
|
|
@@ -1863,7 +1547,7 @@
|
|
|
1863
1547
|
bus.route = function (key, method, arg, t) {
|
|
1864
1548
|
var d = get_domain(key)
|
|
1865
1549
|
if (d && !connections[d]) {
|
|
1866
|
-
bus.
|
|
1550
|
+
bus.ws_mount(d + '/*', d)
|
|
1867
1551
|
connections[d] = true
|
|
1868
1552
|
}
|
|
1869
1553
|
|
|
@@ -2212,8 +1896,8 @@
|
|
|
2212
1896
|
}
|
|
2213
1897
|
|
|
2214
1898
|
// This prune() function is a temporary workaround for dealing with nested
|
|
2215
|
-
// objects in
|
|
2216
|
-
// now, it calls .
|
|
1899
|
+
// objects in set() handlers, until we change statebus' behavior. Right
|
|
1900
|
+
// now, it calls .to_set only on the top-level state. But if that state
|
|
2217
1901
|
// validates, it calls fire() on *every* level of state. This means that
|
|
2218
1902
|
// state changes can sneak inside. Prune() will take out any changes from
|
|
2219
1903
|
// the nested levels of state in a new object -- replacing them with the
|
|
@@ -2230,7 +1914,7 @@
|
|
|
2230
1914
|
// Recurse through each property on objects
|
|
2231
1915
|
else if (typeof(o) === 'object')
|
|
2232
1916
|
if (o !== null && o.key)
|
|
2233
|
-
return bus.
|
|
1917
|
+
return bus.get(o.key)
|
|
2234
1918
|
else
|
|
2235
1919
|
for (var k in o)
|
|
2236
1920
|
o[k] = recurse(o[k])
|
|
@@ -2336,8 +2020,8 @@
|
|
|
2336
2020
|
switch (def.as) {
|
|
2337
2021
|
case 'handler':
|
|
2338
2022
|
return def.bus+"('"+def.key+"')."+def.method+' = '+f_string
|
|
2339
|
-
case '
|
|
2340
|
-
return '
|
|
2023
|
+
case 'get callback':
|
|
2024
|
+
return 'get('+def.key+', '+f_string+')'
|
|
2341
2025
|
case 'reactive':
|
|
2342
2026
|
return "reactive('"+f_string+"')"
|
|
2343
2027
|
default:
|
|
@@ -2348,7 +2032,7 @@
|
|
|
2348
2032
|
function deps (key) {
|
|
2349
2033
|
// First print out everything waiting for it to pub
|
|
2350
2034
|
var result = 'Deps: ('+key+') fires into:'
|
|
2351
|
-
var pubbers = bindings(key, '
|
|
2035
|
+
var pubbers = bindings(key, 'on_set')
|
|
2352
2036
|
if (pubbers.length === 0) result += ' nothing'
|
|
2353
2037
|
for (var i=0; i<pubbers.length; i++)
|
|
2354
2038
|
result += '\n ' + funk_name(pubbers[i].func)
|
|
@@ -2392,16 +2076,16 @@
|
|
|
2392
2076
|
}
|
|
2393
2077
|
|
|
2394
2078
|
// Make these private methods accessible
|
|
2395
|
-
var api = ['cache backup_cache
|
|
2079
|
+
var api = ['cache backup_cache get set forget del fire dirty get_once',
|
|
2396
2080
|
'subspace bindings run_handler bind unbind reactive uncallback',
|
|
2397
2081
|
'versions new_version',
|
|
2398
|
-
'
|
|
2082
|
+
'link',
|
|
2399
2083
|
'funk_key funk_name funks key_id key_name id',
|
|
2400
|
-
'
|
|
2084
|
+
'pending_gets gets_in gets_out loading_keys loading once',
|
|
2401
2085
|
'global_funk busses rerunnable_funks',
|
|
2402
2086
|
'escape_keys unescape_keys translate_keys apply_patch',
|
|
2403
2087
|
'keyed_2_proxied proxied_2_keyed translate_fields',
|
|
2404
|
-
'
|
|
2088
|
+
'ws_mount net_automount message_method',
|
|
2405
2089
|
'parse Set One_To_Many clone extend deep_map deep_equals prune validate sorta_diff log deps symbols'
|
|
2406
2090
|
].join(' ').split(' ')
|
|
2407
2091
|
for (var i=0; i<api.length; i++)
|
|
@@ -2419,27 +2103,20 @@
|
|
|
2419
2103
|
document.querySelector('script[src^="client"][src$=".js"]'))
|
|
2420
2104
|
return script_elem && script_elem.getAttribute(option_name)
|
|
2421
2105
|
}
|
|
2422
|
-
if (nodejs || clientjs_option('globals') !== 'false') {
|
|
2423
|
-
var globals = ['loading', 'clone', 'forget']
|
|
2424
|
-
var client_globals = ['fetch', 'save', 'del', 'state']
|
|
2425
|
-
if (!nodejs && Object.keys(busses).length == 0)
|
|
2426
|
-
globals = globals.concat(client_globals)
|
|
2427
|
-
|
|
2428
|
-
this.og_fetch = this.fetch // Cause fetch() is actually a browser API now
|
|
2429
|
-
for (var i=0; i<globals.length; i++)
|
|
2430
|
-
this[globals[i]] = eval(globals[i])
|
|
2431
|
-
}
|
|
2432
2106
|
|
|
2433
2107
|
busses[bus.id] = bus
|
|
2108
|
+
var this_bus_num = bus_count++
|
|
2109
|
+
|
|
2110
|
+
bus.libs = {}
|
|
2434
2111
|
|
|
2435
2112
|
if (nodejs)
|
|
2436
|
-
require('./
|
|
2113
|
+
require('./servers').import_server(bus, options)
|
|
2437
2114
|
|
|
2438
2115
|
bus.render_when_loading = true
|
|
2439
2116
|
return bus
|
|
2440
2117
|
}
|
|
2441
2118
|
|
|
2442
|
-
if (nodejs) require('./
|
|
2119
|
+
if (nodejs) require('./servers').import_module(make_bus)
|
|
2443
2120
|
|
|
2444
2121
|
return make_bus
|
|
2445
2122
|
}))
|