statebus 7.0.4 → 7.0.7
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/{clients.js → client-library.js} +256 -127
- package/extras/coffee.js +12 -0
- package/extras/sockjs.js +27 -0
- package/extras/tests.js +58 -58
- package/package.json +6 -4
- package/{servers.js → server-library.js} +134 -97
- package/statebus.js +86 -59
package/statebus.js
CHANGED
|
@@ -51,9 +51,9 @@
|
|
|
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
|
|
54
|
+
var getterters = 0
|
|
55
55
|
if (!gets_out[key])
|
|
56
|
-
|
|
56
|
+
getterters = bus.route(key, 'getter', key)
|
|
57
57
|
|
|
58
58
|
// Now there might be a new value pubbed onto this bus.
|
|
59
59
|
// Or there might be a pending get.
|
|
@@ -71,9 +71,9 @@
|
|
|
71
71
|
|
|
72
72
|
// Otherwise, we want to make sure that a pub gets called on the
|
|
73
73
|
// handler. If there's a pending get, then it'll get called later.
|
|
74
|
-
// If there was a
|
|
74
|
+
// If there was a getter, then it already got called. Otherwise,
|
|
75
75
|
// let's call it now.
|
|
76
|
-
else if (!pending_gets[key] &&
|
|
76
|
+
else if (!pending_gets[key] && getterters === 0) {
|
|
77
77
|
// TODO: my intuition suggests that we might prefer to delay this
|
|
78
78
|
// .on_set getting called in a setTimeout(f,0), to be consistent
|
|
79
79
|
// with other calls to .on_set.
|
|
@@ -130,8 +130,8 @@
|
|
|
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 setter() handlers!
|
|
134
|
+
var num_handlers = bus.route(obj.key, 'setter', obj, t)
|
|
135
135
|
if (num_handlers === 0) {
|
|
136
136
|
// And fire if there weren't any!
|
|
137
137
|
set.fire(obj, t)
|
|
@@ -143,7 +143,7 @@
|
|
|
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 setter handler that
|
|
147
147
|
// is shadowed by other handlers if I can get later handlers to shadow
|
|
148
148
|
// earlier ones.
|
|
149
149
|
}
|
|
@@ -191,7 +191,7 @@
|
|
|
191
191
|
if (obj.key && !changed(obj)) {
|
|
192
192
|
color = grey
|
|
193
193
|
icon = 'x'
|
|
194
|
-
if (t.
|
|
194
|
+
if (t.getter)
|
|
195
195
|
message = (t.m) || 'Got ' + bus + "('"+obj.key+"')"
|
|
196
196
|
if (t.version) message += ' [' + t.version + ']'
|
|
197
197
|
statelog(obj.key, color, icon, message)
|
|
@@ -199,7 +199,7 @@
|
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
color = red, icon = '•'
|
|
202
|
-
if (t.
|
|
202
|
+
if (t.getter || pending_gets[obj.key]) {
|
|
203
203
|
color = green
|
|
204
204
|
icon = '^'
|
|
205
205
|
message = add_diff_msg((t.m)||'Got '+bus+"('"+obj.key+"')",
|
|
@@ -409,7 +409,7 @@
|
|
|
409
409
|
clearTimeout(to_be_forgotten[key])
|
|
410
410
|
to_be_forgotten[key] = setTimeout(function () {
|
|
411
411
|
// Send a forget upstream
|
|
412
|
-
bus.route(key, '
|
|
412
|
+
bus.route(key, 'forgetter', key, t)
|
|
413
413
|
|
|
414
414
|
// Delete the cache entry...?
|
|
415
415
|
// delete cache[key]
|
|
@@ -429,11 +429,13 @@
|
|
|
429
429
|
}
|
|
430
430
|
|
|
431
431
|
statelog(key, yellow, 'v', 'Deleting ' + key)
|
|
432
|
-
// Call the
|
|
433
|
-
var handlers_called = bus.route(key, '
|
|
434
|
-
if (handlers_called === 0)
|
|
432
|
+
// Call the deleter handlers
|
|
433
|
+
var handlers_called = bus.route(key, 'deleter', key)
|
|
434
|
+
if (handlers_called === 0) {
|
|
435
435
|
// And go ahead and delete if there aren't any!
|
|
436
436
|
delete cache[key]
|
|
437
|
+
delete backup_cache[key]
|
|
438
|
+
}
|
|
437
439
|
|
|
438
440
|
// Call the on_delete handlers
|
|
439
441
|
bus.route(key, 'on_delete', cache[key] || {key: key}, t)
|
|
@@ -445,11 +447,11 @@
|
|
|
445
447
|
// - Add transactions, so you can check permissions, abort a delete,
|
|
446
448
|
// etc.
|
|
447
449
|
// - NOTE: I did a crappy implementation of abort just now above!
|
|
448
|
-
// But it doesn't work if called after the
|
|
450
|
+
// But it doesn't work if called after the deleter handler returns.
|
|
449
451
|
// - Generalize the code across set and del with a "mutate"
|
|
450
452
|
// operation
|
|
451
453
|
//
|
|
452
|
-
// - Right now we fire the
|
|
454
|
+
// - Right now we fire the deleter handlers right here.
|
|
453
455
|
//
|
|
454
456
|
// - Do we want to batch them up and fire them later?
|
|
455
457
|
// e.g. we could make a mark_deleted(key) like mark_changed(key)
|
|
@@ -468,7 +470,7 @@
|
|
|
468
470
|
|
|
469
471
|
var version = (t && t.version) || 'dirty-' + new_version()
|
|
470
472
|
|
|
471
|
-
// Find any .
|
|
473
|
+
// Find any .getter, and mark as dirty so that it re-runs
|
|
472
474
|
var found = false
|
|
473
475
|
if (gets_out.hasOwnProperty(key))
|
|
474
476
|
for (var i=0; i<gets_out[key].length; i++) {
|
|
@@ -588,13 +590,21 @@
|
|
|
588
590
|
// ****************
|
|
589
591
|
// Connections
|
|
590
592
|
function subspace (key, params) {
|
|
591
|
-
var methods = {
|
|
592
|
-
on_delete:null,
|
|
593
|
+
var methods = {getter:null, setter:null, on_set:null, on_set_sync:null,
|
|
594
|
+
on_delete:null, deleter:null, forgetter:null}
|
|
593
595
|
|
|
594
596
|
if (params) {
|
|
595
597
|
for (var method in params) {
|
|
596
|
-
console.assert(method in methods)
|
|
597
598
|
var func = params[method]
|
|
599
|
+
var param_names = {get:'getter', set:'setter',
|
|
600
|
+
delete: 'deleter', forget: 'forgetter',
|
|
601
|
+
on_set:'on_set', on_set_sync:'on_set_sync'}
|
|
602
|
+
|
|
603
|
+
// Map it from the API's name to our internal name
|
|
604
|
+
console.assert(param_names[method],
|
|
605
|
+
'Method "' + method + '" is invalid')
|
|
606
|
+
method = param_names[method]
|
|
607
|
+
|
|
598
608
|
autodetect_args(func)
|
|
599
609
|
func.defined = func.defined || []
|
|
600
610
|
func.defined.push({bus, method, key, as: 'handler'})
|
|
@@ -756,8 +766,8 @@
|
|
|
756
766
|
|
|
757
767
|
if (false && !funck.global_funk) {
|
|
758
768
|
// \u26A1
|
|
759
|
-
var event = {'
|
|
760
|
-
'
|
|
769
|
+
var event = {'setter':'set','on_set':'set.fire','getter':'get',
|
|
770
|
+
'deleter':'delete','forgetter':'forget'}[method],
|
|
761
771
|
triggering = funk ? 're-running' : 'initiating'
|
|
762
772
|
console.log(' > a', bus+'.'+event + "('" + (arg.key||arg) + "') is " + triggering
|
|
763
773
|
+'\n ' + funk_name(funck))
|
|
@@ -802,7 +812,8 @@
|
|
|
802
812
|
function key_arg () { return ((typeof arg.key) == 'string') ? arg.key : arg }
|
|
803
813
|
function rest_arg () { return (key_arg()).substr(binding.length-1) }
|
|
804
814
|
function val_arg () {
|
|
805
|
-
console.assert(method === '
|
|
815
|
+
console.assert(method === 'setter' || method === 'on_set' || method === 'on_set_sync',
|
|
816
|
+
'Bad method for val_arg()')
|
|
806
817
|
// Is there a time I am supposed to return bus.cache[arg]? It used to say:
|
|
807
818
|
// arg.key ? arg : bus.cache[arg]
|
|
808
819
|
|
|
@@ -821,9 +832,9 @@
|
|
|
821
832
|
t = clone(t || {})
|
|
822
833
|
|
|
823
834
|
// Add .abort() method
|
|
824
|
-
if (method === '
|
|
835
|
+
if (method === 'setter' || method === 'deleter')
|
|
825
836
|
t.abort = function () {
|
|
826
|
-
var key = method === '
|
|
837
|
+
var key = method === 'setter' ? arg.key : arg
|
|
827
838
|
if (f.loading()) return
|
|
828
839
|
bus.cache[key] = bus.cache[key] || {key: key}
|
|
829
840
|
bus.backup_cache[key] = bus.backup_cache[key] || {key: key}
|
|
@@ -831,34 +842,36 @@
|
|
|
831
842
|
}
|
|
832
843
|
|
|
833
844
|
// Add .done() method
|
|
834
|
-
if (method !== '
|
|
845
|
+
if (method !== 'forgetter')
|
|
835
846
|
t.done = function (o) {
|
|
836
|
-
var key = method === '
|
|
847
|
+
var key = method === 'setter' ? arg.key : arg
|
|
837
848
|
if (func.use_linked_json)
|
|
838
849
|
o = {key, val: o}
|
|
839
850
|
bus.log('We are DONE()ing', method, key, o||arg)
|
|
840
851
|
|
|
841
852
|
// We use a simple (and crappy?) heuristic to know if the
|
|
842
|
-
//
|
|
853
|
+
// setter handler has changed the state: whether the
|
|
843
854
|
// programmer passed (o) to the t.done(o) handler. If
|
|
844
855
|
// not, we assume it hasn't changed. If so, we assume it
|
|
845
856
|
// *has* changed, and thus we change the version of the
|
|
846
857
|
// state. I imagine it would be more accurate to diff
|
|
847
|
-
// from before the
|
|
858
|
+
// from before the setter handler began with when
|
|
848
859
|
// t.done(o) ran.
|
|
849
860
|
//
|
|
850
861
|
// Note: We will likely solve this in the future by
|
|
851
|
-
// preventing .
|
|
862
|
+
// preventing .setter() from changing the incoming state,
|
|
852
863
|
// except through an explicit .revise() function.
|
|
853
864
|
if (o) t.version = new_version()
|
|
854
865
|
|
|
855
|
-
if (method === '
|
|
866
|
+
if (method === 'deleter') {
|
|
856
867
|
delete bus.cache[key]
|
|
857
|
-
|
|
868
|
+
delete bus.backup_cache[key]
|
|
869
|
+
}
|
|
870
|
+
else if (method === 'setter') {
|
|
858
871
|
bus.set.fire(o || arg, t)
|
|
859
872
|
bus.route(key, 'on_set_sync', o || arg, t)
|
|
860
873
|
} else {
|
|
861
|
-
// Now method === '
|
|
874
|
+
// Now method === 'getter'
|
|
862
875
|
o.key = key
|
|
863
876
|
bus.set.fire(o, t)
|
|
864
877
|
// And now reset the version cause it could get called again
|
|
@@ -869,14 +882,20 @@
|
|
|
869
882
|
// Alias .return() to .done(), in case that feels better to you
|
|
870
883
|
t.return = t.done
|
|
871
884
|
|
|
885
|
+
// Prepush Scratch:
|
|
886
|
+
// var prepushed = {}
|
|
887
|
+
// t.prepush = function (key) {
|
|
888
|
+
// prepushed[key] = bus.get(key)
|
|
889
|
+
// }
|
|
890
|
+
|
|
872
891
|
// Alias t.reget() to bus.dirty()
|
|
873
|
-
if (method === '
|
|
892
|
+
if (method === 'setter')
|
|
874
893
|
t.reget = function () { bus.dirty(arg.key) }
|
|
875
894
|
|
|
876
895
|
// Now to call the handler, let's line up the function's special
|
|
877
896
|
// named arguemnts like key, o, t, rest, vars, etc.
|
|
878
897
|
var args = []
|
|
879
|
-
args[0] = (method in {
|
|
898
|
+
args[0] = (method in {setter:1, on_set:1, on_set_sync:1}) ? val_arg() : arg
|
|
880
899
|
args[1] = t
|
|
881
900
|
for (var k in (func.args||{})) {
|
|
882
901
|
switch (k) {
|
|
@@ -907,28 +926,29 @@
|
|
|
907
926
|
// arr[func.args[k]] = <compute_blah(k)>
|
|
908
927
|
|
|
909
928
|
// Trigger done() or abort() by return value
|
|
910
|
-
console.assert(!(result === '
|
|
929
|
+
console.assert(!(result === 'getter' &&
|
|
911
930
|
(result === 'done' || result === 'abort')),
|
|
912
|
-
'Returning "done" or "abort" is not allowed from
|
|
931
|
+
'Returning "done" or "abort" is not allowed from getter handlers')
|
|
932
|
+
|
|
913
933
|
if (result === 'done') t.done()
|
|
914
934
|
if (result === 'abort') t.abort()
|
|
915
935
|
|
|
916
936
|
// For get
|
|
917
937
|
if (func.use_linked_json) {
|
|
918
|
-
if (method === '
|
|
938
|
+
if (method === 'getter' && result !== undefined && !f.loading()) {
|
|
919
939
|
var obj = {key: arg, val: result}
|
|
920
940
|
var new_t = clone(t || {})
|
|
921
|
-
new_t.
|
|
941
|
+
new_t.getter = true
|
|
922
942
|
set.fire(obj, new_t)
|
|
923
943
|
return result
|
|
924
944
|
}
|
|
925
945
|
} else {
|
|
926
|
-
if (method === '
|
|
946
|
+
if (method === 'getter' && result instanceof Object
|
|
927
947
|
&& !f.loading() // Experimental.
|
|
928
948
|
) {
|
|
929
949
|
result.key = arg
|
|
930
950
|
var new_t = clone(t || {})
|
|
931
|
-
new_t.
|
|
951
|
+
new_t.getter = true
|
|
932
952
|
set.fire(result, new_t)
|
|
933
953
|
return result
|
|
934
954
|
}
|
|
@@ -937,29 +957,29 @@
|
|
|
937
957
|
// Set, forget and delete handlers stop re-running once they've
|
|
938
958
|
// completed without anything loading.
|
|
939
959
|
// ... with f.forget()
|
|
940
|
-
if (method !== '
|
|
960
|
+
if (method !== 'getter' && !f.loading())
|
|
941
961
|
f.forget()
|
|
942
962
|
})
|
|
943
963
|
f.proxies_for = func
|
|
944
964
|
f.arg = arg
|
|
945
965
|
f.transaction = t || {}
|
|
946
966
|
|
|
947
|
-
//
|
|
948
|
-
if (method === '
|
|
967
|
+
// getter handlers stop re-running when the key is forgotten
|
|
968
|
+
if (method === 'getter') {
|
|
949
969
|
var key = arg
|
|
950
970
|
function handler_done () {
|
|
951
971
|
f.forget()
|
|
952
|
-
unbind(key, '
|
|
972
|
+
unbind(key, 'forgetter', handler_done)
|
|
953
973
|
}
|
|
954
|
-
bind(key, '
|
|
974
|
+
bind(key, 'forgetter', handler_done)
|
|
955
975
|
|
|
956
976
|
// // Check if it's doubled-up
|
|
957
977
|
// if (gets_out[key])
|
|
958
|
-
// console.error('Two .
|
|
978
|
+
// console.error('Two .getter functions are running on the same key',
|
|
959
979
|
// key+'!', funk_name(funck), funk_name(gets_out[key]))
|
|
960
980
|
|
|
961
981
|
gets_out[key] = gets_out[key] || []
|
|
962
|
-
gets_out[key].push(f) // Record active
|
|
982
|
+
gets_out[key].push(f) // Record active getter handler
|
|
963
983
|
pending_gets[key] = f // Record that the get is pending
|
|
964
984
|
}
|
|
965
985
|
|
|
@@ -979,9 +999,9 @@
|
|
|
979
999
|
for (var i=0; i<handlers.length; i++)
|
|
980
1000
|
bus.run_handler(handlers[i].func, method, arg, {t: t, binding: handlers[i].key})
|
|
981
1001
|
|
|
982
|
-
// if (method === '
|
|
1002
|
+
// if (method === 'getter')
|
|
983
1003
|
// console.assert(handlers.length<2,
|
|
984
|
-
// 'Two
|
|
1004
|
+
// 'Two getter functions are registered for the same key '+key,
|
|
985
1005
|
// handlers)
|
|
986
1006
|
return handlers.length
|
|
987
1007
|
}
|
|
@@ -1187,7 +1207,7 @@
|
|
|
1187
1207
|
if (!name) throw 'Uncallback function needs a name'
|
|
1188
1208
|
var watching = {}
|
|
1189
1209
|
var prefix = 'uncallback/' + name
|
|
1190
|
-
bus(prefix + '/*').
|
|
1210
|
+
bus(prefix + '/*').getter = function (key, json) {
|
|
1191
1211
|
var args = json
|
|
1192
1212
|
function cb (err, result) {
|
|
1193
1213
|
if (err) {
|
|
@@ -1212,7 +1232,7 @@
|
|
|
1212
1232
|
}
|
|
1213
1233
|
}
|
|
1214
1234
|
if (options.stop_watching)
|
|
1215
|
-
bus(prefix + '/*').
|
|
1235
|
+
bus(prefix + '/*').forgetter = function (key, json) {
|
|
1216
1236
|
console.assert(watching[key],
|
|
1217
1237
|
'Forgetting a watcher for ' + JSON.stringify(key)
|
|
1218
1238
|
+ ' that is not enabled')
|
|
@@ -1234,6 +1254,10 @@
|
|
|
1234
1254
|
})
|
|
1235
1255
|
}
|
|
1236
1256
|
|
|
1257
|
+
function aget (key) {
|
|
1258
|
+
return new Promise((resolve, reject) =>
|
|
1259
|
+
bus.get_once(key, (o) => resolve(o)))
|
|
1260
|
+
}
|
|
1237
1261
|
|
|
1238
1262
|
// ******************
|
|
1239
1263
|
// Proxy
|
|
@@ -1417,7 +1441,7 @@
|
|
|
1417
1441
|
return bus.translate_links(bus.clone(keyed), rem_prefix)
|
|
1418
1442
|
}
|
|
1419
1443
|
|
|
1420
|
-
bus(prefix).
|
|
1444
|
+
bus(prefix).setter = function (obj, t) {
|
|
1421
1445
|
bus.set.fire(obj)
|
|
1422
1446
|
var x = {set: obj}
|
|
1423
1447
|
if (t.version) x.version = t.version
|
|
@@ -1426,11 +1450,14 @@
|
|
|
1426
1450
|
if (t.patch) x.set = rem_prefix(x.set.key)
|
|
1427
1451
|
send(x)
|
|
1428
1452
|
}
|
|
1429
|
-
bus(prefix).
|
|
1453
|
+
bus(prefix).getter = function (key) { send({get: key}),
|
|
1430
1454
|
client_getted_keys.add(key) }
|
|
1431
|
-
bus(prefix).
|
|
1455
|
+
bus(prefix).forgetter = function (key) { send({forget: key}),
|
|
1432
1456
|
client_getted_keys.delete(key) }
|
|
1433
|
-
bus(prefix).
|
|
1457
|
+
bus(prefix).deleter = function (key, t) {
|
|
1458
|
+
t.done()
|
|
1459
|
+
send({'delete': key})
|
|
1460
|
+
}
|
|
1434
1461
|
|
|
1435
1462
|
function connect () {
|
|
1436
1463
|
nlog('[ ] trying to open ' + url)
|
|
@@ -1933,7 +1960,7 @@
|
|
|
1933
1960
|
|
|
1934
1961
|
// This prune() function is a temporary workaround for dealing with nested
|
|
1935
1962
|
// objects in set() handlers, until we change statebus' behavior. Right
|
|
1936
|
-
// now, it calls .
|
|
1963
|
+
// now, it calls .setter only on the top-level state. But if that state
|
|
1937
1964
|
// validates, it calls fire() on *every* level of state. This means that
|
|
1938
1965
|
// state changes can sneak inside. Prune() will take out any changes from
|
|
1939
1966
|
// the nested levels of state in a new object -- replacing them with the
|
|
@@ -2115,7 +2142,7 @@
|
|
|
2115
2142
|
var api = ['cache backup_cache get set forget del fire dirty get_once',
|
|
2116
2143
|
'subspace bindings run_handler bind unbind reactive uncallback',
|
|
2117
2144
|
'versions new_version',
|
|
2118
|
-
'link',
|
|
2145
|
+
'link aget',
|
|
2119
2146
|
'funk_key funk_name funks key_id key_name id',
|
|
2120
2147
|
'pending_gets gets_in gets_out loading_keys loading once',
|
|
2121
2148
|
'global_funk busses rerunnable_funks',
|
|
@@ -2146,13 +2173,13 @@
|
|
|
2146
2173
|
bus.libs = {}
|
|
2147
2174
|
|
|
2148
2175
|
if (nodejs)
|
|
2149
|
-
require('./
|
|
2176
|
+
require('./server-library').import_server(bus, make_bus, options)
|
|
2150
2177
|
|
|
2151
2178
|
bus.render_when_loading = true
|
|
2152
2179
|
return bus
|
|
2153
2180
|
}
|
|
2154
2181
|
|
|
2155
|
-
if (nodejs) require('./
|
|
2182
|
+
if (nodejs) require('./server-library').import_module(make_bus)
|
|
2156
2183
|
|
|
2157
2184
|
return make_bus
|
|
2158
2185
|
}))
|