# ladder/lib_wallet_serve.sh — long-lived wallet daemon (harness-style) # # taler-harness uses WalletService + WalletClient over a unix socket so the # wallet shepherd stays up while bank confirm + wirewatch complete. Mon e2e # already mirrors that with `advanced serve`. Ladder historically used one-shot # CLI only → coins often stayed pendingIncoming (OK_BANK) until pay-wait. # # Source after lib.sh. Callers set: SCRATCH, WDB, CLI_JS or WALLET_CLI, NODE_BIN. # Optional: LADDER_WALLET_SERVE=1 (default), E2E_WALLET_SERVE (e2e alias). # # Public: # wallet_serve_resolve_bins — NODE_BIN + CLI path # wallet_serve_start — advanced serve --unix-path # wallet_serve_stop — kill daemon # wallet_serve_wcli args… — client via socket if up, else --wallet-db # wallet_serve_install_trap — EXIT cleanup (idempotent) : "${LADDER_WALLET_SERVE:=1}" # e2e reuses same default name : "${E2E_WALLET_SERVE:=${LADDER_WALLET_SERVE}}" WSOCK="${WSOCK:-}" WSERVE_PID="${WSERVE_PID:-}" _WALLET_SERVE_TRAP_INSTALLED="${_WALLET_SERVE_TRAP_INSTALLED:-0}" wallet_serve_resolve_bins() { # Prefer explicit WALLET_CLI / CLI_JS (.mjs); else find_wallet_cli from lib.sh if [ -z "${CLI_JS:-}" ] || [ ! -f "${CLI_JS:-}" ]; then if [ -n "${WALLET_CLI:-}" ] && [ -f "${WALLET_CLI}" ]; then CLI_JS="$WALLET_CLI" elif command -v find_wallet_cli >/dev/null 2>&1; then CLI_JS=$(find_wallet_cli 2>/dev/null || true) fi fi if [ -n "${CLI_JS:-}" ] && [ -f "$CLI_JS" ]; then WALLET_CLI="$CLI_JS" fi if [ -z "${NODE_BIN:-}" ] || [ ! -x "${NODE_BIN:-}" ]; then NODE_BIN=$(command -v node 2>/dev/null || true) fi # PATH for taler-helper-sqlite3 (harness/e2e preflight) local _path="${PATH:-}" case ":${_path}:" in *:/opt/homebrew/bin:*) ;; *) _path="/opt/homebrew/bin:/usr/local/bin:${HOME}/.local/bin:${_path}" ;; esac PATH="$_path" export PATH NODE_BIN CLI_JS WALLET_CLI } wallet_serve_stop() { if [ -n "${WSERVE_PID:-}" ] && kill -0 "$WSERVE_PID" 2>/dev/null; then kill "$WSERVE_PID" 2>/dev/null || true wait "$WSERVE_PID" 2>/dev/null || true fi WSERVE_PID="" if [ -n "${WSOCK:-}" ]; then rm -f "$WSOCK" 2>/dev/null || true fi } wallet_serve_start() { # Returns 0 if serve is up (or intentionally disabled); 1 if wanted but failed. wallet_serve_resolve_bins local want="${LADDER_WALLET_SERVE:-1}" # e2e callers may only set E2E_WALLET_SERVE if [ "${E2E_WALLET_SERVE:-}" = "0" ]; then want=0 fi if [ "$want" != "1" ]; then return 0 fi if [ -z "${NODE_BIN:-}" ] || [ ! -x "${NODE_BIN}" ]; then return 1 fi if [ -z "${WALLET_CLI:-}" ] || [ ! -f "${WALLET_CLI}" ]; then return 1 fi if [ -z "${WDB:-}" ]; then return 1 fi if [ -z "${SCRATCH:-}" ]; then SCRATCH=$(mktemp -d) fi WSOCK="${WSOCK:-$SCRATCH/wallet.sock}" wallet_serve_stop rm -f "$WSOCK" # harness: daemon owns DB; clients use --wallet-connection only (no concurrent --wallet-db) "$NODE_BIN" "$WALLET_CLI" --wallet-db="$WDB" --no-throttle --skip-defaults \ advanced serve --unix-path "$WSOCK" \ >"${SCRATCH}/wallet-serve.log" 2>&1 & WSERVE_PID=$! local i for i in $(seq 1 50); do if [ -S "$WSOCK" ] && kill -0 "$WSERVE_PID" 2>/dev/null; then return 0 fi # died early if ! kill -0 "$WSERVE_PID" 2>/dev/null; then break fi sleep 0.1 done wallet_serve_stop return 1 } wallet_serve_install_trap() { [ "${_WALLET_SERVE_TRAP_INSTALLED}" = "1" ] && return 0 _WALLET_SERVE_TRAP_INSTALLED=1 # Append to existing EXIT trap if any — stop serve first # shellcheck disable=SC2064 trap 'wallet_serve_stop' EXIT } # Run wallet-cli: prefer live serve socket (harness WalletClient path). # Optional first arg: max seconds (integer) → wrapped with timeout when available. wallet_serve_wcli() { wallet_serve_resolve_bins local maxc="" if [[ "${1:-}" =~ ^[0-9]+$ ]]; then maxc=$1 shift fi local -a cmd if [ -n "${NODE_BIN:-}" ] && [ -x "${NODE_BIN}" ] && [ -n "${WALLET_CLI:-}" ] && [ -f "${WALLET_CLI}" ]; then if [ -n "${WSERVE_PID:-}" ] && [ -S "${WSOCK:-}" ] && kill -0 "$WSERVE_PID" 2>/dev/null; then cmd=( "$NODE_BIN" "$WALLET_CLI" --wallet-connection="$WSOCK" --no-throttle "$@" ) else cmd=( "$NODE_BIN" "$WALLET_CLI" --wallet-db="${WDB:?}" --no-throttle --skip-defaults "$@" ) fi elif [ -n "${CLI_JS:-}" ] && [ -f "$CLI_JS" ]; then if [ -n "${WSERVE_PID:-}" ] && [ -S "${WSOCK:-}" ]; then cmd=( node "$CLI_JS" --wallet-connection="$WSOCK" --no-throttle "$@" ) else cmd=( node "$CLI_JS" --wallet-db="${WDB:?}" --no-throttle "$@" ) fi else if [ -n "${WSERVE_PID:-}" ] && [ -S "${WSOCK:-}" ]; then cmd=( taler-wallet-cli --wallet-connection="$WSOCK" --no-throttle "$@" ) else cmd=( taler-wallet-cli --wallet-db="${WDB:?}" --no-throttle "$@" ) fi fi if [ -n "$maxc" ]; then if command -v timeout >/dev/null 2>&1; then timeout -k 2 "$maxc" "${cmd[@]}" elif command -v gtimeout >/dev/null 2>&1; then gtimeout --kill-after=2 "$maxc" "${cmd[@]}" else "${cmd[@]}" fi else "${cmd[@]}" fi }