1
This commit is contained in:
@@ -281,6 +281,100 @@ Get-CimInstance Win32_Process |
|
||||
fi
|
||||
}
|
||||
|
||||
is_tcp_port_available() {
|
||||
local host="$1"
|
||||
local port="$2"
|
||||
|
||||
# 中文注释:用真实 bind 探测端口,覆盖 127.0.0.1 与 0.0.0.0 互相占用的情况。
|
||||
node - "${host}" "${port}" <<'NODE'
|
||||
const net = require('net');
|
||||
const host = process.argv[2];
|
||||
const port = Number(process.argv[3]);
|
||||
|
||||
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const server = net.createServer();
|
||||
const timer = setTimeout(() => {
|
||||
server.close();
|
||||
process.exit(1);
|
||||
}, 1000);
|
||||
|
||||
server.once('error', () => {
|
||||
clearTimeout(timer);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
server.once('listening', () => {
|
||||
clearTimeout(timer);
|
||||
server.close(() => process.exit(0));
|
||||
});
|
||||
|
||||
server.listen({ host, port });
|
||||
NODE
|
||||
}
|
||||
|
||||
describe_tcp_port_owner() {
|
||||
local port="$1"
|
||||
|
||||
# 中文注释:Windows 下直接读取监听端口对应进程,便于用户精确停止旧 dev 栈。
|
||||
if command -v powershell.exe >/dev/null 2>&1; then
|
||||
GENARRATIVE_TCP_PORT="${port}" powershell.exe -NoProfile -Command '
|
||||
$portNumber = [int]$env:GENARRATIVE_TCP_PORT
|
||||
$connections = Get-NetTCPConnection -State Listen -LocalPort $portNumber -ErrorAction SilentlyContinue
|
||||
$seen = @{}
|
||||
foreach ($connection in $connections) {
|
||||
$processId = [int]$connection.OwningProcess
|
||||
if ($seen.ContainsKey($processId)) {
|
||||
continue
|
||||
}
|
||||
|
||||
$seen[$processId] = $true
|
||||
$process = Get-CimInstance Win32_Process -Filter "ProcessId = $processId" -ErrorAction SilentlyContinue
|
||||
if ($process) {
|
||||
$commandLine = ($process.CommandLine -replace "\s+", " ").Trim()
|
||||
"pid=$processId name=$($process.Name) address=$($connection.LocalAddress):$($connection.LocalPort) command=$commandLine"
|
||||
} else {
|
||||
"pid=$processId address=$($connection.LocalAddress):$($connection.LocalPort)"
|
||||
}
|
||||
}
|
||||
' 2>/dev/null || true
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v lsof >/dev/null 2>&1; then
|
||||
lsof -nP -iTCP:"${port}" -sTCP:LISTEN 2>/dev/null |
|
||||
awk 'NR > 1 { print "pid=" $2 " name=" $1 " address=" $9 }' || true
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
ss -ltnp "sport = :${port}" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_tcp_port_available() {
|
||||
local label="$1"
|
||||
local host="$2"
|
||||
local port="$3"
|
||||
local owners
|
||||
|
||||
# 中文注释:完整栈不复用旧 api-server / Vite,避免健康检查命中旧进程后继续误判。
|
||||
if is_tcp_port_available "${host}" "${port}"; then
|
||||
return
|
||||
fi
|
||||
|
||||
owners="$(describe_tcp_port_owner "${port}")"
|
||||
echo "[dev:rust] ${label} 端口已被占用,无法启动: ${host}:${port}" >&2
|
||||
if [[ -n "${owners}" ]]; then
|
||||
echo "[dev:rust] 当前监听进程:" >&2
|
||||
echo "${owners}" >&2
|
||||
fi
|
||||
echo "[dev:rust] 请停止占用进程,或通过对应端口参数换端口后重试。" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
wait_for_api_server() {
|
||||
local health_url="$1"
|
||||
local timeout_seconds="$2"
|
||||
@@ -545,6 +639,10 @@ echo "[dev:rust] spacetime root: ${SPACETIME_ROOT_DIR}"
|
||||
echo "[dev:rust] spacetime data: ${SPACETIME_DATA_DIR}"
|
||||
echo "[dev:rust] api timeout: ${API_SERVER_TIMEOUT_SECONDS}s"
|
||||
|
||||
ensure_tcp_port_available "Rust api-server" "${API_HOST}" "${API_PORT}"
|
||||
ensure_tcp_port_available "主站 Vite" "${WEB_HOST}" "${WEB_PORT}"
|
||||
ensure_tcp_port_available "后台 Vite" "${ADMIN_WEB_HOST}" "${ADMIN_WEB_PORT}"
|
||||
|
||||
if [[ "${SKIP_SPACETIME}" -ne 1 ]]; then
|
||||
mkdir -p "${SPACETIME_ROOT_DIR}" "${SPACETIME_DATA_DIR}"
|
||||
SPACETIME_ROOT_OWNER="$(describe_spacetime_root_owner "${SPACETIME_DATA_DIR}")"
|
||||
@@ -633,7 +731,7 @@ echo "[dev:rust] 启动 vite"
|
||||
ADMIN_WEB_TARGET="http://${ADMIN_WEB_TARGET_HOST}:${ADMIN_WEB_PORT}" \
|
||||
ADMIN_WEB_PORT="${ADMIN_WEB_PORT}" \
|
||||
VITE_DEV_HOST="${WEB_HOST}" \
|
||||
exec node "${VITE_CLI_PATH}" "--port=${WEB_PORT}" "--host=${WEB_HOST}"
|
||||
exec node "${VITE_CLI_PATH}" "--port=${WEB_PORT}" "--host=${WEB_HOST}" "--strictPort"
|
||||
) &
|
||||
PIDS+=("$!")
|
||||
NAMES+=("vite")
|
||||
@@ -644,7 +742,7 @@ echo "[dev:rust] 启动 admin vite"
|
||||
ADMIN_API_TARGET="${RUST_SERVER_TARGET}" \
|
||||
GENARRATIVE_API_TARGET="${RUST_SERVER_TARGET}" \
|
||||
GENARRATIVE_API_PORT="${API_PORT}" \
|
||||
exec node "${VITE_CLI_PATH}" "--host=${ADMIN_WEB_HOST}" "--port=${ADMIN_WEB_PORT}"
|
||||
exec node "${VITE_CLI_PATH}" "--host=${ADMIN_WEB_HOST}" "--port=${ADMIN_WEB_PORT}" "--strictPort"
|
||||
) &
|
||||
PIDS+=("$!")
|
||||
NAMES+=("admin-vite")
|
||||
|
||||
Reference in New Issue
Block a user