mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-15 12:53:31 +08:00
Developers currently start the API server and Vite frontend by hand with fixed ports. This script keeps that workflow fast while avoiding bind failures when a previous run or another service already owns one of the defaults. Constraint: Web UI must receive the actual backend URL whenever the backend port changes Rejected: Reuse Vite auto-port behavior alone | it would not check or report the backend port and could leave the browser pointed at 3456 Confidence: high Scope-risk: narrow Directive: Keep this script dependency-light so it remains usable on a default macOS developer machine Tested: bash -n scripts/start-web-ui.sh Tested: ./scripts/start-web-ui.sh --help Tested: occupied preferred ports 45678 and 45679, script switched to 45680 and 45681 and reached Web UI ready Not-tested: full bun run verify, script-only developer workflow change
207 lines
4.8 KiB
Bash
Executable File
207 lines
4.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
DESKTOP_DIR="${ROOT_DIR}/desktop"
|
|
HOST="${HOST:-127.0.0.1}"
|
|
SERVER_PORT_START="${SERVER_PORT:-3456}"
|
|
WEB_PORT_START="${WEB_PORT:-2024}"
|
|
MAX_PORT_SCAN="${MAX_PORT_SCAN:-100}"
|
|
RUN_ID="$(date +%s)-$RANDOM"
|
|
LOG_DIR="${LOG_DIR:-/tmp/cc-haha-web-ui-${RUN_ID}}"
|
|
SERVER_LOG="${LOG_DIR}/server.log"
|
|
WEB_LOG="${LOG_DIR}/web.log"
|
|
|
|
SERVER_PID=""
|
|
WEB_PID=""
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: scripts/start-web-ui.sh
|
|
|
|
Environment overrides:
|
|
SERVER_PORT=3456 preferred backend port
|
|
WEB_PORT=2024 preferred Web UI port
|
|
HOST=127.0.0.1 bind host for both processes
|
|
LOG_DIR=/tmp/... directory for server.log and web.log
|
|
|
|
The script checks the preferred ports first and scans upward when a port is busy.
|
|
EOF
|
|
}
|
|
|
|
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
usage
|
|
exit 0
|
|
fi
|
|
|
|
require_command() {
|
|
local command_name="$1"
|
|
if ! command -v "$command_name" >/dev/null 2>&1; then
|
|
echo "Missing required command: ${command_name}" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
is_port_in_use() {
|
|
local port="$1"
|
|
|
|
if command -v lsof >/dev/null 2>&1; then
|
|
lsof -nP -iTCP:"${port}" -sTCP:LISTEN >/dev/null 2>&1
|
|
return $?
|
|
fi
|
|
|
|
if command -v nc >/dev/null 2>&1; then
|
|
nc -z "${HOST}" "${port}" >/dev/null 2>&1
|
|
return $?
|
|
fi
|
|
|
|
echo "Missing lsof or nc; cannot check whether port ${port} is available." >&2
|
|
exit 1
|
|
}
|
|
|
|
find_available_port() {
|
|
local start_port="$1"
|
|
local port="${start_port}"
|
|
local end_port=$((start_port + MAX_PORT_SCAN))
|
|
|
|
while (( port <= end_port )); do
|
|
if ! is_port_in_use "${port}"; then
|
|
printf '%s\n' "${port}"
|
|
return 0
|
|
fi
|
|
port=$((port + 1))
|
|
done
|
|
|
|
echo "No available port found in range ${start_port}-${end_port}" >&2
|
|
exit 1
|
|
}
|
|
|
|
urlencode() {
|
|
bun -e 'console.log(encodeURIComponent(process.argv[1]))' "$1"
|
|
}
|
|
|
|
wait_for_http() {
|
|
local url="$1"
|
|
local log_file="$2"
|
|
|
|
for _ in $(seq 1 120); do
|
|
if curl -fsS "${url}" >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
|
|
if [[ -n "${SERVER_PID}" ]] && ! kill -0 "${SERVER_PID}" >/dev/null 2>&1; then
|
|
echo "Server process exited before ${url} became ready. Recent log:" >&2
|
|
tail -n 40 "${SERVER_LOG}" >&2 || true
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -n "${WEB_PID}" ]] && ! kill -0 "${WEB_PID}" >/dev/null 2>&1; then
|
|
echo "Web UI process exited before ${url} became ready. Recent log:" >&2
|
|
tail -n 40 "${WEB_LOG}" >&2 || true
|
|
exit 1
|
|
fi
|
|
|
|
sleep 1
|
|
done
|
|
|
|
echo "Timed out waiting for ${url}. Recent log:" >&2
|
|
tail -n 40 "${log_file}" >&2 || true
|
|
exit 1
|
|
}
|
|
|
|
cleanup() {
|
|
local exit_code=$?
|
|
|
|
if [[ -n "${WEB_PID}" ]]; then
|
|
kill "${WEB_PID}" >/dev/null 2>&1 || true
|
|
wait "${WEB_PID}" >/dev/null 2>&1 || true
|
|
fi
|
|
|
|
if [[ -n "${SERVER_PID}" ]]; then
|
|
kill "${SERVER_PID}" >/dev/null 2>&1 || true
|
|
wait "${SERVER_PID}" >/dev/null 2>&1 || true
|
|
fi
|
|
|
|
if [[ "${exit_code}" -ne 0 && "${exit_code}" -ne 130 && "${exit_code}" -ne 143 ]]; then
|
|
echo "Logs kept at ${LOG_DIR}" >&2
|
|
fi
|
|
}
|
|
|
|
trap cleanup EXIT
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
|
|
require_command bun
|
|
require_command curl
|
|
|
|
if [[ ! -d "${DESKTOP_DIR}" ]]; then
|
|
echo "Desktop directory not found: ${DESKTOP_DIR}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "${LOG_DIR}"
|
|
|
|
SERVER_PORT_RESOLVED="$(find_available_port "${SERVER_PORT_START}")"
|
|
WEB_PORT_RESOLVED="$(find_available_port "${WEB_PORT_START}")"
|
|
if [[ "${WEB_PORT_RESOLVED}" == "${SERVER_PORT_RESOLVED}" ]]; then
|
|
WEB_PORT_RESOLVED="$(find_available_port "$((WEB_PORT_RESOLVED + 1))")"
|
|
fi
|
|
|
|
SERVER_URL="http://${HOST}:${SERVER_PORT_RESOLVED}"
|
|
WEB_URL="http://${HOST}:${WEB_PORT_RESOLVED}/?serverUrl=$(urlencode "${SERVER_URL}")"
|
|
|
|
if [[ "${SERVER_PORT_RESOLVED}" != "${SERVER_PORT_START}" ]]; then
|
|
echo "Server port ${SERVER_PORT_START} is busy; using ${SERVER_PORT_RESOLVED}."
|
|
fi
|
|
|
|
if [[ "${WEB_PORT_RESOLVED}" != "${WEB_PORT_START}" ]]; then
|
|
echo "Web UI port ${WEB_PORT_START} is busy; using ${WEB_PORT_RESOLVED}."
|
|
fi
|
|
|
|
echo "Starting server: ${SERVER_URL}"
|
|
(
|
|
cd "${ROOT_DIR}"
|
|
SERVER_PORT="${SERVER_PORT_RESOLVED}" bun run src/server/index.ts --host "${HOST}" --port "${SERVER_PORT_RESOLVED}"
|
|
) >"${SERVER_LOG}" 2>&1 &
|
|
SERVER_PID=$!
|
|
|
|
wait_for_http "${SERVER_URL}/health" "${SERVER_LOG}"
|
|
|
|
echo "Starting Web UI: http://${HOST}:${WEB_PORT_RESOLVED}"
|
|
(
|
|
cd "${DESKTOP_DIR}"
|
|
VITE_DESKTOP_SERVER_URL="${SERVER_URL}" bun run dev -- --host "${HOST}" --port "${WEB_PORT_RESOLVED}" --strictPort
|
|
) >"${WEB_LOG}" 2>&1 &
|
|
WEB_PID=$!
|
|
|
|
wait_for_http "http://${HOST}:${WEB_PORT_RESOLVED}" "${WEB_LOG}"
|
|
|
|
cat <<EOF
|
|
|
|
Web UI is ready:
|
|
${WEB_URL}
|
|
|
|
Backend:
|
|
${SERVER_URL}
|
|
|
|
Logs:
|
|
${SERVER_LOG}
|
|
${WEB_LOG}
|
|
|
|
Press Ctrl-C to stop both processes.
|
|
EOF
|
|
|
|
while true; do
|
|
if ! kill -0 "${SERVER_PID}" >/dev/null 2>&1; then
|
|
wait "${SERVER_PID}"
|
|
exit $?
|
|
fi
|
|
|
|
if ! kill -0 "${WEB_PID}" >/dev/null 2>&1; then
|
|
wait "${WEB_PID}"
|
|
exit $?
|
|
fi
|
|
|
|
sleep 1
|
|
done
|