portok 1.0.4 → 1.0.5
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 +1 -1
- package/portok.js +56 -72
- package/portok@.service +5 -1
package/package.json
CHANGED
package/portok.js
CHANGED
|
@@ -353,83 +353,67 @@ async function cmdInit(options) {
|
|
|
353
353
|
results.push({ path: stateDir, status: 'error', error: err.message });
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
-
// Install systemd template unit
|
|
356
|
+
// Install systemd template unit from external file
|
|
357
357
|
const systemdDest = path.join(systemdDir, serviceFileName);
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
[
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
Environment=INSTANCE_NAME=%i
|
|
376
|
-
|
|
377
|
-
# Working directory
|
|
378
|
-
WorkingDirectory=/opt/portok
|
|
379
|
-
|
|
380
|
-
# Start the daemon
|
|
381
|
-
ExecStart=/usr/bin/node /opt/portok/portokd.js
|
|
382
|
-
|
|
383
|
-
# Restart policy
|
|
384
|
-
Restart=always
|
|
385
|
-
RestartSec=5
|
|
386
|
-
StartLimitBurst=5
|
|
387
|
-
StartLimitIntervalSec=60
|
|
388
|
-
|
|
389
|
-
# Logging
|
|
390
|
-
StandardOutput=journal
|
|
391
|
-
StandardError=journal
|
|
392
|
-
SyslogIdentifier=portok-%i
|
|
393
|
-
|
|
394
|
-
# Security hardening
|
|
395
|
-
NoNewPrivileges=true
|
|
396
|
-
ProtectSystem=strict
|
|
397
|
-
ProtectHome=true
|
|
398
|
-
PrivateTmp=true
|
|
399
|
-
ProtectKernelTunables=true
|
|
400
|
-
ProtectKernelModules=true
|
|
401
|
-
ProtectControlGroups=true
|
|
402
|
-
|
|
403
|
-
# Allow writing to state directory
|
|
404
|
-
ReadWritePaths=/var/lib/portok
|
|
405
|
-
|
|
406
|
-
# Network access (required for proxying)
|
|
407
|
-
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
|
408
|
-
|
|
409
|
-
[Install]
|
|
410
|
-
WantedBy=multi-user.target
|
|
411
|
-
`;
|
|
358
|
+
|
|
359
|
+
// Find portok@.service file relative to this script
|
|
360
|
+
const scriptDir = path.dirname(process.argv[1]);
|
|
361
|
+
const possibleServicePaths = [
|
|
362
|
+
path.join(scriptDir, serviceFileName),
|
|
363
|
+
path.join(scriptDir, '..', serviceFileName),
|
|
364
|
+
path.join(__dirname, serviceFileName),
|
|
365
|
+
path.join(__dirname, '..', serviceFileName),
|
|
366
|
+
];
|
|
367
|
+
|
|
368
|
+
let serviceSourcePath = null;
|
|
369
|
+
for (const p of possibleServicePaths) {
|
|
370
|
+
if (fs.existsSync(p)) {
|
|
371
|
+
serviceSourcePath = p;
|
|
372
|
+
break;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
412
375
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
376
|
+
// Check if systemd directory exists
|
|
377
|
+
if (!fs.existsSync(systemdDir)) {
|
|
378
|
+
results.push({ path: systemdDest, status: 'skipped', error: 'systemd not available' });
|
|
379
|
+
} else if (!serviceSourcePath) {
|
|
380
|
+
results.push({ path: systemdDest, status: 'error', error: `${serviceFileName} not found in package` });
|
|
381
|
+
} else {
|
|
382
|
+
try {
|
|
383
|
+
// Read template and replace placeholders with actual paths
|
|
384
|
+
let serviceContent = fs.readFileSync(serviceSourcePath, 'utf-8');
|
|
421
385
|
|
|
422
|
-
//
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
386
|
+
// Get actual node path (supports nvm, fnm, volta, etc.)
|
|
387
|
+
const nodePath = process.execPath;
|
|
388
|
+
|
|
389
|
+
// Get actual portok installation directory
|
|
390
|
+
const portokDir = path.dirname(serviceSourcePath);
|
|
391
|
+
|
|
392
|
+
// Replace hardcoded paths with actual paths
|
|
393
|
+
serviceContent = serviceContent.replace(/\/usr\/bin\/node/g, nodePath);
|
|
394
|
+
serviceContent = serviceContent.replace(/WorkingDirectory=\/opt\/portok/g, `WorkingDirectory=${portokDir}`);
|
|
395
|
+
serviceContent = serviceContent.replace(/\/opt\/portok\/portokd\.js/g, `${portokDir}/portokd.js`);
|
|
396
|
+
|
|
397
|
+
const existingContent = fs.existsSync(systemdDest) ? fs.readFileSync(systemdDest, 'utf-8') : null;
|
|
398
|
+
|
|
399
|
+
if (existingContent && existingContent.trim() === serviceContent.trim()) {
|
|
400
|
+
results.push({ path: systemdDest, status: 'exists' });
|
|
401
|
+
} else {
|
|
402
|
+
fs.writeFileSync(systemdDest, serviceContent, { mode: 0o644 });
|
|
403
|
+
results.push({ path: systemdDest, status: 'created' });
|
|
404
|
+
|
|
405
|
+
// Reload systemd daemon
|
|
406
|
+
try {
|
|
407
|
+
const { execSync } = require('child_process');
|
|
408
|
+
execSync('systemctl daemon-reload', { stdio: 'pipe' });
|
|
409
|
+
results.push({ path: 'systemctl daemon-reload', status: 'created' });
|
|
410
|
+
} catch (e) {
|
|
411
|
+
results.push({ path: 'systemctl daemon-reload', status: 'skipped', error: 'systemctl failed' });
|
|
412
|
+
}
|
|
429
413
|
}
|
|
414
|
+
} catch (err) {
|
|
415
|
+
results.push({ path: systemdDest, status: 'error', error: err.message });
|
|
430
416
|
}
|
|
431
|
-
} catch (err) {
|
|
432
|
-
results.push({ path: systemdDest, status: 'error', error: err.message });
|
|
433
417
|
}
|
|
434
418
|
|
|
435
419
|
if (options.json) {
|
package/portok@.service
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Portok systemd template unit for multi-instance deployments
|
|
2
|
-
#
|
|
2
|
+
#
|
|
3
|
+
# This file is used as a template by 'portok init'.
|
|
4
|
+
# The following paths are automatically replaced:
|
|
5
|
+
# - /usr/bin/node -> actual node path (supports nvm, fnm, volta)
|
|
6
|
+
# - /opt/portok -> actual portok installation directory
|
|
3
7
|
#
|
|
4
8
|
# Usage:
|
|
5
9
|
# systemctl start portok@api # Start instance "api"
|