lobstakit-cloud 1.3.0 → 1.3.2
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/lib/gateway.js +97 -2
- package/package.json +1 -1
package/lib/gateway.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LobstaKit Cloud — Gateway Manager
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Controls the openclaw-gateway systemd service.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const { execSync } = require('child_process');
|
|
8
|
+
const fs = require('fs');
|
|
8
9
|
|
|
9
10
|
const SERVICE_NAME = 'openclaw-gateway';
|
|
11
|
+
const DROP_IN_DIR = `/etc/systemd/system/${SERVICE_NAME}.service.d`;
|
|
12
|
+
const DROP_IN_FILE = `${DROP_IN_DIR}/dbus-env.conf`;
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
15
|
* Check if the gateway service is currently running.
|
|
@@ -23,10 +26,102 @@ function isGatewayRunning() {
|
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Ensure D-Bus user session is available and inject env vars into the
|
|
31
|
+
* openclaw-gateway systemd service unit via a drop-in override.
|
|
32
|
+
*
|
|
33
|
+
* Root cause of "systemctl --user unavailable: Failed to connect to bus:
|
|
34
|
+
* No medium found": OpenClaw calls `systemctl --user` internally on startup.
|
|
35
|
+
* On headless VPS, no D-Bus user session exists. Even if LobstaKit sets up
|
|
36
|
+
* D-Bus in its own process, the gateway runs as a *separate* system service
|
|
37
|
+
* and never inherits those env vars.
|
|
38
|
+
*
|
|
39
|
+
* Fix: write a systemd drop-in that bakes XDG_RUNTIME_DIR and
|
|
40
|
+
* DBUS_SESSION_BUS_ADDRESS into the service unit so every restart picks
|
|
41
|
+
* them up automatically — no manual intervention required.
|
|
42
|
+
*/
|
|
43
|
+
function ensureUserSession() {
|
|
44
|
+
try {
|
|
45
|
+
const uid = execSync('id -u', { encoding: 'utf8', timeout: 3000 }).trim();
|
|
46
|
+
const username = execSync('id -un', { encoding: 'utf8', timeout: 3000 }).trim();
|
|
47
|
+
const runtimeDir = `/run/user/${uid}`;
|
|
48
|
+
const busSocket = `${runtimeDir}/bus`;
|
|
49
|
+
const busAddress = `unix:path=${busSocket}`;
|
|
50
|
+
|
|
51
|
+
// 1. Enable lingering so user units survive without an active login
|
|
52
|
+
execSync(`loginctl enable-linger ${username} 2>/dev/null || true`, {
|
|
53
|
+
encoding: 'utf8',
|
|
54
|
+
timeout: 5000
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// 2. Ensure runtime dir exists with correct permissions
|
|
58
|
+
execSync(`mkdir -p ${runtimeDir} && chmod 700 ${runtimeDir} && chown ${uid}:${uid} ${runtimeDir} 2>/dev/null || true`, {
|
|
59
|
+
encoding: 'utf8',
|
|
60
|
+
timeout: 3000
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// 3. Start dbus-daemon if socket not already present
|
|
64
|
+
let dbusRunning = false;
|
|
65
|
+
try {
|
|
66
|
+
execSync(`test -S ${busSocket}`, { encoding: 'utf8', timeout: 2000 });
|
|
67
|
+
dbusRunning = true;
|
|
68
|
+
} catch { /* socket not there yet */ }
|
|
69
|
+
|
|
70
|
+
if (!dbusRunning) {
|
|
71
|
+
try {
|
|
72
|
+
execSync(
|
|
73
|
+
`dbus-daemon --session --address=${busAddress} --fork --nopidfile`,
|
|
74
|
+
{
|
|
75
|
+
encoding: 'utf8',
|
|
76
|
+
timeout: 5000,
|
|
77
|
+
env: { ...process.env, XDG_RUNTIME_DIR: runtimeDir }
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
// Wait up to 2s for socket to appear
|
|
81
|
+
for (let i = 0; i < 10; i++) {
|
|
82
|
+
try {
|
|
83
|
+
execSync(`test -S ${busSocket}`, { encoding: 'utf8', timeout: 500 });
|
|
84
|
+
dbusRunning = true;
|
|
85
|
+
break;
|
|
86
|
+
} catch {
|
|
87
|
+
execSync('sleep 0.2', { timeout: 500 });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch (e) {
|
|
91
|
+
console.warn('[gateway] dbus-daemon unavailable:', e.message);
|
|
92
|
+
// dbus-daemon may not be installed — XDG_RUNTIME_DIR alone may be enough
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 4. Write systemd drop-in so the service unit inherits these env vars
|
|
97
|
+
// on every start/restart, not just when LobstaKit happens to call this.
|
|
98
|
+
const lines = [
|
|
99
|
+
'# Auto-generated by LobstaKit — do not edit manually',
|
|
100
|
+
'[Service]',
|
|
101
|
+
`Environment="XDG_RUNTIME_DIR=${runtimeDir}"`,
|
|
102
|
+
];
|
|
103
|
+
if (dbusRunning) {
|
|
104
|
+
lines.push(`Environment="DBUS_SESSION_BUS_ADDRESS=${busAddress}"`);
|
|
105
|
+
}
|
|
106
|
+
const dropInContent = lines.join('\n') + '\n';
|
|
107
|
+
|
|
108
|
+
execSync(`mkdir -p ${DROP_IN_DIR}`, { encoding: 'utf8', timeout: 3000 });
|
|
109
|
+
fs.writeFileSync(DROP_IN_FILE, dropInContent, 'utf8');
|
|
110
|
+
|
|
111
|
+
// 5. Reload systemd so it picks up the new drop-in
|
|
112
|
+
execSync('systemctl daemon-reload', { encoding: 'utf8', timeout: 10000 });
|
|
113
|
+
|
|
114
|
+
console.log(`[gateway] Session ready — runtimeDir=${runtimeDir} dbus=${dbusRunning} drop-in written`);
|
|
115
|
+
} catch (err) {
|
|
116
|
+
console.warn('[gateway] ensureUserSession warning:', err.message);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
26
120
|
/**
|
|
27
121
|
* Start the gateway service.
|
|
28
122
|
*/
|
|
29
123
|
function startGateway() {
|
|
124
|
+
ensureUserSession();
|
|
30
125
|
try {
|
|
31
126
|
execSync(`systemctl start ${SERVICE_NAME}`, {
|
|
32
127
|
encoding: 'utf8',
|
|
@@ -61,8 +156,8 @@ function stopGateway() {
|
|
|
61
156
|
* Restart the gateway service (enables it first if not already enabled).
|
|
62
157
|
*/
|
|
63
158
|
function restartGateway() {
|
|
159
|
+
ensureUserSession();
|
|
64
160
|
try {
|
|
65
|
-
// Ensure service is enabled (cloud-init doesn't enable it — LobstaKit does after setup)
|
|
66
161
|
execSync(`systemctl enable ${SERVICE_NAME}`, {
|
|
67
162
|
encoding: 'utf8',
|
|
68
163
|
timeout: 10000
|