tlsd 2.8.0 → 2.9.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/package.json +3 -2
- package/{server_static → rpc_static}/rpc/rpc.js +15 -13
- package/scaffold/static/404/index.html +16 -0
- package/scaffold/static/index.html +4 -1
- package/scaffold/static/local.sass +11 -0
- package/scaffold/static/local.sass.css +12 -0
- package/tlsd.js +97 -41
- package/server_static/rpc/test.html +0 -11
- package/test.html +0 -4
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tlsd",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "A server for web app prototyping with HTTPS and Websockets",
|
|
5
5
|
"main": "tlsd.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"tlsd": "tlsd"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
+
"dev": "./tlsd run dev scaffold 12345 5",
|
|
10
11
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
12
|
},
|
|
12
13
|
"author": "Joe Hitchens <joe@sleepless.com>",
|
|
@@ -19,9 +20,9 @@
|
|
|
19
20
|
"cors": "^2.8.5",
|
|
20
21
|
"g": "^2.0.1",
|
|
21
22
|
"greenlock-express": "^4.0.3",
|
|
23
|
+
"sass": "^1.69.5",
|
|
22
24
|
"serve-static": "^1.15.0",
|
|
23
25
|
"sleepless": "^5.13.0",
|
|
24
|
-
"tlsd": "^2.4.1",
|
|
25
26
|
"websocket": "^1.0.34"
|
|
26
27
|
}
|
|
27
28
|
}
|
|
@@ -24,9 +24,11 @@
|
|
|
24
24
|
const time = function( dt ) { return Math.round( ( new Date() ).getTime() / 1000 ); }
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
let DBG =
|
|
27
|
+
let DBG = function( ...args ) {
|
|
28
28
|
if( RPC.debug ) {
|
|
29
|
-
|
|
29
|
+
args.unshift( "RPC:" );
|
|
30
|
+
console.log.apply( this, args );
|
|
31
|
+
//console.log( "RPC: ", args );
|
|
30
32
|
}
|
|
31
33
|
};
|
|
32
34
|
|
|
@@ -47,11 +49,11 @@
|
|
|
47
49
|
delete wraps[id]
|
|
48
50
|
num -= 1
|
|
49
51
|
if(num == 0) {
|
|
50
|
-
DBG( "clearInterval
|
|
52
|
+
//DBG( "clearInterval", timer );
|
|
51
53
|
clearInterval(timer)
|
|
52
54
|
timer = null
|
|
53
55
|
}
|
|
54
|
-
DBG("forgetting
|
|
56
|
+
//DBG("forgetting", id, p );
|
|
55
57
|
}
|
|
56
58
|
return p
|
|
57
59
|
}
|
|
@@ -60,7 +62,7 @@
|
|
|
60
62
|
// Put a msg into the list
|
|
61
63
|
// ttl is in secs and should not be less than 10 (default is 60 if not provided)
|
|
62
64
|
const ins = self.ins = function(p, id, ttl) {
|
|
63
|
-
DBG( "remembering
|
|
65
|
+
//DBG( "remembering", id, p );
|
|
64
66
|
const w = {
|
|
65
67
|
expire: time() + (ttl || 60),
|
|
66
68
|
payload: p,
|
|
@@ -77,7 +79,7 @@
|
|
|
77
79
|
}
|
|
78
80
|
}
|
|
79
81
|
}, 10 * 1000);
|
|
80
|
-
DBG( "setInterval
|
|
82
|
+
//DBG( "setInterval", timer );
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
|
|
@@ -99,7 +101,6 @@
|
|
|
99
101
|
const waiting = new WaitList()
|
|
100
102
|
|
|
101
103
|
const send = function(m, cb, fail) {
|
|
102
|
-
DBG( "send: " + o2j( m ) );
|
|
103
104
|
if(m.msg_id === undefined) {
|
|
104
105
|
m.msg_id = "CMID-" + next_seq(); // every message must have an id
|
|
105
106
|
}
|
|
@@ -109,7 +110,7 @@
|
|
|
109
110
|
waiting.ins( { msg: m, cb, fail }, m.msg_id );
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
DBG(">>--->
|
|
113
|
+
DBG(">>--->", m );
|
|
113
114
|
socket.send( o2j( m ) );
|
|
114
115
|
}
|
|
115
116
|
|
|
@@ -117,7 +118,7 @@
|
|
|
117
118
|
var socket = new WebSocket( ( loc.protocol == "http:" ? "ws:" : "wss:" ) + "//" + loc.host + path )
|
|
118
119
|
|
|
119
120
|
socket.onerror = function( evt ) {
|
|
120
|
-
DBG( "error:
|
|
121
|
+
DBG( "error:", evt.data );
|
|
121
122
|
cb_ctrl( "error", evt.data );
|
|
122
123
|
}
|
|
123
124
|
|
|
@@ -125,7 +126,7 @@
|
|
|
125
126
|
DBG( "close" );
|
|
126
127
|
cb_ctrl( "disconnect", conn.attempt );
|
|
127
128
|
setTimeout( () => {
|
|
128
|
-
DBG( "reconnect atttempt
|
|
129
|
+
DBG( "reconnect atttempt", conn.attempt );
|
|
129
130
|
ws_connect( cb_msg, cb_ctrl, path );
|
|
130
131
|
}, 2 * 1000 );
|
|
131
132
|
}
|
|
@@ -137,7 +138,7 @@
|
|
|
137
138
|
|
|
138
139
|
// handle incoming messages from server
|
|
139
140
|
socket.onmessage = function( evt ) {
|
|
140
|
-
DBG( "<---<<
|
|
141
|
+
//DBG( "<---<<", evt.data )
|
|
141
142
|
|
|
142
143
|
var json = evt.data // raw message is a utf8 string
|
|
143
144
|
var msg_in = j2o( json )
|
|
@@ -146,6 +147,8 @@
|
|
|
146
147
|
return;
|
|
147
148
|
}
|
|
148
149
|
|
|
150
|
+
DBG( "<---<<", msg_in )
|
|
151
|
+
|
|
149
152
|
if(typeof msg_in.msg !== "undefined") {
|
|
150
153
|
// server initiated msg (not a reply to a client msg)
|
|
151
154
|
|
|
@@ -257,7 +260,6 @@
|
|
|
257
260
|
|
|
258
261
|
ws_connect( msg => {
|
|
259
262
|
// msg initiated by server
|
|
260
|
-
//DBG( "Server says: " + msg );
|
|
261
263
|
|
|
262
264
|
// If there's a handler set for this, call that
|
|
263
265
|
const fn = RPC[ "onmessage" ];
|
|
@@ -278,7 +280,7 @@
|
|
|
278
280
|
|
|
279
281
|
}, ( evt, detail ) => {
|
|
280
282
|
// event occurred
|
|
281
|
-
DBG( "Event:
|
|
283
|
+
DBG( "Event:", evt );
|
|
282
284
|
if( evt === "connect" ) {
|
|
283
285
|
RPC.connected = true;
|
|
284
286
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Page Not Found </title>
|
|
5
|
+
</head>
|
|
6
|
+
<body>
|
|
7
|
+
<h1>Sorry, nothing there, mate!</h1>
|
|
8
|
+
<p>
|
|
9
|
+
<script>
|
|
10
|
+
let url = decodeURIComponent( document.location.search.split( "=" ).pop() );
|
|
11
|
+
document.write( "Requested URL: " + url );
|
|
12
|
+
</script>
|
|
13
|
+
</p>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
16
|
+
|
package/tlsd.js
CHANGED
|
@@ -159,25 +159,33 @@ const basic_handler = function( root ) {
|
|
|
159
159
|
|
|
160
160
|
} );
|
|
161
161
|
|
|
162
|
-
// Serve my own static files
|
|
163
|
-
// this is primarily so that GET /rpc/rpc.js can return the client-side code for
|
|
164
|
-
// sending WS and RPC messages (similar to how socket.io works)
|
|
165
|
-
app.use( serveStatic( __dirname + "/server_static" ) );
|
|
166
162
|
|
|
167
|
-
// Serve static files
|
|
163
|
+
// Serve my (tlsd's) own static files
|
|
164
|
+
// This is primarily so that GET /rpc/rpc.js can return the client-side code for
|
|
165
|
+
// sending WS RPC messages (similar to how socket.io works) and providing the
|
|
166
|
+
// browser hot-reload feature (which requires WS RPC)
|
|
167
|
+
app.use( serveStatic( __dirname + "/rpc_static" ) );
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
// Serve static files for the domain
|
|
168
171
|
app.use( serveStatic( root + "/static" ) );
|
|
169
172
|
|
|
173
|
+
|
|
170
174
|
// finally, if serveStatic can't service the request,
|
|
171
175
|
// look for a 404/ dir and redirect to that if present
|
|
172
176
|
app.use( function( req, res, next ) {
|
|
173
177
|
// I can't just return a redirect here because if the /404 doesn't exist,
|
|
174
178
|
// I will just go into a redirect loop, so I have to test to see if the
|
|
175
179
|
// dir exists, and then if so, redirect to it, otherwise, just return 404.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
+
let { url, } = req;
|
|
181
|
+
let p = root + "/static/404";
|
|
182
|
+
is_dir( p, so => {
|
|
183
|
+
if( so ) {
|
|
184
|
+
let p404 = "/404/?original_path=" + encodeURIComponent( url );
|
|
185
|
+
res.writeHead( 302, { "Location": p404, } );
|
|
186
|
+
} else {
|
|
180
187
|
res.writeHead( 404 );
|
|
188
|
+
}
|
|
181
189
|
res.end();
|
|
182
190
|
} );
|
|
183
191
|
} );
|
|
@@ -220,18 +228,22 @@ const rest_handler = function( root, req, rsp ) {
|
|
|
220
228
|
};
|
|
221
229
|
|
|
222
230
|
|
|
223
|
-
|
|
231
|
+
// tracked websocket connections
|
|
232
|
+
const ws_connections = {};
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
const ws_attach = function( httpServer, msg_handler ) {
|
|
224
236
|
|
|
225
237
|
const wsd = new websocket.server( { httpServer, autoAcceptConnections: false, } );
|
|
226
238
|
|
|
227
|
-
wsd.on( "request", function(
|
|
228
|
-
V( "WS: connection request from "+
|
|
239
|
+
wsd.on( "request", function( wsreq ) {
|
|
240
|
+
V( "WS: connection request from "+wsreq.remoteAddress+" "+wsreq.resource )
|
|
229
241
|
|
|
230
|
-
const domain =
|
|
242
|
+
const domain = wsreq.httpRequest.headers[ "host" ];
|
|
231
243
|
|
|
232
|
-
const socket =
|
|
244
|
+
const socket = wsreq.accept( null, wsreq.origin );
|
|
233
245
|
|
|
234
|
-
const name = "ws-client-"+next_seq();
|
|
246
|
+
const name = "ws-client-"+next_seq(); // XXX just use the websocket id
|
|
235
247
|
|
|
236
248
|
// send msg to connected client
|
|
237
249
|
const send = function( msg , cb ) {
|
|
@@ -250,6 +262,7 @@ const ws_attach = function( httpServer, msg_handler, done ) {
|
|
|
250
262
|
|
|
251
263
|
socket.on("close", function() {
|
|
252
264
|
D( "WS: disconnect" );
|
|
265
|
+
delete ws_connections[ name ]; // remove from tracked connections
|
|
253
266
|
});
|
|
254
267
|
|
|
255
268
|
// incoming msgs from client come through here
|
|
@@ -281,7 +294,7 @@ const ws_attach = function( httpServer, msg_handler, done ) {
|
|
|
281
294
|
|
|
282
295
|
D( "WS: connected: "+name );
|
|
283
296
|
|
|
284
|
-
|
|
297
|
+
ws_connections[ name ] = conn; // add to tracked connections
|
|
285
298
|
|
|
286
299
|
} );
|
|
287
300
|
|
|
@@ -292,36 +305,81 @@ const ws_attach = function( httpServer, msg_handler, done ) {
|
|
|
292
305
|
};
|
|
293
306
|
|
|
294
307
|
|
|
295
|
-
const enable_hot_reload = function( root, conn ) {
|
|
296
|
-
D( "Enabling hot-reload" );
|
|
297
308
|
|
|
298
|
-
|
|
299
|
-
|
|
309
|
+
const build_sass = function( path ) {
|
|
310
|
+
//D( "_________ auto_build sass " + path );
|
|
311
|
+
const sass = require( "sass" );
|
|
312
|
+
const result = sass.compile( path );
|
|
313
|
+
fs.writeFileSync( path + ".css", result.css, "utf8" );
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const auto_builders = [
|
|
317
|
+
[ /\.(sass|scss)$/, build_sass ],
|
|
318
|
+
];
|
|
319
|
+
|
|
320
|
+
// Do auto-build processes (dev mode only)
|
|
321
|
+
const auto_build = function( paths ) {
|
|
322
|
+
|
|
323
|
+
for( let path of paths ) {
|
|
324
|
+
// D( "___ path? " + path );
|
|
325
|
+
for( const bldr of auto_builders ) {
|
|
326
|
+
if( bldr[ 0 ].test( path ) ) {
|
|
327
|
+
bldr[ 1 ]( path );
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
// Engage the filesystem watcher (dev mode only)
|
|
337
|
+
const enable_fs_watch = function( root ) {
|
|
338
|
+
|
|
339
|
+
let paths_noted = {};
|
|
300
340
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
341
|
+
let hot_reload_tid = null;
|
|
342
|
+
let hot_reload_count = 0;
|
|
343
|
+
|
|
344
|
+
function hot_reload_tick() {
|
|
345
|
+
hot_reload_count -= 1; // reduce count by 1
|
|
346
|
+
if( hot_reload_count <= 0 ) {
|
|
304
347
|
// counter reached 0
|
|
305
|
-
clearInterval(
|
|
306
|
-
|
|
307
|
-
|
|
348
|
+
clearInterval( hot_reload_tid ); // turn off the ticker
|
|
349
|
+
hot_reload_tid = null;
|
|
350
|
+
|
|
351
|
+
auto_build( Object.keys( paths_noted ) );
|
|
352
|
+
paths_noted = {};
|
|
353
|
+
|
|
354
|
+
// send RELOAD msg to all client that have an active ws connection
|
|
355
|
+
for( let conn of Object.values( ws_connections ) ) {
|
|
356
|
+
conn.send( { msg: "RELOAD" } ); // send RELOAD msg to browser
|
|
357
|
+
}
|
|
308
358
|
}
|
|
309
359
|
}
|
|
310
360
|
|
|
311
|
-
function
|
|
312
|
-
//
|
|
313
|
-
//
|
|
361
|
+
function note( evt, path ) {
|
|
362
|
+
// A change of some sort was seen
|
|
363
|
+
// Hundreds of these can happen very rapidly, so the timer stuff
|
|
314
364
|
// above is used to delay sending the RELOAD command until
|
|
315
365
|
// a second or so has passed without any more calls to this function
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
//
|
|
319
|
-
|
|
320
|
-
|
|
366
|
+
|
|
367
|
+
paths_noted[ path ] = evt; // XXX
|
|
368
|
+
//D( "noted fs change: [" + evt + "] " + path );
|
|
369
|
+
|
|
370
|
+
hot_reload_count = 5;
|
|
371
|
+
if( hot_reload_tid === null ) {
|
|
372
|
+
// ticker isn't running, so start it
|
|
373
|
+
hot_reload_tid = setInterval( hot_reload_tick, 200 );
|
|
321
374
|
}
|
|
375
|
+
|
|
322
376
|
};
|
|
323
377
|
|
|
324
|
-
|
|
378
|
+
// tell OS to start watching for any changes in root
|
|
379
|
+
fs.watch( root, { recursive: true, }, function( evt, path ) {
|
|
380
|
+
note( evt, root + "/" + path );
|
|
381
|
+
} );
|
|
382
|
+
|
|
325
383
|
};
|
|
326
384
|
|
|
327
385
|
|
|
@@ -354,8 +412,6 @@ if( argv.length == 2 ) {
|
|
|
354
412
|
ws_attach( httpd, ( msg, conn, domain ) => {
|
|
355
413
|
const root = path.resolve( DOMAINS_ROOT + "/" + domain );
|
|
356
414
|
ws_msg_handler( root, msg );
|
|
357
|
-
}, conn => {
|
|
358
|
-
// attachment complete
|
|
359
415
|
} );
|
|
360
416
|
|
|
361
417
|
glx.serveApp( ( req, res ) => {
|
|
@@ -391,16 +447,16 @@ if( argv.length == 5 ) {
|
|
|
391
447
|
rest_handler( SITE_ROOT, req, res );
|
|
392
448
|
} );
|
|
393
449
|
|
|
450
|
+
// XXX call ws_attach *before* calling listen() ?
|
|
394
451
|
httpd.listen( toInt( PORT ), () => {
|
|
395
452
|
|
|
396
453
|
ws_attach( httpd, ( msg, conn, domain ) => {
|
|
397
454
|
ws_msg_handler( SITE_ROOT, msg );
|
|
398
|
-
}, conn => {
|
|
399
|
-
// attachment complete
|
|
400
|
-
enable_hot_reload( SITE_ROOT, conn );
|
|
401
|
-
|
|
402
455
|
} );
|
|
403
456
|
|
|
457
|
+
// enable the file system watch, which handles hot-reload and auto-build
|
|
458
|
+
enable_fs_watch( SITE_ROOT );
|
|
459
|
+
|
|
404
460
|
I( "Listening on " + PORT + " & serving from " + SITE_ROOT );
|
|
405
461
|
|
|
406
462
|
} );
|
package/test.html
DELETED