@caboodle-tech/node-simple-server 4.1.0 → 4.2.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/README.md +26 -3
- package/bin/nss.js +57 -17
- package/bin/print.js +64 -0
- package/changelogs/v4.md +9 -0
- package/handlers/live-reloading.html +3 -2
- package/handlers/websocket-only.html +10 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -87,7 +87,7 @@ function watcherCallback(event, path, extension) {
|
|
|
87
87
|
/**
|
|
88
88
|
* NOTE: This is a heavy request to use if your site loads resources from
|
|
89
89
|
* other sites such as images, databases, or API calls. Consider a better
|
|
90
|
-
* approach in
|
|
90
|
+
* approach in these cases such as throttling.
|
|
91
91
|
*/
|
|
92
92
|
Server.reloadAllPages();
|
|
93
93
|
return;
|
|
@@ -97,7 +97,13 @@ function watcherCallback(event, path, extension) {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
/**
|
|
101
|
+
* A bare minimum callback to handle all websocket messages from the frontend. By
|
|
102
|
+
* default NSS registers and responds to WebSockets by the web pages pathname. In
|
|
103
|
+
* a web page:
|
|
104
|
+
*
|
|
105
|
+
* NSS_WS.send([string|int|bool|object]) // Pathname lookup will be used.
|
|
106
|
+
*/
|
|
101
107
|
function websocketCallback(messageObject, pageId) {
|
|
102
108
|
// Interpret and do what you need to with the message:
|
|
103
109
|
const datatype = messageObject.type
|
|
@@ -107,9 +113,26 @@ function websocketCallback(messageObject, pageId) {
|
|
|
107
113
|
// Respond to the page that sent the message if you like:
|
|
108
114
|
Server.message(pageId, 'Messaged received!');
|
|
109
115
|
}
|
|
110
|
-
|
|
111
116
|
Server.addWebsocketCallback('.*', websocketCallback);
|
|
112
117
|
|
|
118
|
+
/**
|
|
119
|
+
* A bare minimum callback to handle all websocket messages from the frontend.
|
|
120
|
+
* This is a special example that registers a specific route to listen for. In a
|
|
121
|
+
* web page:
|
|
122
|
+
*
|
|
123
|
+
* NSS_WS.send([string|int|bool|object], [route string]) // Route lookup will be used.
|
|
124
|
+
*/
|
|
125
|
+
function websocketCallback(messageObject, pageId) {
|
|
126
|
+
// Interpret and do what you need to with the message:
|
|
127
|
+
const datatype = messageObject.type
|
|
128
|
+
const data = messageObject.data;
|
|
129
|
+
console.log(`Route received ${datatype} data from page ${pageId}: ${data}`)
|
|
130
|
+
|
|
131
|
+
// Respond to the page that sent the message if you like:
|
|
132
|
+
Server.message(pageId, 'Route specific messaged received!');
|
|
133
|
+
}
|
|
134
|
+
Server.addWebsocketCallback('api/search', websocketCallback);
|
|
135
|
+
|
|
113
136
|
// A bare minimum watcher options object; use for development, omit for production.
|
|
114
137
|
const watcherOptions = {
|
|
115
138
|
events: {
|
package/bin/nss.js
CHANGED
|
@@ -8,6 +8,7 @@ import { fileURLToPath } from 'url';
|
|
|
8
8
|
|
|
9
9
|
import ContentTypes from '../handlers/js/content-types.js';
|
|
10
10
|
import HTTPStatus from '../handlers/js/http-status.js';
|
|
11
|
+
import Print from './print.js';
|
|
11
12
|
|
|
12
13
|
// eslint-disable-next-line no-underscore-dangle
|
|
13
14
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -43,7 +44,7 @@ class NodeSimpleServer {
|
|
|
43
44
|
map: {}
|
|
44
45
|
};
|
|
45
46
|
|
|
46
|
-
#VERSION = '4.
|
|
47
|
+
#VERSION = '4.2.0';
|
|
47
48
|
|
|
48
49
|
#watching = [];
|
|
49
50
|
|
|
@@ -730,7 +731,6 @@ class NodeSimpleServer {
|
|
|
730
731
|
* @param {object} request The incoming initial connection.
|
|
731
732
|
*/
|
|
732
733
|
#socketListener(socket, request) {
|
|
733
|
-
|
|
734
734
|
// Strip the page ID and /ws tag off the url to get the actual url.
|
|
735
735
|
let cleanURL = request.url.substr(1, request.url.indexOf('/ws?id=') - 1);
|
|
736
736
|
if (!cleanURL) {
|
|
@@ -749,7 +749,20 @@ class NodeSimpleServer {
|
|
|
749
749
|
}
|
|
750
750
|
|
|
751
751
|
// Record the unique page ID directly on the socket object.
|
|
752
|
-
|
|
752
|
+
let idStartIndex;
|
|
753
|
+
if (request.url.indexOf('?id=') !== -1) {
|
|
754
|
+
idStartIndex = request.url.indexOf('?id=');
|
|
755
|
+
} else {
|
|
756
|
+
idStartIndex = -1;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
let pageId;
|
|
760
|
+
if (idStartIndex !== -1) {
|
|
761
|
+
pageId = request.url.substr(idStartIndex).replace('?id=', '');
|
|
762
|
+
} else {
|
|
763
|
+
pageId = 'unknown';
|
|
764
|
+
}
|
|
765
|
+
|
|
753
766
|
// eslint-disable-next-line no-param-reassign
|
|
754
767
|
socket.nssUid = pageId;
|
|
755
768
|
|
|
@@ -779,7 +792,17 @@ class NodeSimpleServer {
|
|
|
779
792
|
// Handle future incoming WebSocket messages from this page.
|
|
780
793
|
socket.on('message', (message) => {
|
|
781
794
|
// NSS messages have a standard format.
|
|
782
|
-
|
|
795
|
+
let msgObj;
|
|
796
|
+
try {
|
|
797
|
+
msgObj = JSON.parse(message.toString());
|
|
798
|
+
if (!('message' in msgObj) || !('type' in msgObj)) {
|
|
799
|
+
throw new Error('Bad format!');
|
|
800
|
+
}
|
|
801
|
+
} catch (e) {
|
|
802
|
+
Print.warn('Invalid socket message received! Socket message must be in Node Simple Server\'s format.');
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
|
|
783
806
|
// If message is a ping send pong and stop.
|
|
784
807
|
if (msgObj.type === 'string') {
|
|
785
808
|
if (msgObj.message === 'ping') {
|
|
@@ -787,17 +810,32 @@ class NodeSimpleServer {
|
|
|
787
810
|
return;
|
|
788
811
|
}
|
|
789
812
|
}
|
|
813
|
+
|
|
814
|
+
// Pull out specific route if there is one.
|
|
815
|
+
let route = null;
|
|
816
|
+
if ('route' in msgObj) {
|
|
817
|
+
route = msgObj.route;
|
|
818
|
+
}
|
|
819
|
+
|
|
790
820
|
// See if the message belongs to a callback and send it there.
|
|
791
821
|
for (let i = 0; i < this.#OPS.callbacks.length; i++) {
|
|
792
822
|
const regex = this.#OPS.callbacks[i][0];
|
|
793
823
|
const callback = this.#OPS.callbacks[i][1];
|
|
794
|
-
|
|
824
|
+
// If the message has a route check that only.
|
|
825
|
+
if (route) {
|
|
826
|
+
if (regex.test(route)) {
|
|
827
|
+
callback(msgObj, pageId);
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
} else if (regex.test(cleanURL)) {
|
|
831
|
+
// Default to the URL (pathname).
|
|
795
832
|
callback(msgObj, pageId);
|
|
796
833
|
return;
|
|
797
834
|
}
|
|
798
835
|
}
|
|
836
|
+
|
|
799
837
|
// No one is listening for this message.
|
|
800
|
-
|
|
838
|
+
Print.warn(`Unanswered WebSocket message from ${cleanURL}: ${message.toString()}`);
|
|
801
839
|
});
|
|
802
840
|
|
|
803
841
|
// When a connection closes remove it from CONNECTIONS.
|
|
@@ -813,6 +851,7 @@ class NodeSimpleServer {
|
|
|
813
851
|
}
|
|
814
852
|
});
|
|
815
853
|
|
|
854
|
+
console.log(this.#OPS.callbacks);
|
|
816
855
|
}
|
|
817
856
|
|
|
818
857
|
/**
|
|
@@ -842,7 +881,7 @@ class NodeSimpleServer {
|
|
|
842
881
|
|
|
843
882
|
// Don't start an already running server.
|
|
844
883
|
if (this.#OPS.running) {
|
|
845
|
-
|
|
884
|
+
Print.warn('Server is already running.');
|
|
846
885
|
// Notify the callback.
|
|
847
886
|
if (callback) {
|
|
848
887
|
callback(true);
|
|
@@ -878,7 +917,8 @@ class NodeSimpleServer {
|
|
|
878
917
|
if (port) {
|
|
879
918
|
// Stop trying new ports after 100 attempts.
|
|
880
919
|
if (this.#OPS.port - port > 100) {
|
|
881
|
-
|
|
920
|
+
// eslint-disable-next-line max-len
|
|
921
|
+
Print.error(`FATAL ERROR: Could not find an available port number in the range of ${this.#OPS.port}–${this.#OPS.port + 100}.`);
|
|
882
922
|
// Notify the callback.
|
|
883
923
|
if (callback) {
|
|
884
924
|
callback(false);
|
|
@@ -891,7 +931,7 @@ class NodeSimpleServer {
|
|
|
891
931
|
}
|
|
892
932
|
return;
|
|
893
933
|
}
|
|
894
|
-
|
|
934
|
+
Print.error(`Server Error:\n${error}`);
|
|
895
935
|
});
|
|
896
936
|
|
|
897
937
|
// Attempt to start the server now.
|
|
@@ -907,19 +947,19 @@ class NodeSimpleServer {
|
|
|
907
947
|
|
|
908
948
|
// Warn the user if we had to change port numbers.
|
|
909
949
|
if (port && (port !== this.#OPS.port)) {
|
|
910
|
-
|
|
950
|
+
Print.warn(`Port ${this.#OPS.port} was in use, switched to using ${port}.\n`);
|
|
911
951
|
}
|
|
912
952
|
|
|
913
953
|
// Record port in use.
|
|
914
954
|
this.#OPS.portInUse = port;
|
|
915
955
|
|
|
916
956
|
// Log the ip addresses being watched.
|
|
917
|
-
|
|
957
|
+
Print.notice('Node Simple Server live @:');
|
|
918
958
|
const addresses = this.getAddresses(port);
|
|
919
959
|
addresses.forEach((address) => {
|
|
920
|
-
|
|
960
|
+
Print.notice(` ${address}`);
|
|
921
961
|
});
|
|
922
|
-
|
|
962
|
+
Print.log('');
|
|
923
963
|
|
|
924
964
|
// Notify the callback.
|
|
925
965
|
if (callback) {
|
|
@@ -953,7 +993,7 @@ class NodeSimpleServer {
|
|
|
953
993
|
this.#server = null;
|
|
954
994
|
this.#socket = null;
|
|
955
995
|
this.#OPS.running = false;
|
|
956
|
-
|
|
996
|
+
Print.notice('Server has been stopped.');
|
|
957
997
|
}
|
|
958
998
|
// Notify the callback.
|
|
959
999
|
if (callback) {
|
|
@@ -1031,7 +1071,7 @@ class NodeSimpleServer {
|
|
|
1031
1071
|
* all backslashes (\) into forward slashes (/).
|
|
1032
1072
|
*/
|
|
1033
1073
|
if (alterCatachAlls.includes(key)) {
|
|
1034
|
-
watcher.on(key, (evt, path, statsOrDetails) => {
|
|
1074
|
+
watcher.on(key, (evt, path, statsOrDetails = {}) => {
|
|
1035
1075
|
// Capture the call and alter the path before passing it on.
|
|
1036
1076
|
const altPath = path.replace(/\\/g, '/');
|
|
1037
1077
|
// Since we're messing with the path already grab the extension for the user.
|
|
@@ -1040,7 +1080,7 @@ class NodeSimpleServer {
|
|
|
1040
1080
|
options.events[key](evt, altPath, statsOrDetails);
|
|
1041
1081
|
});
|
|
1042
1082
|
} else if (alterAddUpdates.includes(key)) {
|
|
1043
|
-
watcher.on(key, (path, statsOrDetails) => {
|
|
1083
|
+
watcher.on(key, (path, statsOrDetails = {}) => {
|
|
1044
1084
|
// Capture the call and alter the path before passing it on.
|
|
1045
1085
|
const altPath = path.replace(/\\/g, '/');
|
|
1046
1086
|
// Since we're messing with the path already grab the extension for the user.
|
|
@@ -1061,7 +1101,7 @@ class NodeSimpleServer {
|
|
|
1061
1101
|
}
|
|
1062
1102
|
});
|
|
1063
1103
|
} catch (error) {
|
|
1064
|
-
|
|
1104
|
+
Print.error(error);
|
|
1065
1105
|
return false;
|
|
1066
1106
|
}
|
|
1067
1107
|
return true;
|
package/bin/print.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
class Print {
|
|
4
|
+
|
|
5
|
+
#enabled = true;
|
|
6
|
+
|
|
7
|
+
disable() {
|
|
8
|
+
this.#enabled = false;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
enable() {
|
|
12
|
+
this.#enabled = true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
error(message, override = false) {
|
|
16
|
+
if (!this.#enabled && !override) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
// Red color
|
|
20
|
+
console.error(this.#formatMessage(message, '\x1b[31m'));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#formatMessage(message, colorCode) {
|
|
24
|
+
const resetCode = '\x1b[0m';
|
|
25
|
+
return `${colorCode}${message}${resetCode}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
log(message, override = false) {
|
|
29
|
+
if (!this.#enabled && !override) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// White color
|
|
33
|
+
console.log(this.#formatMessage(message, '\x1b[37m'));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
notice(message, override = false) {
|
|
37
|
+
if (!this.#enabled && !override) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Blue color
|
|
41
|
+
console.log(this.#formatMessage(message, '\x1b[94m'));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
success(message, override = false) {
|
|
45
|
+
if (!this.#enabled && !override) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// Green color
|
|
49
|
+
console.log(this.#formatMessage(message, '\x1b[32m'));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
warn(message, override = false) {
|
|
53
|
+
if (!this.#enabled && !override) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Yellow color
|
|
57
|
+
console.warn(this.#formatMessage(message, '\x1b[33m'));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const printer = new Print();
|
|
63
|
+
|
|
64
|
+
export default printer;
|
package/changelogs/v4.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
### NSS 4.2.0 (23 January 2024)
|
|
2
|
+
|
|
3
|
+
- feat: WebSocket connections can now specify a specific backend route instead of just sending messages to the the listener (if any) for the pages path.
|
|
4
|
+
|
|
5
|
+
### NSS 4.1.1 (22 January 2024)
|
|
6
|
+
|
|
7
|
+
- fix: Correct a bug in the watcher where we attach a files extension to the stats object. This object is missing when moving directories causing a crash since there is no object to attach the extension, albeit non-existent, to.
|
|
8
|
+
- improve: Quality of life improvement by adding the Caboodle Tech Print class to replace console output; Now in color!
|
|
9
|
+
|
|
1
10
|
### NSS 4.0.0 (7 January 2024)
|
|
2
11
|
|
|
3
12
|
- !feat: Correct bug caused by NSS non-standard implementation of Chokidar; see below.
|
|
@@ -91,10 +91,11 @@
|
|
|
91
91
|
};
|
|
92
92
|
|
|
93
93
|
/** Send a WebSocket message to the WebSocket server. */
|
|
94
|
-
const send = (message) => {
|
|
94
|
+
const send = (message, route = null) => {
|
|
95
95
|
if (ready && socket.readyState === WebSocket.OPEN) {
|
|
96
96
|
socket.send(JSON.stringify({
|
|
97
97
|
message,
|
|
98
|
+
route,
|
|
98
99
|
type: whatIs(message)
|
|
99
100
|
}));
|
|
100
101
|
return;
|
|
@@ -147,7 +148,7 @@
|
|
|
147
148
|
|
|
148
149
|
// Socket specific variables.
|
|
149
150
|
const protocol = window.location.protocol === "http:" ? "ws://" : "wss://";
|
|
150
|
-
const address = protocol + window.location.host +
|
|
151
|
+
const address = protocol + window.location.host + pathname + "/ws?id=" + pageId;
|
|
151
152
|
const socket = new WebSocket(address);
|
|
152
153
|
|
|
153
154
|
// Respond to messages the socket receives.
|
|
@@ -42,15 +42,16 @@
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
/** Send a WebSocket message to the WebSocket server. */
|
|
45
|
-
const send = (message) => {
|
|
45
|
+
const send = (message, route = null) => {
|
|
46
46
|
if (ready && socket.readyState === WebSocket.OPEN) {
|
|
47
47
|
socket.send(JSON.stringify({
|
|
48
48
|
message,
|
|
49
|
+
route,
|
|
49
50
|
type: whatIs(message)
|
|
50
51
|
}));
|
|
51
52
|
return;
|
|
52
53
|
}
|
|
53
|
-
console.warn(
|
|
54
|
+
console.warn('Node Simple Server: The WebSocket is not ready or the connection was closed.');
|
|
54
55
|
};
|
|
55
56
|
|
|
56
57
|
/** Generate a random unique ID for this page; will be registered in the back-end. */
|
|
@@ -90,9 +91,15 @@
|
|
|
90
91
|
let restartAttempts = 0;
|
|
91
92
|
let restartInterval = null;
|
|
92
93
|
|
|
94
|
+
// Prep window path.
|
|
95
|
+
let pathname = window.location.pathname;
|
|
96
|
+
if (pathname === '/') {
|
|
97
|
+
pathname = '';
|
|
98
|
+
}
|
|
99
|
+
|
|
93
100
|
// Socket specific variables.
|
|
94
101
|
const protocol = window.location.protocol === "http:" ? "ws://" : "wss://";
|
|
95
|
-
const address = protocol + window.location.host +
|
|
102
|
+
const address = protocol + window.location.host + pathname + "/ws?id=" + pageId;
|
|
96
103
|
const socket = new WebSocket(address);
|
|
97
104
|
|
|
98
105
|
// Respond to messages the socket receives.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caboodle-tech/node-simple-server",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Node Simple Server (NSS): A small but effective node based server for development sites, customizable live reloading, and websocket support built-in.",
|
|
5
5
|
"main": "bin/nss.js",
|
|
6
6
|
"scripts": {
|