roster-server 1.9.2 β 1.9.4
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 +69 -2
- package/demo/custom-port-range.js +40 -0
- package/demo/local-url-example.js +40 -0
- package/demo/socketio.js +9 -1
- package/index.js +52 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -166,6 +166,8 @@ When creating a new `RosterServer` instance, you can pass the following options:
|
|
|
166
166
|
- `greenlockStorePath` (string): Directory for Greenlock configuration.
|
|
167
167
|
- `staging` (boolean): Set to `true` to use Let's Encrypt's staging environment (for testing).
|
|
168
168
|
- `local` (boolean): Set to `true` to run in local development mode.
|
|
169
|
+
- `minLocalPort` (number): Minimum port for local mode (default: 4000).
|
|
170
|
+
- `maxLocalPort` (number): Maximum port for local mode (default: 9999).
|
|
169
171
|
|
|
170
172
|
## π Local Development Mode
|
|
171
173
|
|
|
@@ -178,19 +180,84 @@ When `{ local: true }` is enabled, RosterServer **Skips SSL/HTTPS**: Runs pure H
|
|
|
178
180
|
```javascript
|
|
179
181
|
const server = new Roster({
|
|
180
182
|
wwwPath: '/srv/www',
|
|
181
|
-
local: true // Enable local development mode
|
|
183
|
+
local: true, // Enable local development mode
|
|
184
|
+
minLocalPort: 4000, // Optional: minimum port (default: 4000)
|
|
185
|
+
maxLocalPort: 9999 // Optional: maximum port (default: 9999)
|
|
182
186
|
});
|
|
183
187
|
server.start();
|
|
184
188
|
```
|
|
185
189
|
|
|
186
190
|
### Port Assignment
|
|
187
191
|
|
|
188
|
-
In local mode, domains are automatically assigned ports based on a CRC32 hash of the domain name (range 4000-9999):
|
|
192
|
+
In local mode, domains are automatically assigned ports based on a CRC32 hash of the domain name (default range 4000-9999, configurable via `minLocalPort` and `maxLocalPort`):
|
|
189
193
|
|
|
190
194
|
- `example.com` β `http://localhost:9465`
|
|
191
195
|
- `api.example.com` β `http://localhost:9388`
|
|
192
196
|
- And so on...
|
|
193
197
|
|
|
198
|
+
You can customize the port range:
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
const roster = new Roster({
|
|
202
|
+
local: true,
|
|
203
|
+
minLocalPort: 5000, // Start from port 5000
|
|
204
|
+
maxLocalPort: 6000 // Up to port 6000
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Getting Local URLs
|
|
209
|
+
|
|
210
|
+
RosterServer provides two methods to get the local URL for a domain:
|
|
211
|
+
|
|
212
|
+
**1. Static Method (Predictable, No Instance Required):**
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
// Get the URL before starting the server (using default range 4000-9999)
|
|
216
|
+
const url = Roster.getLocalUrl('example.com');
|
|
217
|
+
console.log(url); // http://localhost:9465
|
|
218
|
+
|
|
219
|
+
// Or specify custom port range
|
|
220
|
+
const customUrl = Roster.getLocalUrl('example.com', {
|
|
221
|
+
minLocalPort: 5000,
|
|
222
|
+
maxLocalPort: 6000
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
This static method calculates the port deterministically using CRC32, so you can predict the URL before even creating a Roster instance.
|
|
227
|
+
|
|
228
|
+
**2. Instance Method (After Registration):**
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
const roster = new Roster({ local: true });
|
|
232
|
+
roster.register('example.com', handler);
|
|
233
|
+
|
|
234
|
+
await roster.start();
|
|
235
|
+
|
|
236
|
+
// Get the actual URL assigned to the domain
|
|
237
|
+
const url = roster.getLocalUrl('example.com');
|
|
238
|
+
console.log(url); // http://localhost:9465
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
This instance method returns the actual URL assigned to the domain after the server starts. It's useful when you need to confirm the URL or when there might be port collisions.
|
|
242
|
+
|
|
243
|
+
**Example Usage:**
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
const roster = new Roster({ local: true });
|
|
247
|
+
|
|
248
|
+
roster.register('example.com', (httpsServer) => {
|
|
249
|
+
return (req, res) => {
|
|
250
|
+
res.writeHead(200);
|
|
251
|
+
res.end('Hello World!');
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
roster.start().then(() => {
|
|
256
|
+
const url = roster.getLocalUrl('example.com');
|
|
257
|
+
console.log(`Server available at: ${url}`);
|
|
258
|
+
});
|
|
259
|
+
```
|
|
260
|
+
|
|
194
261
|
## π§ A Touch of Magic
|
|
195
262
|
|
|
196
263
|
You might be thinking, "But setting up HTTPS and virtual hosts is supposed to be complicated and time-consuming!" Well, not anymore. With RosterServer, you can get back to writing code that matters, like defending Earth from alien invaders! πΎπΎπΎ
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const Roster = require('../index.js');
|
|
2
|
+
|
|
3
|
+
// Example with custom port range
|
|
4
|
+
const roster = new Roster({
|
|
5
|
+
local: true,
|
|
6
|
+
minLocalPort: 5000, // Custom minimum port
|
|
7
|
+
maxLocalPort: 5100 // Custom maximum port
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
console.log('\nπ Static URL Prediction with custom range (5000-5100):');
|
|
11
|
+
console.log('example.com β', Roster.getLocalUrl('example.com', {
|
|
12
|
+
minLocalPort: 5000,
|
|
13
|
+
maxLocalPort: 5100
|
|
14
|
+
}));
|
|
15
|
+
console.log('api.example.com β', Roster.getLocalUrl('api.example.com', {
|
|
16
|
+
minLocalPort: 5000,
|
|
17
|
+
maxLocalPort: 5100
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
roster.register('example.com', (httpsServer) => {
|
|
21
|
+
return (req, res) => {
|
|
22
|
+
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
23
|
+
res.end('Hello from example.com with custom port range!');
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
roster.register('api.example.com', (httpsServer) => {
|
|
28
|
+
return (req, res) => {
|
|
29
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
30
|
+
res.end(JSON.stringify({ message: 'API with custom port range' }));
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
roster.start().then(() => {
|
|
35
|
+
console.log('\nπ Server Started with custom port range:');
|
|
36
|
+
console.log('example.com β', roster.getLocalUrl('example.com'));
|
|
37
|
+
console.log('api.example.com β', roster.getLocalUrl('api.example.com'));
|
|
38
|
+
|
|
39
|
+
console.log('\nβ
Both domains running in custom port range (5000-5100)!');
|
|
40
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const Roster = require('../index.js');
|
|
2
|
+
|
|
3
|
+
// Example 1: Get URL before creating instance (static method)
|
|
4
|
+
console.log('\nπ Static URL Prediction (before server starts):');
|
|
5
|
+
console.log('example.com β', Roster.getLocalUrl('example.com'));
|
|
6
|
+
console.log('api.example.com β', Roster.getLocalUrl('api.example.com'));
|
|
7
|
+
console.log('test.example.com β', Roster.getLocalUrl('test.example.com'));
|
|
8
|
+
|
|
9
|
+
// Example 2: Get URL after registration (instance method)
|
|
10
|
+
const roster = new Roster({ local: true });
|
|
11
|
+
|
|
12
|
+
roster.register('example.com', (httpsServer) => {
|
|
13
|
+
return (req, res) => {
|
|
14
|
+
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
15
|
+
res.end('Hello from example.com!');
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
roster.register('api.example.com', (httpsServer) => {
|
|
20
|
+
return (req, res) => {
|
|
21
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
22
|
+
res.end(JSON.stringify({ message: 'API endpoint' }));
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
roster.start().then(() => {
|
|
27
|
+
console.log('\nπ Server Started - Actual URLs:');
|
|
28
|
+
console.log('example.com β', roster.getLocalUrl('example.com'));
|
|
29
|
+
console.log('api.example.com β', roster.getLocalUrl('api.example.com'));
|
|
30
|
+
|
|
31
|
+
// Test with www prefix (should return same URL)
|
|
32
|
+
console.log('\nπ Testing www prefix handling:');
|
|
33
|
+
console.log('www.example.com β', roster.getLocalUrl('www.example.com'));
|
|
34
|
+
|
|
35
|
+
// Test non-existent domain
|
|
36
|
+
console.log('\nβ Testing non-existent domain:');
|
|
37
|
+
console.log('nonexistent.com β', roster.getLocalUrl('nonexistent.com') || 'null (domain not registered)');
|
|
38
|
+
|
|
39
|
+
console.log('\nβ
All domains running!');
|
|
40
|
+
});
|
package/demo/socketio.js
CHANGED
|
@@ -26,4 +26,12 @@ roster.register('example.com', (httpsServer) => {
|
|
|
26
26
|
};
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
roster.start()
|
|
29
|
+
roster.start().then(() => {
|
|
30
|
+
// Get local URL for registered domain (requires instance)
|
|
31
|
+
const url = roster.getLocalUrl('example.com');
|
|
32
|
+
console.log(`β
Socket.IO server available at: ${url}`);
|
|
33
|
+
|
|
34
|
+
// Get local URL without instance (static method - predictable port)
|
|
35
|
+
const staticUrl = Roster.getLocalUrl('example.com');
|
|
36
|
+
console.log(`βΉοΈ Static prediction: ${staticUrl}`);
|
|
37
|
+
});
|
package/index.js
CHANGED
|
@@ -160,9 +160,12 @@ class Roster {
|
|
|
160
160
|
this.sites = {};
|
|
161
161
|
this.domainServers = {}; // Store separate servers for each domain
|
|
162
162
|
this.portServers = {}; // Store servers by port
|
|
163
|
+
this.domainPorts = {}; // Store domain β port mapping for local mode
|
|
163
164
|
this.assignedPorts = new Set(); // Track ports assigned to domains (not OS availability)
|
|
164
165
|
this.hostname = options.hostname || '0.0.0.0';
|
|
165
166
|
this.filename = options.filename || 'index';
|
|
167
|
+
this.minLocalPort = options.minLocalPort || 4000;
|
|
168
|
+
this.maxLocalPort = options.maxLocalPort || 9999;
|
|
166
169
|
|
|
167
170
|
const port = options.port === undefined ? 443 : options.port;
|
|
168
171
|
if (port === 80 && !this.local) {
|
|
@@ -363,19 +366,57 @@ class Roster {
|
|
|
363
366
|
return { domain: domainString, port: this.defaultPort };
|
|
364
367
|
}
|
|
365
368
|
|
|
369
|
+
/**
|
|
370
|
+
* Get the local URL for a domain when running in local mode
|
|
371
|
+
* @param {string} domain - The domain name (e.g., 'example.com')
|
|
372
|
+
* @param {Object} options - Optional configuration
|
|
373
|
+
* @param {number} options.minLocalPort - Minimum port range (default: 4000)
|
|
374
|
+
* @param {number} options.maxLocalPort - Maximum port range (default: 9999)
|
|
375
|
+
* @returns {string} The local URL (e.g., 'http://localhost:4321')
|
|
376
|
+
*/
|
|
377
|
+
static getLocalUrl(domain, options = {}) {
|
|
378
|
+
const minPort = options.minLocalPort || 4000;
|
|
379
|
+
const maxPort = options.maxLocalPort || 9999;
|
|
380
|
+
|
|
381
|
+
// Remove www prefix if present
|
|
382
|
+
const cleanDomain = domain.startsWith('www.') ? domain.slice(4) : domain;
|
|
383
|
+
|
|
384
|
+
// Calculate deterministic port
|
|
385
|
+
const port = domainToPort(cleanDomain, minPort, maxPort);
|
|
386
|
+
|
|
387
|
+
return `http://localhost:${port}`;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Get the local URL for a domain that was registered on this instance
|
|
392
|
+
* @param {string} domain - The domain name
|
|
393
|
+
* @returns {string|null} The local URL if found, null otherwise
|
|
394
|
+
*/
|
|
395
|
+
getLocalUrl(domain) {
|
|
396
|
+
// Remove www prefix if present
|
|
397
|
+
const cleanDomain = domain.startsWith('www.') ? domain.slice(4) : domain;
|
|
398
|
+
|
|
399
|
+
// Check if domain has a port assigned
|
|
400
|
+
if (this.domainPorts && this.domainPorts[cleanDomain]) {
|
|
401
|
+
return `http://localhost:${this.domainPorts[cleanDomain]}`;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
|
|
366
407
|
createVirtualServer(domain) {
|
|
367
408
|
return new VirtualServer(domain);
|
|
368
409
|
}
|
|
369
410
|
|
|
370
411
|
// Assign port to domain, detecting collisions with already assigned ports
|
|
371
|
-
assignPortToDomain(domain
|
|
372
|
-
let port = domainToPort(domain,
|
|
412
|
+
assignPortToDomain(domain) {
|
|
413
|
+
let port = domainToPort(domain, this.minLocalPort, this.maxLocalPort);
|
|
373
414
|
|
|
374
415
|
// If port is already assigned to another domain, increment until we find a free one
|
|
375
416
|
while (this.assignedPorts.has(port)) {
|
|
376
417
|
port++;
|
|
377
|
-
if (port >
|
|
378
|
-
port =
|
|
418
|
+
if (port > this.maxLocalPort) {
|
|
419
|
+
port = this.minLocalPort; // Wrap around if we exceed max port
|
|
379
420
|
}
|
|
380
421
|
}
|
|
381
422
|
|
|
@@ -403,6 +444,9 @@ class Roster {
|
|
|
403
444
|
|
|
404
445
|
// Start server in local mode with HTTP - simplified version
|
|
405
446
|
startLocalMode() {
|
|
447
|
+
// Store mapping of domain to port for later retrieval
|
|
448
|
+
this.domainPorts = {};
|
|
449
|
+
|
|
406
450
|
// Create a simple HTTP server for each domain with CRC32-based ports
|
|
407
451
|
for (const [hostKey, siteApp] of Object.entries(this.sites)) {
|
|
408
452
|
const domain = hostKey.split(':')[0]; // Remove port if present
|
|
@@ -413,7 +457,10 @@ class Roster {
|
|
|
413
457
|
}
|
|
414
458
|
|
|
415
459
|
// Calculate deterministic port based on domain CRC32, with collision detection
|
|
416
|
-
const port = this.assignPortToDomain(domain
|
|
460
|
+
const port = this.assignPortToDomain(domain);
|
|
461
|
+
|
|
462
|
+
// Store domain β port mapping
|
|
463
|
+
this.domainPorts[domain] = port;
|
|
417
464
|
|
|
418
465
|
// Create virtual server for the domain
|
|
419
466
|
const virtualServer = this.createVirtualServer(domain);
|