diff --git a/QUICKSTART.md b/QUICKSTART.md index 0781ba6..df891b3 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -41,13 +41,33 @@ On Linux and Windows a tray icon appears — closing the window hides to tray ra --- -## Option 3 — Run the daemon manually (headless / power users) +## Option 3 — Run the daemon + TUI or web UI locally (power users / dev) + +Example scripts are provided for the common local workflows. Copy them and fill in your anchor URL: + +```bash +# TUI (terminal UI): +cp launch-tui.sh.example launch-tui.sh +$EDITOR launch-tui.sh # set ANCHOR=wss://your-anchor/ws +./launch-tui.sh + +# Web UI in daemon mode (Vite dev server + daemon): +cp launch-web.sh.example launch-web.sh +$EDITOR launch-web.sh # set ANCHOR=wss://your-anchor/ws +./launch-web.sh +``` + +The real script files are gitignored so your local edits (anchor URL, alias, network) are never accidentally committed. + +--- + +## Option 4 — Run the daemon manually (headless) If you want the daemon running in the background without the desktop UI — on a server, over SSH, or with the web UI in a browser pointed at your local machine: ```bash # Download waste-daemon from the releases page, then: -./waste-daemon -alias yourname -anchor wss://your-anchor-server/ws +./waste-daemon -alias yourname -anchor wss://YOUR_ANCHOR_DOMAIN/ws ``` Then open the web UI in a browser at the anchor URL, or point the web UI's daemon mode at `ws://127.0.0.1:17338`. @@ -83,7 +103,7 @@ The anchor is a tiny signaling server that helps peers find each other — it ne ```bash # On your VPS: -./waste-anchor -bind 127.0.0.1:8080 +./waste-anchor -bind 127.0.0.1:8080 -turn-secret YOUR_COTURN_SECRET ``` -Put it behind nginx with a `/ws` WebSocket proxy and serve the web UI static files at `/`. See [README.md](README.md#hosting-on-a-vps) for the full nginx setup. +Put it behind nginx with `/ws` and `/turn-credentials` proxied to the anchor, and the web UI static files at `/`. See [README.md](README.md#hosting-on-a-vps) for the full nginx setup. diff --git a/deploy-web.sh.example b/deploy-web.sh.example new file mode 100644 index 0000000..ba92a09 --- /dev/null +++ b/deploy-web.sh.example @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# deploy-web.sh — build and push the web UI to the VPS. +# Assumes SSH agent forwarding is set up. +# +# SETUP: copy this file to deploy-web.sh (gitignored) and set HOST below. +# +# Usage: +# ./deploy-web.sh +# +# Optional env vars: +# HOST SSH target (user@host) (required — edit below) +# REMOTE_DIR path on VPS (default: ~/waste-www) + +set -euo pipefail + +HOST="${HOST:-user@YOUR_VPS_IP}" # ← edit this +REMOTE_DIR="${REMOTE_DIR:-~/waste-www}" + +if [[ "$HOST" == *YOUR_VPS_IP* ]]; then + echo "error: edit HOST in this script (or export HOST=user@your-vps before running)" >&2 + exit 1 +fi + +echo "→ building web UI…" +"$(dirname "$0")/build-web.sh" + +echo "→ syncing to $HOST:$REMOTE_DIR" +rsync -azv --delete \ + --exclude='config.js' \ + web/dist/ "$HOST:$REMOTE_DIR/" + +echo "✓ done" diff --git a/launch-tui.sh.example b/launch-tui.sh.example new file mode 100644 index 0000000..e11ec0b --- /dev/null +++ b/launch-tui.sh.example @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +# launch-tui.sh — build and launch the TUI against a remote anchor. +# Starts a local daemon then opens the Bubble Tea terminal UI. +# +# SETUP: copy this file to launch-tui.sh (gitignored) and set ANCHOR below. +# +# Usage: +# ./launch-tui.sh +# ALIAS=alice NETWORK=friends ./launch-tui.sh +# +# Optional env vars (all have defaults): +# ANCHOR anchor WebSocket URL (required — edit below) +# NETWORK network name to join (default: "friends") +# ALIAS display name (default: $USER) +# DATA_DIR identity + message store dir (default: ~/.waste-$ALIAS) +# IPC_PORT local daemon IPC port (default: 17337) +# SHARE_DIR directory to share with peers (optional) + +set -euo pipefail + +ANCHOR="${ANCHOR:-wss://YOUR_ANCHOR_DOMAIN/ws}" # ← edit this + +NETWORK="${NETWORK:-friends}" +ALIAS="${ALIAS:-${USER:-anon}}" +DATA_DIR="${DATA_DIR:-${HOME}/.waste-${ALIAS}}" + +_DEFAULT_ALIAS="${USER:-anon}" +if [ "${ALIAS}" = "${_DEFAULT_ALIAS}" ]; then + IPC_PORT="${IPC_PORT:-17337}" +else + _HASH=$(printf '%d' "0x$(printf '%s' "$ALIAS" | md5sum | cut -c1-4)") + IPC_PORT="${IPC_PORT:-$(( 17400 + _HASH % 1000 ))}" +fi + +SHARE_DIR="${SHARE_DIR:-}" + +RED='\033[0;31m'; GREEN='\033[0;32m'; DIM='\033[2m'; BOLD='\033[1m'; RESET='\033[0m' + +if [[ "$ANCHOR" == *YOUR_ANCHOR_DOMAIN* ]]; then + echo -e "${RED}error: edit ANCHOR in this script (or export ANCHOR=wss://... before running)${RESET}" >&2 + exit 1 +fi + +mkdir -p "$DATA_DIR" + +echo "" +echo -e "${BOLD}waste TUI${RESET}" +echo -e "${DIM}anchor : ${BOLD}${ANCHOR}${RESET}" +echo -e "${DIM}network : ${BOLD}${NETWORK}${RESET}" +echo -e "${DIM}alias : ${BOLD}${ALIAS}${RESET}" +echo -e "${DIM}data : ${DATA_DIR}${RESET}" +[ -n "$SHARE_DIR" ] && echo -e "${DIM}share : ${SHARE_DIR}${RESET}" +echo "" + +echo -e "${DIM}building binaries…${RESET}" +go build -o /tmp/waste-daemon-run ./cmd/daemon +go build -o /tmp/waste-tui-run ./cmd/tui +echo -e "${GREEN}✓ built${RESET}" +echo "" + +existing=$(lsof -ti tcp:"$IPC_PORT" 2>/dev/null || true) +[ -n "$existing" ] && kill "$existing" 2>/dev/null && sleep 0.3 || true + +echo -e "${DIM}starting daemon on :${IPC_PORT}…${RESET}" +WS_PORT=$(( IPC_PORT + 1 )) +/tmp/waste-daemon-run \ + -alias "$ALIAS" -data-dir "$DATA_DIR" \ + -ipc-port "$IPC_PORT" -ws-port "$WS_PORT" \ + -anchor "$ANCHOR" \ + 2>/tmp/waste-daemon.log & +DAEMON_PID=$! + +n=0 +while ! nc -z 127.0.0.1 "$IPC_PORT" 2>/dev/null; do + sleep 0.1; n=$(( n + 1 )) + [ "$n" -gt 80 ] && echo -e "${RED}daemon failed — check /tmp/waste-daemon.log${RESET}" >&2 && exit 1 +done +echo -e "${GREEN}✓ daemon started (pid ${DAEMON_PID})${RESET}" + +sleep 0.3 +if [ -n "$SHARE_DIR" ]; then + JOIN=$(jq -cn --arg net "$NETWORK" --arg dir "$SHARE_DIR" \ + '{"type":"join_network","network_name":$net,"share_dir":$dir}') +else + JOIN=$(jq -cn --arg net "$NETWORK" '{"type":"join_network","network_name":$net}') +fi +echo "$JOIN" | nc -q 0 127.0.0.1 "$IPC_PORT" >/dev/null 2>&1 || true +echo -e "${DIM}joined network: ${BOLD}${NETWORK}${RESET}" + +cleanup() { kill "$DAEMON_PID" 2>/dev/null || true; } +trap cleanup EXIT INT TERM + +echo "" +echo -e "${BOLD}launching TUI${RESET} — ${DIM}ctrl+c to quit${RESET}" +echo "" +exec /tmp/waste-tui-run -ipc "$IPC_PORT" -network "$NETWORK" diff --git a/launch-web.sh.example b/launch-web.sh.example new file mode 100644 index 0000000..844207c --- /dev/null +++ b/launch-web.sh.example @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# launch-web.sh — start the daemon and open the web UI Vite dev server. +# For local development / daemon-mode browsing. +# +# SETUP: copy this file to launch-web.sh (gitignored) and set ANCHOR below. +# +# Usage: +# ./launch-web.sh +# ALIAS=alice NETWORK=friends ./launch-web.sh + +set -euo pipefail + +ANCHOR="${ANCHOR:-wss://YOUR_ANCHOR_DOMAIN/ws}" # ← edit this + +NETWORK="${NETWORK:-friends}" +ALIAS="${ALIAS:-${USER:-anon}}" +DATA_DIR="${DATA_DIR:-${HOME}/.waste-${ALIAS}}" +IPC_PORT="${IPC_PORT:-17337}" +WS_PORT=$(( IPC_PORT + 1 )) + +if [[ "$ANCHOR" == *YOUR_ANCHOR_DOMAIN* ]]; then + echo "error: edit ANCHOR in this script (or export ANCHOR=wss://... before running)" >&2 + exit 1 +fi + +PIDS=() +cleanup() { + for pid in "${PIDS[@]:-}"; do kill "$pid" 2>/dev/null || true; done + wait 2>/dev/null || true +} +trap cleanup EXIT INT TERM + +for port in "$IPC_PORT" "$WS_PORT"; do + existing=$(lsof -ti tcp:"$port" 2>/dev/null || true) + [ -n "$existing" ] && kill "$existing" 2>/dev/null || true +done +for port in "$IPC_PORT" "$WS_PORT"; do + n=0 + while lsof -ti tcp:"$port" >/dev/null 2>&1; do + sleep 0.1; n=$(( n + 1 )); [ "$n" -gt 30 ] && break + done +done + +mkdir -p "$DATA_DIR" + +echo "alias : $ALIAS" +echo "network : $NETWORK" +echo "anchor : $ANCHOR" +echo "ws-port : $WS_PORT" +echo "" + +echo "building daemon…" +go build -o /tmp/waste-daemon-web ./cmd/daemon + +/tmp/waste-daemon-web \ + -alias "$ALIAS" -data-dir "$DATA_DIR" \ + -ipc-port "$IPC_PORT" -ws-port "$WS_PORT" \ + -anchor "$ANCHOR" \ + 2>/tmp/waste-daemon-web.log & +PIDS+=($!) + +n=0 +while ! nc -z 127.0.0.1 "$IPC_PORT" 2>/dev/null; do + sleep 0.1; n=$(( n + 1 )) + [ "$n" -gt 80 ] && echo "daemon failed to start — check /tmp/waste-daemon-web.log" >&2 && exit 1 +done + +sleep 0.2 +jq -cn --arg net "$NETWORK" '{"type":"join_network","network_name":$net}' \ + | nc -q0 127.0.0.1 "$IPC_PORT" >/dev/null 2>&1 || true +echo "daemon ready — joined $NETWORK" +echo "" + +npm run dev --prefix "$(dirname "$0")/web" diff --git a/serve-web.sh.example b/serve-web.sh.example new file mode 100644 index 0000000..1a97c02 --- /dev/null +++ b/serve-web.sh.example @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# serve-web.sh — start (or restart) the static file server on the VPS. +# Runs `npx serve` in the background, logs to ~/waste-www.log. +# +# SETUP: copy this file to serve-web.sh (gitignored) and set HOST below. +# +# Usage: +# ./serve-web.sh +# +# Optional env vars: +# HOST SSH target (user@host) (required — edit below) +# REMOTE_DIR path on VPS (default: ~/waste-www) +# PORT local port on VPS (default: 1337) + +set -euo pipefail + +HOST="${HOST:-user@YOUR_VPS_IP}" # ← edit this +REMOTE_DIR="${REMOTE_DIR:-~/waste-www}" +REMOTE_LOG="~/waste-www.log" +REMOTE_PID="~/waste-www.pid" +PORT="${PORT:-1337}" + +if [[ "$HOST" == *YOUR_VPS_IP* ]]; then + echo "error: edit HOST in this script (or export HOST=user@your-vps before running)" >&2 + exit 1 +fi + +ssh "$HOST" bash </dev/null || true + rm -f $REMOTE_PID + fi + + echo "[\$(date)] starting npx serve on port $PORT" >> $REMOTE_LOG + nohup npx serve -s $REMOTE_DIR -l $PORT >> $REMOTE_LOG 2>&1 & + echo \$! > $REMOTE_PID + echo "→ started (pid \$(cat $REMOTE_PID)), logging to $REMOTE_LOG" +EOF