fostrom 0.0.19 → 0.1.0
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/dl-agent.sh +22 -3
- package/index.js +24 -12
- package/package.json +1 -1
package/dl-agent.sh
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
#
|
|
5
5
|
# Usage: ./dl-agent.sh <directory>
|
|
6
6
|
|
|
7
|
-
VERSION="v0.0
|
|
7
|
+
VERSION="v0.1.0"
|
|
8
8
|
|
|
9
9
|
# CDN URLs in order of preference
|
|
10
10
|
CDN_PRIMARY="https://cdn.fostrom.dev/fostrom-device-agent/$VERSION"
|
|
@@ -135,6 +135,14 @@ install_binary() {
|
|
|
135
135
|
ln -sf "$FILENAME" "$INSTALL_DIR/fostrom-device-agent"
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
read_installed_version() {
|
|
139
|
+
BIN="$1"
|
|
140
|
+
[ ! -x "$BIN" ] && return 1
|
|
141
|
+
RAW_VERSION="$("$BIN" version 2>/dev/null || true)"
|
|
142
|
+
[ -z "$RAW_VERSION" ] && return 1
|
|
143
|
+
printf "%s\n" "$RAW_VERSION" | tr -d '[:space:]'
|
|
144
|
+
}
|
|
145
|
+
|
|
138
146
|
main() {
|
|
139
147
|
# Detect OS and architecture
|
|
140
148
|
OS="$(uname -s)"
|
|
@@ -165,9 +173,16 @@ main() {
|
|
|
165
173
|
|
|
166
174
|
FILENAME="fostrom-device-agent-${OS}-${ARCH}"
|
|
167
175
|
|
|
168
|
-
# Check if binary already exists
|
|
176
|
+
# Check if binary already exists and the version matches.
|
|
169
177
|
if [ -f "$LOCATION/$FILENAME" ]; then
|
|
170
|
-
|
|
178
|
+
INSTALLED_VERSION="$(read_installed_version "$LOCATION/$FILENAME" || true)"
|
|
179
|
+
if [ "$INSTALLED_VERSION" = "$VERSION" ]; then
|
|
180
|
+
# Ensure symlink exists even when reusing.
|
|
181
|
+
ln -sf "$FILENAME" "$LOCATION/fostrom-device-agent"
|
|
182
|
+
exit 0
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
printf "Updating Fostrom Device Agent to %s...\n" "$VERSION"
|
|
171
186
|
fi
|
|
172
187
|
|
|
173
188
|
printf "Downloading Fostrom Device Agent...\n"
|
|
@@ -179,6 +194,10 @@ main() {
|
|
|
179
194
|
xattr -r -d com.apple.quarantine "$LOCATION/$FILENAME" 2>/dev/null || true
|
|
180
195
|
fi
|
|
181
196
|
|
|
197
|
+
INSTALLED_VERSION="$(read_installed_version "$LOCATION/$FILENAME" || true)"
|
|
198
|
+
[ "$INSTALLED_VERSION" = "$VERSION" ] || die \
|
|
199
|
+
"Fatal: Installed Version Mismatch (expected $VERSION, got ${INSTALLED_VERSION:-unknown})"
|
|
200
|
+
|
|
182
201
|
printf "Fostrom Device Agent downloaded successfully\n"
|
|
183
202
|
}
|
|
184
203
|
|
package/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "child_process"
|
|
2
2
|
import { fileURLToPath } from "url"
|
|
3
3
|
import path from "path"
|
|
4
4
|
import http from "node:http"
|
|
@@ -40,6 +40,7 @@ export default class Fostrom {
|
|
|
40
40
|
#log = true
|
|
41
41
|
#creds = {}
|
|
42
42
|
#sseBuffer = ""
|
|
43
|
+
#sseEvent = {}
|
|
43
44
|
#sseReq = null
|
|
44
45
|
#reconnectTimer = null
|
|
45
46
|
#stopped = true
|
|
@@ -52,7 +53,7 @@ export default class Fostrom {
|
|
|
52
53
|
onMail = async mail => {
|
|
53
54
|
if (this.#log) {
|
|
54
55
|
console.warn(`[Fostrom] Received Mail (Mailbox Size: ${mail.mailbox_size}): ${mail.name} -> ID ${mail.id}`)
|
|
55
|
-
console.warn(" Auto-Acknowledging Mail. Define Mail Handler to handle incoming mail.\n `fostrom.
|
|
56
|
+
console.warn(" Auto-Acknowledging Mail. Define Mail Handler to handle incoming mail.\n `fostrom.onMail = async (mail) => { ...; await mail.ack(); }`\n")
|
|
56
57
|
}
|
|
57
58
|
await mail.ack()
|
|
58
59
|
}
|
|
@@ -108,18 +109,18 @@ export default class Fostrom {
|
|
|
108
109
|
env["FOSTROM_RUNTIME_ENV"] = String(this.#runtimeEnv)
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
const args = ["start"]
|
|
112
|
-
|
|
113
112
|
try {
|
|
114
|
-
const output =
|
|
113
|
+
const output = execFileSync(agent_path(), ["start"], { encoding: "utf8", env })
|
|
115
114
|
const out = output.trim()
|
|
116
115
|
if (out.startsWith("started:")) return
|
|
117
116
|
if (out.startsWith("already_started:")) return
|
|
118
117
|
return
|
|
119
118
|
} catch (error) {
|
|
120
119
|
const out = (error.stdout || "").toString().trim()
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
const err = (error.stderr || "").toString().trim()
|
|
121
|
+
const text = out || err
|
|
122
|
+
if (text) {
|
|
123
|
+
const [atom, rest] = text.split(":", 2)
|
|
123
124
|
throw new FostromError(atom || "failed", (rest || "Failed to start Device Agent").trim())
|
|
124
125
|
}
|
|
125
126
|
throw new FostromError("failed", "Failed to start Device Agent")
|
|
@@ -166,7 +167,7 @@ export default class Fostrom {
|
|
|
166
167
|
|
|
167
168
|
static stopAgent() {
|
|
168
169
|
try {
|
|
169
|
-
|
|
170
|
+
execFileSync(agent_path(), ["stop"], { encoding: "utf8" })
|
|
170
171
|
} catch (e) {
|
|
171
172
|
console.error("[Fostrom] Failed to stop the Fostrom Device Agent")
|
|
172
173
|
}
|
|
@@ -192,6 +193,8 @@ export default class Fostrom {
|
|
|
192
193
|
}
|
|
193
194
|
} catch { }
|
|
194
195
|
this.#sseReq = null
|
|
196
|
+
this.#sseBuffer = ""
|
|
197
|
+
this.#sseEvent = {}
|
|
195
198
|
const doStop = (stopAgent === null) ? this.#stopAgentOnExit : Boolean(stopAgent)
|
|
196
199
|
if (doStop) Fostrom.stopAgent()
|
|
197
200
|
}
|
|
@@ -282,6 +285,7 @@ export default class Fostrom {
|
|
|
282
285
|
if (this.#stopped) return
|
|
283
286
|
if (this.#sseReq) return
|
|
284
287
|
this.#sseBuffer = ""
|
|
288
|
+
this.#sseEvent = {}
|
|
285
289
|
const { fleet_id, device_id } = this.#creds
|
|
286
290
|
const options = {
|
|
287
291
|
socketPath: Fostrom.#SOCK,
|
|
@@ -298,6 +302,7 @@ export default class Fostrom {
|
|
|
298
302
|
const scheduleReconnect = (delay) => {
|
|
299
303
|
this.#sseReq = null
|
|
300
304
|
this.#sseBuffer = ""
|
|
305
|
+
this.#sseEvent = {}
|
|
301
306
|
if (!this.#stopped) {
|
|
302
307
|
this.#reconnectTimer = setTimeout(() => this.#open_event_stream(), delay)
|
|
303
308
|
}
|
|
@@ -306,7 +311,14 @@ export default class Fostrom {
|
|
|
306
311
|
const req = http.request(options, (res) => {
|
|
307
312
|
res.setEncoding('utf8')
|
|
308
313
|
res.on('data', (chunk) => {
|
|
309
|
-
|
|
314
|
+
const parsed = Fostrom.#parse_events(
|
|
315
|
+
this.#sseBuffer,
|
|
316
|
+
chunk,
|
|
317
|
+
this.#sseEvent,
|
|
318
|
+
this.#event_handler.bind(this)
|
|
319
|
+
)
|
|
320
|
+
this.#sseBuffer = parsed.buffer
|
|
321
|
+
this.#sseEvent = parsed.event
|
|
310
322
|
})
|
|
311
323
|
res.on('error', () => scheduleReconnect(500))
|
|
312
324
|
res.on('aborted', () => scheduleReconnect(500))
|
|
@@ -376,12 +388,12 @@ export default class Fostrom {
|
|
|
376
388
|
})
|
|
377
389
|
}
|
|
378
390
|
|
|
379
|
-
static #parse_events(buffer, chunk, event_handler) {
|
|
391
|
+
static #parse_events(buffer, chunk, currentEvent, event_handler) {
|
|
380
392
|
buffer += chunk
|
|
381
393
|
const lines = buffer.split('\n')
|
|
382
394
|
buffer = lines.pop() || ''
|
|
383
395
|
|
|
384
|
-
let event = {}
|
|
396
|
+
let event = currentEvent || {}
|
|
385
397
|
for (const raw of lines) {
|
|
386
398
|
const line = raw.replace(/\r$/, '')
|
|
387
399
|
if (line === '') {
|
|
@@ -400,7 +412,7 @@ export default class Fostrom {
|
|
|
400
412
|
}
|
|
401
413
|
}
|
|
402
414
|
|
|
403
|
-
return buffer
|
|
415
|
+
return { buffer, event }
|
|
404
416
|
}
|
|
405
417
|
|
|
406
418
|
async #deliverMail(mail) {
|