New Vercel project igneum-relay from relay/: one function (api/relay.mjs) over Neon tables relay_items and relay_machines, files in Vercel Blob store igneum-relay (50 MB client uploads, 4 MB through the function), phone-first web page at /r/<token>/ with the site tokens. Mac CLI tools/relay.mjs (feed, read, drop, task, run, watch, inbox, machines, role, name). Windows clients send.bat/send.ps1 and the igneum-agent (registers hostname, role, GPUs, WSL, nvcc; runs queued PowerShell scripts, posts results, reboot-continue via scheduled task + RunOnce), bash twins send.sh and agent.sh (verified live), playbooks for WSL setup, prover setup, prove-block, miner v4, one-click placeholder. make-clients.sh bakes the secrets into a zip; the repo copies hold placeholders. Screenshots under docs/design/relay. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
48 lines
4.3 KiB
Bash
Executable file
48 lines
4.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Igneum relay client for Mac/Linux/WSL. Needs curl and jq (python3 fallback for jq).
|
|
# send.sh "<text>" note to everyone send.sh <file> file (up to 50 MB)
|
|
# send.sh inbox unread tasks for this machine, marked read send.sh peek same, not marked
|
|
# send.sh get <id> print an item, download its file here send.sh done <id>
|
|
# send.sh result "<text>" [--task-id N] [--file path]
|
|
# RELAY_TO=PC1 RELAY_TITLE="..." RELAY_MACHINE=Mac override the defaults.
|
|
# The URL, key and token are written in by make-clients.sh (the repo copy holds placeholders).
|
|
set -euo pipefail
|
|
RELAY_URL='__RELAY_URL__'; RELAY_KEY='__RELAY_KEY__'; RELAY_TOKEN='__RELAY_TOKEN__'
|
|
BASE="$RELAY_URL/r/$RELAY_TOKEN/api"
|
|
STATE="${XDG_STATE_HOME:-$HOME/.local/state}/igneum-relay"
|
|
machine() { if [ -n "${RELAY_MACHINE:-}" ]; then echo "$RELAY_MACHINE"; elif [ -f "$STATE/machine.txt" ]; then cat "$STATE/machine.txt"; else hostname -s; fi; }
|
|
jqq() { if command -v jq >/dev/null; then jq "$@"; else python3 -c 'import json,sys; q=sys.argv[1]; d=json.load(sys.stdin); print(d[q.strip(".")])' "$@"; fi; }
|
|
post() { curl -sS --max-time 120 -X POST "$BASE/$1" -H 'Content-Type: application/json' -H "x-igneum-key: $RELAY_KEY" --data-binary "$2"; }
|
|
get() { curl -sS --max-time 60 "$BASE/$1" -H "x-igneum-key: $RELAY_KEY"; }
|
|
jstr() { python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))' ; }
|
|
upload() {
|
|
local path="$1" name size tok
|
|
name="$(basename "$path")"; size=$(stat -f%z "$path" 2>/dev/null || stat -c%s "$path")
|
|
tok="$(post upload "{\"name\":$(printf '%s' "$name" | jstr),\"size\":$size}")"
|
|
local put url token ver
|
|
put="$(printf '%s' "$tok" | jqq -r .put_url)"; token="$(printf '%s' "$tok" | jqq -r .token)"; ver="$(printf '%s' "$tok" | jqq -r .api_version)"
|
|
url="$(curl -sS --max-time 600 -X PUT "$put" -H "authorization: Bearer $token" -H "x-api-version: $ver" -H 'x-add-random-suffix: 1' -H 'x-content-type: application/octet-stream' --data-binary "@$path" | jqq -r .url)"
|
|
[ -n "$url" ] && [ "$url" != "null" ] || { echo "blob upload failed" >&2; return 1; }
|
|
printf '"file_name":%s,"file_url":"%s","size":%s' "$(printf '%s' "$name" | jstr)" "$url" "$size"
|
|
}
|
|
show() { python3 -c '
|
|
import json,sys; it=json.load(sys.stdin)
|
|
for x in (it if isinstance(it,list) else [it]):
|
|
print("===== #%s %s from %s to %s at %s%s =====" % (x["id"],x["kind"],x["from"],x["to"],x["ts"], (" | "+x["title"]) if x.get("title") else ""))
|
|
if x.get("body"): print(x["body"])
|
|
if x.get("has_file"): print("file: %s (%s bytes); send.sh get %s downloads it" % (x["file_name"],x["size"],x["id"]))'; }
|
|
cmd="${1:-}"; M="$(machine)"; TO="${RELAY_TO:-all}"; TITLE="${RELAY_TITLE:-}"
|
|
case "$cmd" in
|
|
inbox) get "inbox?machine=$M&ack=1" | jqq .items | show ;;
|
|
peek) get "inbox?machine=$M" | jqq .items | show ;;
|
|
get) [ -n "${2:-}" ] || { echo 'get <id>' >&2; exit 1; }; j="$(get "item?id=$2")"; printf '%s' "$j" | jqq .item | show
|
|
if [ "$(printf '%s' "$j" | jqq -r .item.has_file)" = "true" ]; then out="$2-$(printf '%s' "$j" | jqq -r .item.file_name)"; curl -sSL --max-time 600 "$BASE/file?id=$2" -H "x-igneum-key: $RELAY_KEY" -o "$out"; echo "downloaded: $out"; fi ;;
|
|
done) [ -n "${2:-}" ] || { echo "done <id>" >&2; exit 1; }; post done "{\"id\":$2}" >/dev/null; echo "#$2 done" ;;
|
|
result) shift; text="${1:-}"; shift || true; task=0; file=""
|
|
while [ $# -gt 0 ]; do case "$1" in --task-id) task="$2"; shift 2;; --file) file="$2"; shift 2;; *) shift;; esac; done
|
|
extra=""; [ -n "$file" ] && extra=",$(upload "$file")"
|
|
post drop "{\"from\":$(printf '%s' "$M" | jstr),\"to\":\"$TO\",\"kind\":\"result\",\"title\":$(printf '%s' "$TITLE" | jstr),\"body\":$(printf '%s' "$text" | jstr),\"task_id\":$task$extra}"; echo ;;
|
|
"") echo 'send.sh "<text>" | send.sh <file> | send.sh inbox | send.sh result "<text>" | send.sh get <id> | send.sh done <id>' >&2; exit 1 ;;
|
|
*) if [ -f "$cmd" ]; then post drop "{\"from\":$(printf '%s' "$M" | jstr),\"to\":\"$TO\",\"kind\":\"file\",\"title\":$(printf '%s' "${TITLE:-$(basename "$cmd")}" | jstr),\"body\":$(printf '%s' "${2:-}" | jstr),$(upload "$cmd")}"
|
|
else post drop "{\"from\":$(printf '%s' "$M" | jstr),\"to\":\"$TO\",\"kind\":\"text\",\"title\":$(printf '%s' "$TITLE" | jstr),\"body\":$(printf '%s' "$cmd" | jstr)}"; fi; echo ;;
|
|
esac
|