#!/usr/bin/env bash # walletman 远程管理:deploy / start / stop / restart / status # 用法: ./wm.sh deploy|start|stop|restart|status set -euo pipefail JUMP_HOST="${JUMP_HOST:-ipay-jump}" TARGET_HOST="${TARGET_HOST:-ipay-test}" REMOTE_BASE="${REMOTE_BASE:-/home/ec2-user/walletman}" REMOTE_BIN_DIR="${REMOTE_BASE}/cmd/server" REMOTE_BIN="${REMOTE_BIN_DIR}/ipay.bin" REMOTE_WALLETS="${REMOTE_BASE}/cmd/wallets.json" REMOTE_PROXIES="${REMOTE_BASE}/cmd/proxies.json" REMOTE_FCM_CONFIG="${REMOTE_BIN_DIR}/config/fcm-service-account.json" REMOTE_LOG="${REMOTE_BASE}/walletman.log" REMOTE_PID="${REMOTE_BASE}/walletman.pid" GO_TLS_FLAG="${GO_TLS_FLAG:--tls golang}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" WALLETMAN_DIR="$(cd "${SCRIPT_DIR}/../walletman" && pwd)" log() { printf '\033[1;32m[wm]\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m[wm]\033[0m %s\n' "$*"; } die() { printf '\033[1;31m[wm]\033[0m %s\n' "$*" >&2; exit 1; } ssh_jump() { ssh -o ClearAllForwardings=yes -o BatchMode=yes "${JUMP_HOST}" "$@" } ssh_target() { ssh_jump ssh -o BatchMode=yes "${TARGET_HOST}" "$@" } remote_script() { ssh_target bash -s } # 远端 start/stop/status(deploy 也会 source 这段逻辑) run_remote_ctl() { local action="$1" local check_health="${2:-0}" remote_script </dev/null || true) if [[ -n "\${old_pid}" ]] && kill -0 "\${old_pid}" 2>/dev/null; then echo "stop pid=\${old_pid}" kill "\${old_pid}" || true sleep 1 kill -9 "\${old_pid}" 2>/dev/null || true fi rm -f "\${REMOTE_PID}" fi if pkill -f "\${REMOTE_BIN}" 2>/dev/null; then echo "stop pkill \${REMOTE_BIN}" sleep 1 fi } start_walletman() { if [[ ! -x "\${REMOTE_BIN}" ]]; then echo "binary not found: \${REMOTE_BIN}" >&2 exit 1 fi cd "\${REMOTE_BIN_DIR}" nohup "\${REMOTE_BIN}" \${GO_TLS_FLAG} >> "\${REMOTE_LOG}" 2>&1 & echo \$! > "\${REMOTE_PID}" echo "started pid=\$(cat "\${REMOTE_PID}")" } status_walletman() { if [[ -f "\${REMOTE_PID}" ]]; then pid=\$(cat "\${REMOTE_PID}" 2>/dev/null || true) if [[ -n "\${pid}" ]] && kill -0 "\${pid}" 2>/dev/null; then echo "running pid=\${pid}" else echo "not running (stale pid file)" fi else echo "not running" fi if curl -sf --max-time 5 http://127.0.0.1:16000/wallets >/dev/null; then echo "health ok" else echo "health fail" exit 1 fi } case "\${ACTION}" in stop) stop_walletman ;; start) stop_walletman start_walletman sleep 2 ;; restart) stop_walletman start_walletman sleep 2 ;; status) status_walletman; exit 0 ;; *) echo "unknown action \${ACTION}" >&2; exit 1 ;; esac if [[ "\${CHECK_HEALTH}" == "1" ]]; then if curl -sf --max-time 5 http://127.0.0.1:16000/wallets >/dev/null; then echo "health ok: http://127.0.0.1:16000/wallets" else echo "health check failed, tail log:" >&2 tail -n 30 "\${REMOTE_LOG}" >&2 || true exit 1 fi fi EOF } cmd_start() { log "start ${TARGET_HOST}" run_remote_ctl start 1 } cmd_stop() { log "stop ${TARGET_HOST}" run_remote_ctl stop 0 log "已停止" } cmd_restart() { log "restart ${TARGET_HOST}" run_remote_ctl restart 1 } cmd_status() { log "status ${TARGET_HOST}" run_remote_ctl status } cmd_deploy() { local build_dir staging tarball build_dir="$(mktemp -d)" staging="${build_dir}/staging" tarball="${build_dir}/walletman-deploy.tgz" trap 'rm -rf "${build_dir}"' EXIT local wallets_json="${WALLETMAN_DIR}/cmd/wallets.json" local proxies_json="${WALLETMAN_DIR}/cmd/proxies.json" local fcm_config="${WALLETMAN_DIR}/cmd/server/config/fcm-service-account.json" [[ -f "${wallets_json}" ]] || die "缺少 ${wallets_json}" [[ -f "${proxies_json}" ]] || die "缺少 ${proxies_json}" [[ -f "${fcm_config}" ]] || die "缺少 ${fcm_config}" log "构建 linux/amd64 二进制..." mkdir -p "${staging}/bin" "${staging}/test" "${staging}/cmd" "${staging}/config" ( cd "${WALLETMAN_DIR}" GOOS=linux GOARCH=amd64 go build -buildvcs=false -ldflags="-s -w" -o "${staging}/bin/ipay.bin" ./cmd/server ) cp -R "${WALLETMAN_DIR}/test/." "${staging}/test/" cp "${wallets_json}" "${staging}/cmd/wallets.json" cp "${proxies_json}" "${staging}/cmd/proxies.json" cp "${fcm_config}" "${staging}/config/fcm-service-account.json" if [[ "$(uname -s)" == Darwin ]]; then xattr -cr "${staging}" 2>/dev/null || true fi log "打包..." if [[ "$(uname -s)" == Darwin ]]; then COPYFILE_DISABLE=1 tar --no-xattrs -czf "${tarball}" -C "${staging}" bin test cmd config 2>/dev/null \ || COPYFILE_DISABLE=1 tar -czf "${tarball}" -C "${staging}" bin test cmd config else tar czf "${tarball}" -C "${staging}" bin test cmd config fi log "上传到 ${JUMP_HOST}..." scp -o ClearAllForwardings=yes "${tarball}" "${JUMP_HOST}:/tmp/walletman-deploy.tgz" ssh_jump scp "/tmp/walletman-deploy.tgz" "${TARGET_HOST}:/tmp/walletman-deploy.tgz" log "分发到 ${TARGET_HOST}:${REMOTE_BASE} ..." remote_script </dev/null \ || tar xzf walletman-deploy.tgz 2>/dev/null \ || tar xzf walletman-deploy.tgz rm -f walletman-deploy.tgz if [[ -f "\${REMOTE_BIN}" ]]; then cp "\${REMOTE_BIN}" "\${REMOTE_BIN}.bak.\$(date +%Y%m%d%H%M%S)" fi install -m 755 bin/ipay.bin "\${REMOTE_BIN}" rsync -a test/ "\${REMOTE_BASE}/test/" ln -sfn ../../test "\${REMOTE_BIN_DIR}/test" if [[ -f "\${REMOTE_WALLETS}" ]]; then cp "\${REMOTE_WALLETS}" "\${REMOTE_WALLETS}.bak.\$(date +%Y%m%d%H%M%S)" fi install -m 644 cmd/wallets.json "\${REMOTE_WALLETS}" install -m 600 cmd/proxies.json "\${REMOTE_PROXIES}" install -m 600 config/fcm-service-account.json "\${REMOTE_FCM_CONFIG}" rm -f "\${REMOTE_BIN_DIR}/wallets.json" EOF ssh_jump rm -f /tmp/walletman-deploy.tgz log "文件已更新,重启服务..." run_remote_ctl restart 1 log "部署完成: ${TARGET_HOST}:${REMOTE_BIN}" log "wallets.json → ${REMOTE_WALLETS}" log "fcm config → ${REMOTE_FCM_CONFIG}" log "proxies.json → ${REMOTE_PROXIES}" } usage() { cat < deploy 构建并部署到 ${TARGET_HOST},然后 restart start 启动远端 walletman stop 停止远端 walletman restart 重启远端 walletman status 查看进程与健康检查 环境变量: JUMP_HOST TARGET_HOST REMOTE_BASE GO_TLS_FLAG EOF } main() { local cmd="${1:-}" case "${cmd}" in deploy|--deploy) cmd_deploy ;; start|--start) cmd_start ;; stop|--stop) cmd_stop ;; restart|--restart) cmd_restart ;; status|--status) cmd_status ;; -h|--help|help|"") usage ;; *) die "未知命令: ${cmd}(见 --help)" ;; esac } main "$@"