roster-server 1.8.2 â 1.8.6
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 +25 -0
- package/demo/package-lock.json +252 -0
- package/demo/package.json +15 -0
- package/demo/socketio.js +28 -0
- package/index.js +49 -20
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -162,6 +162,31 @@ When creating a new `RosterServer` instance, you can pass the following options:
|
|
|
162
162
|
- `wwwPath` (string): Path to your `www` directory containing your sites.
|
|
163
163
|
- `greenlockStorePath` (string): Directory for Greenlock configuration.
|
|
164
164
|
- `staging` (boolean): Set to `true` to use Let's Encrypt's staging environment (for testing).
|
|
165
|
+
- `local` (boolean): Set to `true` to run in local development mode.
|
|
166
|
+
|
|
167
|
+
## đ Local Development Mode
|
|
168
|
+
|
|
169
|
+
For local development and testing, you can run RosterServer in local mode by setting `local: true`. This mode is perfect for development environments where you don't need SSL certificates or production features.
|
|
170
|
+
|
|
171
|
+
When `{ local: true }` is enabled, RosterServer **Skips SSL/HTTPS**: Runs pure HTTP servers instead of HTTPS.
|
|
172
|
+
|
|
173
|
+
### Setting Up Local Mode
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
const server = new Roster({
|
|
177
|
+
wwwPath: '/srv/www',
|
|
178
|
+
local: true // Enable local development mode
|
|
179
|
+
});
|
|
180
|
+
server.start();
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Port Assignment
|
|
184
|
+
|
|
185
|
+
In local mode, domains are automatically assigned ports starting from 3000:
|
|
186
|
+
|
|
187
|
+
- `example.com` â `http://localhost:3000`
|
|
188
|
+
- `api.example.com` â `http://localhost:3001`
|
|
189
|
+
- And so on...
|
|
165
190
|
|
|
166
191
|
## đ§ A Touch of Magic
|
|
167
192
|
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "demo",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "demo",
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"socket.io": "^4.8.1"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"node_modules/@socket.io/component-emitter": {
|
|
16
|
+
"version": "3.1.2",
|
|
17
|
+
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
|
18
|
+
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
|
|
19
|
+
"license": "MIT"
|
|
20
|
+
},
|
|
21
|
+
"node_modules/@types/cors": {
|
|
22
|
+
"version": "2.8.19",
|
|
23
|
+
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
|
|
24
|
+
"integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@types/node": "*"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"node_modules/@types/node": {
|
|
31
|
+
"version": "24.10.2",
|
|
32
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.2.tgz",
|
|
33
|
+
"integrity": "sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"undici-types": "~7.16.0"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"node_modules/accepts": {
|
|
40
|
+
"version": "1.3.8",
|
|
41
|
+
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
|
42
|
+
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"mime-types": "~2.1.34",
|
|
46
|
+
"negotiator": "0.6.3"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">= 0.6"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"node_modules/base64id": {
|
|
53
|
+
"version": "2.0.0",
|
|
54
|
+
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
|
55
|
+
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
|
|
56
|
+
"license": "MIT",
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": "^4.5.0 || >= 5.9"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"node_modules/cookie": {
|
|
62
|
+
"version": "0.7.2",
|
|
63
|
+
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
|
64
|
+
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
|
65
|
+
"license": "MIT",
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">= 0.6"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"node_modules/cors": {
|
|
71
|
+
"version": "2.8.5",
|
|
72
|
+
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
|
73
|
+
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
|
74
|
+
"license": "MIT",
|
|
75
|
+
"dependencies": {
|
|
76
|
+
"object-assign": "^4",
|
|
77
|
+
"vary": "^1"
|
|
78
|
+
},
|
|
79
|
+
"engines": {
|
|
80
|
+
"node": ">= 0.10"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"node_modules/debug": {
|
|
84
|
+
"version": "4.3.7",
|
|
85
|
+
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
|
86
|
+
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
|
87
|
+
"license": "MIT",
|
|
88
|
+
"dependencies": {
|
|
89
|
+
"ms": "^2.1.3"
|
|
90
|
+
},
|
|
91
|
+
"engines": {
|
|
92
|
+
"node": ">=6.0"
|
|
93
|
+
},
|
|
94
|
+
"peerDependenciesMeta": {
|
|
95
|
+
"supports-color": {
|
|
96
|
+
"optional": true
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"node_modules/engine.io": {
|
|
101
|
+
"version": "6.6.4",
|
|
102
|
+
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
|
|
103
|
+
"integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
|
|
104
|
+
"license": "MIT",
|
|
105
|
+
"dependencies": {
|
|
106
|
+
"@types/cors": "^2.8.12",
|
|
107
|
+
"@types/node": ">=10.0.0",
|
|
108
|
+
"accepts": "~1.3.4",
|
|
109
|
+
"base64id": "2.0.0",
|
|
110
|
+
"cookie": "~0.7.2",
|
|
111
|
+
"cors": "~2.8.5",
|
|
112
|
+
"debug": "~4.3.1",
|
|
113
|
+
"engine.io-parser": "~5.2.1",
|
|
114
|
+
"ws": "~8.17.1"
|
|
115
|
+
},
|
|
116
|
+
"engines": {
|
|
117
|
+
"node": ">=10.2.0"
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"node_modules/engine.io-parser": {
|
|
121
|
+
"version": "5.2.3",
|
|
122
|
+
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
|
123
|
+
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
|
|
124
|
+
"license": "MIT",
|
|
125
|
+
"engines": {
|
|
126
|
+
"node": ">=10.0.0"
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"node_modules/mime-db": {
|
|
130
|
+
"version": "1.52.0",
|
|
131
|
+
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
|
132
|
+
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
|
133
|
+
"license": "MIT",
|
|
134
|
+
"engines": {
|
|
135
|
+
"node": ">= 0.6"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"node_modules/mime-types": {
|
|
139
|
+
"version": "2.1.35",
|
|
140
|
+
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
|
141
|
+
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
|
142
|
+
"license": "MIT",
|
|
143
|
+
"dependencies": {
|
|
144
|
+
"mime-db": "1.52.0"
|
|
145
|
+
},
|
|
146
|
+
"engines": {
|
|
147
|
+
"node": ">= 0.6"
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
"node_modules/ms": {
|
|
151
|
+
"version": "2.1.3",
|
|
152
|
+
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
153
|
+
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
|
154
|
+
"license": "MIT"
|
|
155
|
+
},
|
|
156
|
+
"node_modules/negotiator": {
|
|
157
|
+
"version": "0.6.3",
|
|
158
|
+
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
|
159
|
+
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
|
|
160
|
+
"license": "MIT",
|
|
161
|
+
"engines": {
|
|
162
|
+
"node": ">= 0.6"
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"node_modules/object-assign": {
|
|
166
|
+
"version": "4.1.1",
|
|
167
|
+
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
|
168
|
+
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
|
169
|
+
"license": "MIT",
|
|
170
|
+
"engines": {
|
|
171
|
+
"node": ">=0.10.0"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"node_modules/socket.io": {
|
|
175
|
+
"version": "4.8.1",
|
|
176
|
+
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
|
|
177
|
+
"integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
|
|
178
|
+
"license": "MIT",
|
|
179
|
+
"dependencies": {
|
|
180
|
+
"accepts": "~1.3.4",
|
|
181
|
+
"base64id": "~2.0.0",
|
|
182
|
+
"cors": "~2.8.5",
|
|
183
|
+
"debug": "~4.3.2",
|
|
184
|
+
"engine.io": "~6.6.0",
|
|
185
|
+
"socket.io-adapter": "~2.5.2",
|
|
186
|
+
"socket.io-parser": "~4.2.4"
|
|
187
|
+
},
|
|
188
|
+
"engines": {
|
|
189
|
+
"node": ">=10.2.0"
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"node_modules/socket.io-adapter": {
|
|
193
|
+
"version": "2.5.5",
|
|
194
|
+
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
|
|
195
|
+
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
|
|
196
|
+
"license": "MIT",
|
|
197
|
+
"dependencies": {
|
|
198
|
+
"debug": "~4.3.4",
|
|
199
|
+
"ws": "~8.17.1"
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"node_modules/socket.io-parser": {
|
|
203
|
+
"version": "4.2.4",
|
|
204
|
+
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
|
205
|
+
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
|
206
|
+
"license": "MIT",
|
|
207
|
+
"dependencies": {
|
|
208
|
+
"@socket.io/component-emitter": "~3.1.0",
|
|
209
|
+
"debug": "~4.3.1"
|
|
210
|
+
},
|
|
211
|
+
"engines": {
|
|
212
|
+
"node": ">=10.0.0"
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
"node_modules/undici-types": {
|
|
216
|
+
"version": "7.16.0",
|
|
217
|
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
|
218
|
+
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
|
219
|
+
"license": "MIT"
|
|
220
|
+
},
|
|
221
|
+
"node_modules/vary": {
|
|
222
|
+
"version": "1.1.2",
|
|
223
|
+
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
|
224
|
+
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
|
225
|
+
"license": "MIT",
|
|
226
|
+
"engines": {
|
|
227
|
+
"node": ">= 0.8"
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
"node_modules/ws": {
|
|
231
|
+
"version": "8.17.1",
|
|
232
|
+
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
|
233
|
+
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
|
234
|
+
"license": "MIT",
|
|
235
|
+
"engines": {
|
|
236
|
+
"node": ">=10.0.0"
|
|
237
|
+
},
|
|
238
|
+
"peerDependencies": {
|
|
239
|
+
"bufferutil": "^4.0.1",
|
|
240
|
+
"utf-8-validate": ">=5.0.2"
|
|
241
|
+
},
|
|
242
|
+
"peerDependenciesMeta": {
|
|
243
|
+
"bufferutil": {
|
|
244
|
+
"optional": true
|
|
245
|
+
},
|
|
246
|
+
"utf-8-validate": {
|
|
247
|
+
"optional": true
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "demo",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"socket.io": "^4.8.1"
|
|
14
|
+
}
|
|
15
|
+
}
|
package/demo/socketio.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const Roster = require('../index.js');
|
|
2
|
+
const { Server } = require('socket.io');
|
|
3
|
+
|
|
4
|
+
const roster = new Roster({ local: true });
|
|
5
|
+
|
|
6
|
+
roster.register('example.com', (httpsServer) => {
|
|
7
|
+
const io = new Server(httpsServer);
|
|
8
|
+
|
|
9
|
+
io.on('connection', (socket) => {
|
|
10
|
+
console.log('A user connected');
|
|
11
|
+
|
|
12
|
+
socket.on('chat:message', (msg) => {
|
|
13
|
+
console.log('Message received:', msg);
|
|
14
|
+
io.emit('chat:message', msg);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
socket.on('disconnect', () => {
|
|
18
|
+
console.log('User disconnected');
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return (req, res) => {
|
|
23
|
+
res.writeHead(404);
|
|
24
|
+
res.end('Not found');
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
roster.start();
|
package/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const https = require('https');
|
|
|
5
5
|
const tls = require('tls');
|
|
6
6
|
const { EventEmitter } = require('events');
|
|
7
7
|
const Greenlock = require('greenlock-express');
|
|
8
|
+
const log = require('lemonlog')('roster');
|
|
8
9
|
|
|
9
10
|
// Virtual Server that completely isolates applications
|
|
10
11
|
class VirtualServer extends EventEmitter {
|
|
@@ -66,8 +67,31 @@ class VirtualServer extends EventEmitter {
|
|
|
66
67
|
|
|
67
68
|
// Process request with this virtual server's listeners
|
|
68
69
|
processRequest(req, res) {
|
|
70
|
+
let handled = false;
|
|
71
|
+
|
|
72
|
+
// Track if response was handled
|
|
73
|
+
const originalEnd = res.end;
|
|
74
|
+
res.end = function(...args) {
|
|
75
|
+
handled = true;
|
|
76
|
+
return originalEnd.apply(this, args);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Try all listeners
|
|
69
80
|
for (const listener of this.requestListeners) {
|
|
70
|
-
|
|
81
|
+
if (!handled) {
|
|
82
|
+
listener(req, res);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Restore original end method
|
|
87
|
+
res.end = originalEnd;
|
|
88
|
+
|
|
89
|
+
// If no listener handled the request, try fallback handler
|
|
90
|
+
if (!handled && this.fallbackHandler) {
|
|
91
|
+
this.fallbackHandler(req, res);
|
|
92
|
+
} else if (!handled) {
|
|
93
|
+
res.writeHead(404);
|
|
94
|
+
res.end('No handler found');
|
|
71
95
|
}
|
|
72
96
|
}
|
|
73
97
|
}
|
|
@@ -80,7 +104,7 @@ class Roster {
|
|
|
80
104
|
this.greenlockStorePath = options.greenlockStorePath || path.join(basePath, 'greenlock.d');
|
|
81
105
|
this.staging = options.staging || false;
|
|
82
106
|
this.cluster = options.cluster || false;
|
|
83
|
-
this.local = options.local || false;
|
|
107
|
+
this.local = options.local || false;
|
|
84
108
|
this.domains = [];
|
|
85
109
|
this.sites = {};
|
|
86
110
|
this.domainServers = {}; // Store separate servers for each domain
|
|
@@ -98,7 +122,7 @@ class Roster {
|
|
|
98
122
|
async loadSites() {
|
|
99
123
|
// Check if wwwPath exists
|
|
100
124
|
if (!fs.existsSync(this.wwwPath)) {
|
|
101
|
-
|
|
125
|
+
log.warn(`â ī¸ WWW path does not exist: ${this.wwwPath}`);
|
|
102
126
|
return;
|
|
103
127
|
}
|
|
104
128
|
|
|
@@ -125,7 +149,7 @@ class Roster {
|
|
|
125
149
|
siteApp = siteApp.default || siteApp;
|
|
126
150
|
break;
|
|
127
151
|
} catch (err) {
|
|
128
|
-
|
|
152
|
+
log.warn(`â ī¸ Error loading ${indexPath}:`, err);
|
|
129
153
|
}
|
|
130
154
|
}
|
|
131
155
|
}
|
|
@@ -137,9 +161,9 @@ class Roster {
|
|
|
137
161
|
this.sites[d] = siteApp;
|
|
138
162
|
});
|
|
139
163
|
|
|
140
|
-
|
|
164
|
+
log.info(`(â) Loaded site: https://${domain}`);
|
|
141
165
|
} else {
|
|
142
|
-
|
|
166
|
+
log.warn(`â ī¸ No index file (js/mjs/cjs) found in ${domainPath}`);
|
|
143
167
|
}
|
|
144
168
|
}
|
|
145
169
|
}
|
|
@@ -217,16 +241,16 @@ class Roster {
|
|
|
217
241
|
const currentConfigContentFormatted = JSON.stringify(currentConfig, null, 2);
|
|
218
242
|
|
|
219
243
|
if (newConfigContent === currentConfigContentFormatted) {
|
|
220
|
-
|
|
244
|
+
log.info('âšī¸ Configuration has not changed. config.json will not be overwritten.');
|
|
221
245
|
return;
|
|
222
246
|
}
|
|
223
|
-
|
|
247
|
+
log.info('đ Configuration has changed. config.json will be updated.');
|
|
224
248
|
} else {
|
|
225
|
-
|
|
249
|
+
log.info('đ config.json does not exist. A new one will be created.');
|
|
226
250
|
}
|
|
227
251
|
|
|
228
252
|
fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2));
|
|
229
|
-
|
|
253
|
+
log.info(`đ config.json generated at ${configPath}`);
|
|
230
254
|
}
|
|
231
255
|
|
|
232
256
|
handleRequest(req, res) {
|
|
@@ -270,7 +294,7 @@ class Roster {
|
|
|
270
294
|
this.sites[domainKey] = requestHandler;
|
|
271
295
|
});
|
|
272
296
|
|
|
273
|
-
|
|
297
|
+
log.info(`(â) Registered site: ${domain}${port !== this.defaultPort ? ':' + port : ''}`);
|
|
274
298
|
return this;
|
|
275
299
|
}
|
|
276
300
|
|
|
@@ -334,6 +358,9 @@ class Roster {
|
|
|
334
358
|
|
|
335
359
|
// Create simple dispatcher for this domain
|
|
336
360
|
const dispatcher = (req, res) => {
|
|
361
|
+
// Set fallback handler on virtual server for non-Socket.IO requests
|
|
362
|
+
virtualServer.fallbackHandler = appHandler;
|
|
363
|
+
|
|
337
364
|
if (virtualServer.requestListeners.length > 0) {
|
|
338
365
|
virtualServer.processRequest(req, res);
|
|
339
366
|
} else if (appHandler) {
|
|
@@ -349,17 +376,17 @@ class Roster {
|
|
|
349
376
|
this.portServers[port] = httpServer;
|
|
350
377
|
|
|
351
378
|
httpServer.listen(port, 'localhost', () => {
|
|
352
|
-
|
|
379
|
+
log.info(`đ ${domain} â http://localhost:${port}`);
|
|
353
380
|
});
|
|
354
381
|
|
|
355
382
|
httpServer.on('error', (error) => {
|
|
356
|
-
|
|
383
|
+
log.error(`â Error on port ${port} for ${domain}:`, error.message);
|
|
357
384
|
});
|
|
358
385
|
|
|
359
386
|
currentPort++;
|
|
360
387
|
}
|
|
361
388
|
|
|
362
|
-
|
|
389
|
+
log.info(`(â) Started ${currentPort - startPort} sites in local mode`);
|
|
363
390
|
return Promise.resolve();
|
|
364
391
|
}
|
|
365
392
|
|
|
@@ -431,6 +458,8 @@ class Roster {
|
|
|
431
458
|
const appHandler = portData.appHandlers[domain];
|
|
432
459
|
|
|
433
460
|
if (virtualServer && virtualServer.requestListeners.length > 0) {
|
|
461
|
+
// Set fallback handler on virtual server for non-Socket.IO requests
|
|
462
|
+
virtualServer.fallbackHandler = appHandler;
|
|
434
463
|
// App registered listeners on virtual server - use them
|
|
435
464
|
virtualServer.processRequest(req, res);
|
|
436
465
|
} else if (appHandler) {
|
|
@@ -444,7 +473,7 @@ class Roster {
|
|
|
444
473
|
};
|
|
445
474
|
|
|
446
475
|
httpServer.listen(80, this.hostname, () => {
|
|
447
|
-
|
|
476
|
+
log.info('HTTP server listening on port 80');
|
|
448
477
|
});
|
|
449
478
|
|
|
450
479
|
// Handle different port types
|
|
@@ -458,7 +487,7 @@ class Roster {
|
|
|
458
487
|
this.portServers[portNum] = httpsServer;
|
|
459
488
|
|
|
460
489
|
httpsServer.listen(portNum, this.hostname, () => {
|
|
461
|
-
|
|
490
|
+
log.info(`HTTPS server listening on port ${portNum}`);
|
|
462
491
|
});
|
|
463
492
|
} else {
|
|
464
493
|
// Create HTTPS server for custom ports using Greenlock certificates
|
|
@@ -492,13 +521,13 @@ class Roster {
|
|
|
492
521
|
const httpsServer = https.createServer(httpsOptions, dispatcher);
|
|
493
522
|
|
|
494
523
|
httpsServer.on('error', (error) => {
|
|
495
|
-
|
|
524
|
+
log.error(`HTTPS server error on port ${portNum}:`, error.message);
|
|
496
525
|
});
|
|
497
526
|
|
|
498
527
|
httpsServer.on('tlsClientError', (error) => {
|
|
499
528
|
// Suppress HTTP request errors to avoid log spam
|
|
500
529
|
if (!error.message.includes('http request')) {
|
|
501
|
-
|
|
530
|
+
log.error(`TLS error on port ${portNum}:`, error.message);
|
|
502
531
|
}
|
|
503
532
|
});
|
|
504
533
|
|
|
@@ -506,9 +535,9 @@ class Roster {
|
|
|
506
535
|
|
|
507
536
|
httpsServer.listen(portNum, this.hostname, (error) => {
|
|
508
537
|
if (error) {
|
|
509
|
-
|
|
538
|
+
log.error(`Failed to start HTTPS server on port ${portNum}:`, error.message);
|
|
510
539
|
} else {
|
|
511
|
-
|
|
540
|
+
log.info(`HTTPS server listening on port ${portNum}`);
|
|
512
541
|
}
|
|
513
542
|
});
|
|
514
543
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roster-server",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.6",
|
|
4
4
|
"description": "đž RosterServer - A domain host router to host multiple HTTPS.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"homepage": "https://github.com/clasen/RosterServer#readme",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"greenlock-express": "^4.0.3"
|
|
37
|
+
"greenlock-express": "^4.0.3",
|
|
38
|
+
"lemonlog": "^1.2.0"
|
|
38
39
|
}
|
|
39
40
|
}
|