statebus 7.0.32 → 7.1.0
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-library.js +7 -3
- package/extras/tests.js +161 -27
- package/package.json +2 -2
- package/server-library.js +222 -232
- package/statebus.js +425 -115
package/server-library.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
var fs = require('fs'),
|
|
2
2
|
util = require('util')
|
|
3
3
|
|
|
4
|
-
var braidify = require('braid-http').http_server
|
|
5
|
-
|
|
6
4
|
|
|
7
5
|
function default_options (bus) { return {
|
|
8
6
|
port: 'auto',
|
|
9
|
-
backdoor: null,
|
|
10
7
|
client: (c) => {c.shadows(bus)},
|
|
11
8
|
file_store: {save_delay: 250, filename: 'db', backup_dir: 'backups', prefix: '*'},
|
|
12
9
|
sync_files: [{state_path: 'files', fs_path: null}],
|
|
@@ -14,9 +11,11 @@ function default_options (bus) { return {
|
|
|
14
11
|
certs: {private_key: 'certs/private-key',
|
|
15
12
|
certificate: 'certs/certificate',
|
|
16
13
|
certificate_bundle: 'certs/certificate-bundle'},
|
|
17
|
-
connections: {include_users: true, edit_others: true},
|
|
14
|
+
connections: {include_users: true, edit_others: true}, // Only for websockets
|
|
15
|
+
websocket: false,
|
|
18
16
|
websocket_path: '_connect_to_statebus_',
|
|
19
|
-
|
|
17
|
+
free_cors: true,
|
|
18
|
+
__secure: false // Only for websocket for connections state. Deprecate soon.
|
|
20
19
|
}}
|
|
21
20
|
|
|
22
21
|
function set_options (bus, options) {
|
|
@@ -53,41 +52,44 @@ function import_server (bus, make_statebus, options)
|
|
|
53
52
|
|| require('fs').existsSync(bus.options.certs.certificate)
|
|
54
53
|
|| require('fs').existsSync(bus.options.certs.certificate_bundle))
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
bus.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
bus.file_store()
|
|
55
|
+
// Create the client
|
|
56
|
+
if (bus.options.client)
|
|
57
|
+
// Todo: rewrite this func
|
|
58
|
+
bus.custom_clients = (client, client_id) => {
|
|
59
|
+
client.honk = bus.honk
|
|
60
|
+
client.serves_auth(master)
|
|
61
|
+
bus.options.client && bus.options.client(client)
|
|
62
|
+
}
|
|
65
63
|
|
|
66
|
-
//
|
|
67
|
-
// ***** Create our own http server *********
|
|
64
|
+
// Create HTTP server
|
|
68
65
|
bus.make_http_server({port: bus.options.port, use_ssl})
|
|
69
|
-
bus.
|
|
66
|
+
if (bus.options.websocket)
|
|
67
|
+
bus.sockjs_server(this.http_server) // Serve via sockjs on it
|
|
70
68
|
var express = require('express')
|
|
71
69
|
bus.express = express()
|
|
72
70
|
bus.http = express.Router()
|
|
73
71
|
bus.install_express(bus.express)
|
|
74
72
|
|
|
73
|
+
// User will put his routes in here
|
|
74
|
+
bus.express.use(bus.http)
|
|
75
|
+
|
|
76
|
+
// Connect bus to the HTTP server
|
|
77
|
+
bus.express.use(bus.http_in)
|
|
78
|
+
|
|
75
79
|
// use gzip compression if available
|
|
76
80
|
try { bus.http.use(require('compression')())
|
|
77
81
|
console.log('Enabled http compression!') } catch (e) {}
|
|
78
82
|
|
|
83
|
+
// Initialize storage
|
|
84
|
+
if (bus.options.file_store)
|
|
85
|
+
bus.file_store()
|
|
86
|
+
|
|
79
87
|
// Initialize file sync
|
|
80
88
|
; (bus.options.sync_files || []).forEach( x => {
|
|
81
89
|
if (require('fs').existsSync(x.fs_path || x.state_path))
|
|
82
90
|
bus.sync_files(x.state_path, x.fs_path)
|
|
83
91
|
})
|
|
84
92
|
|
|
85
|
-
// User will put his routes in here
|
|
86
|
-
bus.express.use(bus.http)
|
|
87
|
-
|
|
88
|
-
// Connect bus to the HTTP server
|
|
89
|
-
bus.express.use(bus.http_in)
|
|
90
|
-
|
|
91
93
|
// Serve Client Coffee
|
|
92
94
|
bus.serve_client_coffee()
|
|
93
95
|
|
|
@@ -124,130 +126,156 @@ function import_server (bus, make_statebus, options)
|
|
|
124
126
|
}
|
|
125
127
|
return handlers.length
|
|
126
128
|
}
|
|
127
|
-
|
|
128
|
-
// Back door to the control room
|
|
129
|
-
if (bus.options.backdoor) {
|
|
130
|
-
bus.make_http_server({
|
|
131
|
-
port: bus.options.backdoor,
|
|
132
|
-
name: 'backdoor_http_server',
|
|
133
|
-
use_ssl: use_ssl
|
|
134
|
-
})
|
|
135
|
-
bus.sockjs_server(this.backdoor_http_server)
|
|
136
|
-
}
|
|
137
129
|
},
|
|
138
130
|
|
|
131
|
+
|
|
139
132
|
// Connect HTTP GET and PUT to our Get and Set
|
|
140
133
|
http_in: function (req, res, next) {
|
|
134
|
+
// Log this request!
|
|
141
135
|
if (bus.honk)
|
|
142
|
-
console.log(req.method, req.url, req.headers.subscribe
|
|
136
|
+
console.log('IN:', req.method, decodeURIComponent(req.url), req.headers.subscribe
|
|
143
137
|
? 'Subscribe: ' + req.headers.subscribe : '')
|
|
144
138
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
// If this requests knows about Braid then we presume the programmer
|
|
139
|
+
// If this request knows about Braid then we presume the programmer
|
|
148
140
|
// knows that any client might make this cross-origin request.
|
|
149
141
|
if (req.headers.version || req.headers.parents || req.headers.subscribe
|
|
150
142
|
|| req.headers.peer || req.headers['put-order']
|
|
151
|
-
|| req.method === 'OPTIONS')
|
|
143
|
+
|| req.method === 'OPTIONS' || bus.options?.free_cors)
|
|
152
144
|
free_the_cors(req, res)
|
|
153
145
|
if (req.method === 'OPTIONS')
|
|
154
146
|
return
|
|
155
147
|
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
+ Math.random().toString(36).substring(2)
|
|
163
|
-
+ Math.random().toString(36).substring(2))
|
|
164
|
-
|
|
165
|
-
res.setHeader('Set-Cookie', 'peer=' + req.peer
|
|
166
|
-
+ '; Expires=21 Oct 2055 00:0:00 GMT;')
|
|
148
|
+
// Give up on methods we can't handle
|
|
149
|
+
if (!['GET', 'PUT', 'DELETE'].includes(req.method)) {
|
|
150
|
+
res.setHeader('Allow', 'GET, PUT, DELETE')
|
|
151
|
+
res.statusCode = 405
|
|
152
|
+
res.end()
|
|
153
|
+
return
|
|
167
154
|
}
|
|
168
155
|
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
var key = req.url.substr(1)
|
|
172
|
-
|
|
173
|
-
// Make a temporary client bus
|
|
174
|
-
var cbus = bus.bus_for_http_client(req, res)
|
|
156
|
+
// Braidify the req and res
|
|
157
|
+
require('braid-http').http_server(req, res)
|
|
175
158
|
|
|
159
|
+
// Initialize new clients with an id. We put the client id on
|
|
160
|
+
// req.client, and also in a cookie for the browser to see.
|
|
161
|
+
var client_id = req.headers.peer ||
|
|
162
|
+
require('cookie').parse(req.headers.cookie || '').peer
|
|
163
|
+
|
|
164
|
+
if (!client_id)
|
|
165
|
+
client_id = (Math.random().toString(36).substring(2)
|
|
166
|
+
+ Math.random().toString(36).substring(2)
|
|
167
|
+
+ Math.random().toString(36).substring(2))
|
|
168
|
+
|
|
169
|
+
// Add peer to response cookie, so client knows we've named it
|
|
170
|
+
var expires = new Date()
|
|
171
|
+
expires.setFullYear(expires.getFullYear() + 20)
|
|
172
|
+
res.setHeader('Set-Cookie', 'peer=' + client_id
|
|
173
|
+
+ '; Expires=' + expires.toUTCString() + ';')
|
|
174
|
+
|
|
175
|
+
// Decode the key
|
|
176
|
+
var key = decodeURIComponent(req.url.substr(1))
|
|
177
|
+
|
|
178
|
+
// Make the client bus
|
|
179
|
+
var client_bus = bus.client_bus_for(client_id)
|
|
180
|
+
|
|
181
|
+
// Handle a GET!
|
|
182
|
+
if (req.method === 'GET') {
|
|
176
183
|
if (req.subscribe)
|
|
177
|
-
res.startSubscription({ onClose:
|
|
184
|
+
res.startSubscription({ onClose: close_subscription })
|
|
178
185
|
else
|
|
179
186
|
res.statusCode = 200
|
|
180
187
|
|
|
181
|
-
// We
|
|
188
|
+
// We assume all content is JSON
|
|
182
189
|
res.setHeader('Content-Type', 'application/json')
|
|
183
190
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
// console.trace('http_in: Sending update of', key)
|
|
188
|
-
var body = to_http_body(o)
|
|
191
|
+
function send_update (obj, t) {
|
|
192
|
+
var body = to_http_body(obj)
|
|
193
|
+
// console.log('http_in: Sending update of', body)
|
|
189
194
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
195
|
+
res.sendUpdate({
|
|
196
|
+
body,
|
|
197
|
+
// If body === undefined, send 404
|
|
198
|
+
status: body === undefined ? 404 : 200
|
|
199
|
+
})
|
|
194
200
|
|
|
195
201
|
// And shut down the connection if there's no subscription
|
|
196
202
|
if (!req.subscribe)
|
|
197
|
-
|
|
203
|
+
close_subscription()
|
|
198
204
|
}
|
|
199
205
|
|
|
200
|
-
function
|
|
201
|
-
|
|
206
|
+
function close_subscription () {
|
|
207
|
+
client_bus.forget(key, send_update)
|
|
202
208
|
res.end()
|
|
203
|
-
cbus.http_unsubscribe(req)
|
|
204
209
|
|
|
205
|
-
|
|
206
|
-
if (cbus.http_callbacks)
|
|
207
|
-
delete cbus.http_callbacks[JSON.stringify({peer, key})]
|
|
210
|
+
delete client_bus.dialogues[req.headers.dialogue]
|
|
208
211
|
}
|
|
209
212
|
|
|
210
213
|
// If we have a peer id, then register this callback at that peer,
|
|
211
214
|
// so it can avoid getting its own PUT versions echoed back to
|
|
212
215
|
// itself.
|
|
213
|
-
if (req.headers.
|
|
214
|
-
|
|
215
|
-
cbus.http_callbacks = {}
|
|
216
|
-
let peer = req.headers.peer
|
|
217
|
-
cbus.http_callbacks[JSON.stringify({peer, key})]
|
|
218
|
-
= send_to_client
|
|
219
|
-
}
|
|
216
|
+
if (req.headers.dialogue)
|
|
217
|
+
client_bus.dialogues[req.headers.dialogue] = send_update
|
|
220
218
|
|
|
221
219
|
// And issue the get!
|
|
222
|
-
|
|
220
|
+
client_bus.get(key, send_update)
|
|
223
221
|
}
|
|
224
222
|
|
|
223
|
+
// Handle a PUT!
|
|
225
224
|
else if (req.method === 'PUT') {
|
|
226
225
|
|
|
226
|
+
// Grab the version(s)
|
|
227
|
+
var t = {
|
|
228
|
+
version: req.version || client_bus.new_version(),
|
|
229
|
+
parents: req.parents
|
|
230
|
+
}
|
|
231
|
+
|
|
227
232
|
// Maybe the new state is expressed in patches
|
|
228
233
|
if (req.headers.patches || req.headers['content-range']) {
|
|
229
234
|
|
|
230
235
|
var patches = req.patches().then(patches => {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
+
|
|
237
|
+
// Presume all patch contents are text
|
|
238
|
+
t.patches = patches.map(patch => ({
|
|
239
|
+
...patch,
|
|
240
|
+
content: patch.content_text
|
|
241
|
+
}))
|
|
242
|
+
// console.log("...and we see these patches:", patches)
|
|
243
|
+
|
|
244
|
+
// Fetch our current state on the bus
|
|
245
|
+
client_bus.get_once(key, (obj) => {
|
|
246
|
+
// ...and apply the patches to it
|
|
247
|
+
client_bus.set(key, t)
|
|
248
|
+
|
|
249
|
+
// Todo: Make a statebus auto-fetch current state when
|
|
250
|
+
// patching so that I don't need to manually fetch it
|
|
251
|
+
// before applying a patch.
|
|
252
|
+
|
|
253
|
+
// Todo: only send success once transaction has
|
|
254
|
+
// validated. Handle aborts, too.
|
|
236
255
|
res.sendStatus(200)
|
|
237
|
-
console.log('We just processed a
|
|
256
|
+
// console.log('We just processed a patches!')
|
|
238
257
|
})
|
|
239
258
|
})
|
|
240
|
-
}
|
|
241
|
-
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Otherwise, we have JSON in the body
|
|
262
|
+
else {
|
|
263
|
+
|
|
264
|
+
// Sanity check the body
|
|
242
265
|
if (typeof req.headers['content-type'] !== 'string'
|
|
243
266
|
|| req.headers['content-type'].toLowerCase() !== 'application/json')
|
|
244
267
|
console.error('Error: PUT content-type is not application/json')
|
|
268
|
+
|
|
269
|
+
// Start downloading it
|
|
245
270
|
var body = ''
|
|
246
271
|
req.on('data', chunk => {body += chunk.toString()})
|
|
272
|
+
|
|
273
|
+
// When the body is downloaded...
|
|
247
274
|
req.on('end', () => {
|
|
275
|
+
|
|
276
|
+
// Parse it as JSON
|
|
248
277
|
try {
|
|
249
|
-
var
|
|
250
|
-
var obj = from_http_body(path, body)
|
|
278
|
+
var obj = from_http_body(path, key)
|
|
251
279
|
} catch (e) {
|
|
252
280
|
console.error('Error: PUT body was not valid json', e)
|
|
253
281
|
res.statusCode = 500
|
|
@@ -255,73 +283,24 @@ function import_server (bus, make_statebus, options)
|
|
|
255
283
|
return
|
|
256
284
|
}
|
|
257
285
|
|
|
258
|
-
// Make a temporary client bus
|
|
259
|
-
var cbus = bus.bus_for_http_client(req, res)
|
|
260
|
-
var t = {
|
|
261
|
-
version: req.version || cbus.new_version(),
|
|
262
|
-
parents: req.parents
|
|
263
|
-
}
|
|
264
|
-
|
|
265
286
|
// If the peer declares itself, let's remember it so that
|
|
266
287
|
// we don't send it echoes
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
key = obj.key
|
|
270
|
-
var cb = cbus.http_callbacks && cbus.http_callbacks[
|
|
271
|
-
JSON.stringify({peer, key})
|
|
272
|
-
]
|
|
273
|
-
if (cb) cb.has_seen(cbus, key, t.version)
|
|
274
|
-
}
|
|
288
|
+
var send_func = client_bus.dialogues[req.headers.dialogue]
|
|
289
|
+
if (send_func) send_func.has_seen(client_bus, key, t.version)
|
|
275
290
|
|
|
276
|
-
// Now send the
|
|
277
|
-
|
|
291
|
+
// Now send the update to the bus!
|
|
292
|
+
client_bus.set(obj, t)
|
|
278
293
|
|
|
279
294
|
res.statusCode = 200
|
|
280
295
|
res.end()
|
|
281
|
-
|
|
296
|
+
client_bus.http_unsubscribe(req)
|
|
282
297
|
})
|
|
283
298
|
}
|
|
284
299
|
}
|
|
285
|
-
else
|
|
300
|
+
else {
|
|
301
|
+
console.log('IN: nothing on the bus for it! passing along...')
|
|
286
302
|
next()
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
bus_for_http_client: function (req, res) {
|
|
290
|
-
var bus = this
|
|
291
|
-
if (!bus.bus_for_http_client.counter) {
|
|
292
|
-
bus.bus_for_http_client.counter = 0
|
|
293
|
-
bus.bus_for_http_client.busses = {}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// If this client has a peer ID, and we've got a bus for that peer,
|
|
297
|
-
// then re-use it!
|
|
298
|
-
if (req.peer && bus.bus_for_http_client.busses[req.peer]) {
|
|
299
|
-
var cbus = bus.bus_for_http_client.busses[req.peer]
|
|
300
|
-
cbus.client_ip = req.connection.remoteAddress
|
|
301
|
-
cbus.num_subscriptions++
|
|
302
|
-
return cbus
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// Otherwise, create a new bus
|
|
306
|
-
var cbus = make_statebus()
|
|
307
|
-
cbus.label = 'client_http' + bus.bus_for_http_client.counter++
|
|
308
|
-
cbus.master = bus
|
|
309
|
-
cbus.num_subscriptions = 1
|
|
310
|
-
cbus.http_unsubscribe = (req) => {
|
|
311
|
-
cbus.num_subscriptions--
|
|
312
|
-
if (cbus.num_subscriptions === 0) {
|
|
313
|
-
// log('Last subscription! Killing client bus!')
|
|
314
|
-
cbus.delete_bus()
|
|
315
|
-
delete bus.bus_for_http_client.busses[req.peer]
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
bus.bus_for_http_client.busses[req.peer] = cbus
|
|
319
|
-
|
|
320
|
-
// And log into it as the client
|
|
321
|
-
cbus.serves_auth({remoteAddress: req.connection.remoteAddress}, bus)
|
|
322
|
-
bus.options.client(cbus)
|
|
323
|
-
cbus.set({key: 'current_user', val: {client: req.peer}})
|
|
324
|
-
return cbus
|
|
303
|
+
}
|
|
325
304
|
},
|
|
326
305
|
|
|
327
306
|
make_http_server: function make_http_server (options) {
|
|
@@ -417,12 +396,12 @@ function import_server (bus, make_statebus, options)
|
|
|
417
396
|
})
|
|
418
397
|
|
|
419
398
|
},
|
|
420
|
-
sockjs_server: function sockjs_server(httpserver
|
|
421
|
-
var master =
|
|
399
|
+
sockjs_server: function sockjs_server(httpserver) {
|
|
400
|
+
var master = bus
|
|
422
401
|
var client_num = 0
|
|
423
402
|
// var client_busses = {} // XXX work in progress
|
|
424
403
|
var log = master.log
|
|
425
|
-
if (
|
|
404
|
+
if (master.custom_clients) {
|
|
426
405
|
master.set({key: 'connections', val: {}}) // Clean out old sessions
|
|
427
406
|
var connections = master.get('connections')
|
|
428
407
|
}
|
|
@@ -432,7 +411,7 @@ function import_server (bus, make_statebus, options)
|
|
|
432
411
|
heartbeat_delay: 6000 * 1000
|
|
433
412
|
})
|
|
434
413
|
s.on('connection', function(conn) {
|
|
435
|
-
if (
|
|
414
|
+
if (master.custom_clients) {
|
|
436
415
|
// To do for pooling client busses:
|
|
437
416
|
// - What do I do with connections? Do they pool at all?
|
|
438
417
|
// - Before creating a new bus here, check to see if there's
|
|
@@ -441,15 +420,18 @@ function import_server (bus, make_statebus, options)
|
|
|
441
420
|
// - When disconnecting, decrement the number, and if it gets
|
|
442
421
|
// to zero, delete the client bus.
|
|
443
422
|
|
|
444
|
-
connections.val[conn.id] = {
|
|
445
|
-
|
|
446
|
-
|
|
423
|
+
// connections.val[conn.id] = {id: conn.id}
|
|
424
|
+
// master.set(connections)
|
|
425
|
+
|
|
426
|
+
var client_id = conn.headers.peer ||
|
|
427
|
+
require('cookie').parse(conn.headers.cookie || '').peer
|
|
447
428
|
|
|
448
429
|
var client = make_statebus()
|
|
449
430
|
client.label = 'client' + client_num++
|
|
450
431
|
master.label = master.label || 'master'
|
|
432
|
+
client.client_ip = conn.remoteAddress
|
|
451
433
|
client.master = master
|
|
452
|
-
|
|
434
|
+
master.custom_clients(client, client_id)
|
|
453
435
|
} else
|
|
454
436
|
var client = master
|
|
455
437
|
|
|
@@ -519,16 +501,22 @@ function import_server (bus, make_statebus, options)
|
|
|
519
501
|
break
|
|
520
502
|
case 'set':
|
|
521
503
|
message.version = message.version || client.new_version()
|
|
522
|
-
if (message.patches) {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
504
|
+
// if (message.patches) {
|
|
505
|
+
// var o = client.cache[message.set] || {key: message.set}
|
|
506
|
+
// try {
|
|
507
|
+
// console.log('Applying patch', {
|
|
508
|
+
// key: message.set,
|
|
509
|
+
// patches: message.patches,
|
|
510
|
+
// to: o,
|
|
511
|
+
// bus: bus.label
|
|
512
|
+
// })
|
|
513
|
+
// message.set = client.apply_patch(o.val, message.patches[0])
|
|
514
|
+
// } catch (e) {
|
|
515
|
+
// console.error('Received bad sockjs message from '
|
|
516
|
+
// + conn.remoteAddress +': ', message, e)
|
|
517
|
+
// return
|
|
518
|
+
// }
|
|
519
|
+
// }
|
|
532
520
|
client.set(message.set,
|
|
533
521
|
{version: message.version,
|
|
534
522
|
parents: message.parents,
|
|
@@ -553,67 +541,68 @@ function import_server (bus, make_statebus, options)
|
|
|
553
541
|
log('sockjs_s: disconnected from', conn.remoteAddress, conn.id, client.id)
|
|
554
542
|
for (var key in our_gets_in)
|
|
555
543
|
client.forget(key, sockjs_pubber)
|
|
556
|
-
if (
|
|
557
|
-
delete connections.val[conn.id]; master.set(connections)
|
|
558
|
-
master.delete('connection/' + conn.id)
|
|
544
|
+
if (master.custom_clients) {
|
|
545
|
+
// delete connections.val[conn.id]; master.set(connections)
|
|
546
|
+
// master.delete('connection/' + conn.id)
|
|
559
547
|
client.delete_bus()
|
|
560
548
|
}
|
|
561
549
|
})
|
|
562
550
|
|
|
563
|
-
// Define the /connection* state!
|
|
564
|
-
if (
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
551
|
+
// // Define the /connection* state!
|
|
552
|
+
// if (master.custom_clients && !master.options.__secure) {
|
|
553
|
+
|
|
554
|
+
// // A connection
|
|
555
|
+
// client('connection/*').getter = function (key, star) {
|
|
556
|
+
// var result = bus.clone(master.get(key))
|
|
557
|
+
// if (master.options.connections.include_users && result.user)
|
|
558
|
+
// result.user = client.get(result.user.key)
|
|
559
|
+
// result.id = star
|
|
560
|
+
// result.client = star // Deprecated. Delete this line in v7.
|
|
561
|
+
// return result
|
|
562
|
+
// }
|
|
563
|
+
// client('connection/*').setter = function (o, star, t) {
|
|
564
|
+
// // Check permissions before editing
|
|
565
|
+
// if (star !== conn.id && !master.options.connections.edit_others) {
|
|
566
|
+
// t.abort()
|
|
567
|
+
// return
|
|
568
|
+
// }
|
|
569
|
+
// o.id = star
|
|
570
|
+
// o.client = star // Deprecated. Delete this line in v7.
|
|
571
|
+
// master.set(client.clone(o))
|
|
572
|
+
// }
|
|
585
573
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
574
|
+
// // Your connection
|
|
575
|
+
// client('connection').getter = function () {
|
|
576
|
+
// // subscribe to changes in authentication
|
|
577
|
+
// client.get('current_user')
|
|
590
578
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
579
|
+
// var result = client.clone(client.get('connection/' + conn.id))
|
|
580
|
+
// delete result.key
|
|
581
|
+
// return result
|
|
582
|
+
// }
|
|
583
|
+
// client('connection').setter = function (o) {
|
|
584
|
+
// o = client.clone(o)
|
|
585
|
+
// o.key = 'connection/' + conn.id
|
|
586
|
+
// client.set(o)
|
|
587
|
+
// }
|
|
600
588
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
589
|
+
// // All connections
|
|
590
|
+
// client('connections').setter = function noop (t) {t.abort()}
|
|
591
|
+
// client('connections').getter = function () {
|
|
592
|
+
// var result = []
|
|
593
|
+
// var conns = master.get('connections').val
|
|
594
|
+
// for (var connid in conns)
|
|
595
|
+
// if (connid !== 'key')
|
|
596
|
+
// result.push(client.get('connection/' + connid))
|
|
609
597
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
}
|
|
598
|
+
// return {val: result}
|
|
599
|
+
// }
|
|
600
|
+
// }
|
|
613
601
|
})
|
|
614
602
|
|
|
615
603
|
// console.log('websocket listening on', '/' + bus.options.websocket_path)
|
|
616
|
-
s.installHandlers(httpserver
|
|
604
|
+
s.installHandlers(httpserver || bus.http,
|
|
605
|
+
{prefix:'/' + bus.options.websocket_path})
|
|
617
606
|
},
|
|
618
607
|
|
|
619
608
|
make_websocket: function make_websocket (url) {
|
|
@@ -1215,7 +1204,6 @@ function import_server (bus, make_statebus, options)
|
|
|
1215
1204
|
},
|
|
1216
1205
|
|
|
1217
1206
|
smtp (opts) {
|
|
1218
|
-
var bus = this
|
|
1219
1207
|
// Listen for SMTP messages on port 25
|
|
1220
1208
|
if (opts.domain) {
|
|
1221
1209
|
var mailin = require('mailin')
|
|
@@ -1699,7 +1687,7 @@ function import_server (bus, make_statebus, options)
|
|
|
1699
1687
|
}
|
|
1700
1688
|
},
|
|
1701
1689
|
|
|
1702
|
-
serves_auth: function serves_auth (
|
|
1690
|
+
serves_auth: function serves_auth (master) {
|
|
1703
1691
|
// Right now, we only support accounts at '@username', but in general
|
|
1704
1692
|
// we could allow the prefix to be configurable. We just have to go
|
|
1705
1693
|
// through this function and make all the regular expressions (like
|
|
@@ -1743,6 +1731,7 @@ function import_server (bus, make_statebus, options)
|
|
|
1743
1731
|
var users = master.get('users')
|
|
1744
1732
|
users.val = users.val || []
|
|
1745
1733
|
for (var i=0; i<users.val.length; i++) {
|
|
1734
|
+
if (!users.val[i]) console.log('Undefined for', {users, i})
|
|
1746
1735
|
var u = master.get(users.val[i].link)
|
|
1747
1736
|
if (!(u.val.login || u.val.name)) {
|
|
1748
1737
|
console.error('upass: this user has bogus name/login', u.key, u.val.name, u.val.login)
|
|
@@ -1758,6 +1747,7 @@ function import_server (bus, make_statebus, options)
|
|
|
1758
1747
|
}
|
|
1759
1748
|
return result
|
|
1760
1749
|
}
|
|
1750
|
+
|
|
1761
1751
|
master.auth_initialized = true
|
|
1762
1752
|
master.get('users/passwords')
|
|
1763
1753
|
|
|
@@ -1864,10 +1854,10 @@ function import_server (bus, make_statebus, options)
|
|
|
1864
1854
|
|
|
1865
1855
|
// Current User
|
|
1866
1856
|
client('current_user').getter = function (k) {
|
|
1867
|
-
if (!
|
|
1857
|
+
if (!client.client_id)
|
|
1868
1858
|
return {val: {error: 'no client'}}
|
|
1869
1859
|
|
|
1870
|
-
var u = (master.get('logged_in_clients').val || {})[
|
|
1860
|
+
var u = (master.get('logged_in_clients').val || {})[client.client_id]
|
|
1871
1861
|
var result = {val: {user: u || null, logged_in: !!u}}
|
|
1872
1862
|
return result
|
|
1873
1863
|
}
|
|
@@ -1888,14 +1878,12 @@ function import_server (bus, make_statebus, options)
|
|
|
1888
1878
|
}
|
|
1889
1879
|
|
|
1890
1880
|
client.log('* saving: current_user!')
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
//
|
|
1894
|
-
//
|
|
1895
|
-
//
|
|
1896
|
-
conn.client = val.client
|
|
1881
|
+
|
|
1882
|
+
if (val.client && !client.client_id) {
|
|
1883
|
+
// Note: HTTP clients already set client.client_id when
|
|
1884
|
+
// creating the client bus, so this code should only run for
|
|
1885
|
+
// websocket clients..
|
|
1897
1886
|
client.client_id = val.client
|
|
1898
|
-
client.client_ip = conn.remoteAddress
|
|
1899
1887
|
|
|
1900
1888
|
// if (conn.id) {
|
|
1901
1889
|
// var connections = master.get('connections')
|
|
@@ -1933,6 +1921,7 @@ function import_server (bus, make_statebus, options)
|
|
|
1933
1921
|
|
|
1934
1922
|
client.log('auth said:', user_key)
|
|
1935
1923
|
if (user_key) {
|
|
1924
|
+
client.log('Success!')
|
|
1936
1925
|
// Success!
|
|
1937
1926
|
// Associate this user with this session
|
|
1938
1927
|
// user.log('Logging the user in!', u)
|
|
@@ -1941,7 +1930,7 @@ function import_server (bus, make_statebus, options)
|
|
|
1941
1930
|
// var connections = master.get('connections')
|
|
1942
1931
|
|
|
1943
1932
|
clients.val = clients.val || {}
|
|
1944
|
-
clients.val[
|
|
1933
|
+
clients.val[client.client_id] = {link: user_key}
|
|
1945
1934
|
// connections.val[conn.id].user = {link: user_key}
|
|
1946
1935
|
|
|
1947
1936
|
master.set(clients)
|
|
@@ -1961,12 +1950,13 @@ function import_server (bus, make_statebus, options)
|
|
|
1961
1950
|
}
|
|
1962
1951
|
|
|
1963
1952
|
else if (val.logout) {
|
|
1964
|
-
client.log('current_user: logging out'
|
|
1953
|
+
client.log('current_user: logging out of client ',
|
|
1954
|
+
client.client_id)
|
|
1965
1955
|
var clients = master.get('logged_in_clients')
|
|
1966
1956
|
// var connections = master.get('connections')
|
|
1967
1957
|
|
|
1968
1958
|
clients.val = clients.val || {}
|
|
1969
|
-
delete clients.val[
|
|
1959
|
+
delete clients.val[client.client_id]
|
|
1970
1960
|
// connections.val[conn.id].user = null
|
|
1971
1961
|
|
|
1972
1962
|
master.set(clients)
|
|
@@ -2450,8 +2440,8 @@ function import_server (bus, make_statebus, options)
|
|
|
2450
2440
|
path = path || 'client.js'
|
|
2451
2441
|
bus.http.get('/' + path, (req, res) => {
|
|
2452
2442
|
var files =
|
|
2453
|
-
['extras/coffee.js', 'extras/sockjs.js',
|
|
2454
|
-
'statebus.js', 'client.js'].map((f) => fs.readFileSync('node_modules/statebus/' + f))
|
|
2443
|
+
['extras/coffee.js', 'extras/sockjs.js', 'extras/react12.min.js',
|
|
2444
|
+
'statebus.js', 'client-library.js'].map((f) => fs.readFileSync('node_modules/statebus/' + f))
|
|
2455
2445
|
files.unshift(fs.readFileSync(
|
|
2456
2446
|
'node_modules/braid-http/braid-http-client.js'
|
|
2457
2447
|
))
|