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.
Files changed (2) hide show
  1. package/lib/gateway.js +97 -2
  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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lobstakit-cloud",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "LobstaKit Cloud — Setup wizard and management for LobstaCloud gateways",
5
5
  "main": "server.js",
6
6
  "bin": {