feat: OpsxAPI v1.0 全协议接口工作台
- 六协议调试:HTTP/GraphQL/WebSocket/SSE/Socket.IO/MQTT
- 集合树/多标签/多环境变量/历史记录,localStorage 持久化
- 导入:OpenAPI 2/3/3.1、Postman、Apifox、Apipost、cURL、HAR、
Insomnia、Hoppscotch、Markdown(自动识别,21 个单测覆盖)
- 导出:OpenAPI 3.0 JSON/YAML、Postman v2.1、Markdown 文档、
全量备份;单请求生成 cURL/fetch/Python/Go 代码
- Gin 服务:HTTP 代理、NDJSON 流式代理(SSE 透传)、
WebSocket 隧道(浏览器自定义握手 Header)
- 内置产品官网 /home 与用户文档站 /docs(SSR,随二进制交付)
- lucide 图标体系 + 品牌标识(Logo/favicon),明暗双主题
- 环境变量:彩色徽标切换器、管理弹窗、{{ 自动补全
This commit is contained in:
commit
dec66db5aa
182 files changed
+23377
No files matched your search
@@ -0,0 +1,275 @@
|
||||
#!/usr/bin/env bash
|
||||
# OpsxAPI launcher — scene profiles, not random process soup
|
||||
#
|
||||
# ./run.sh # = web
|
||||
# ./run.sh web # Gin 代理 + Vite(浏览器)
|
||||
# ./run.sh gui # Vite + Tauri 桌面(Gin 可选;默认也拉起方便对照)
|
||||
# ./run.sh all # Gin + Vite + Desktop
|
||||
# ./run.sh server|web-only|desktop # 单组件
|
||||
# ./run.sh stop|restart|status|help
|
||||
#
|
||||
# 设计:一份 Vite UI,Web/GUI 共用;Gin 对 Web 刚需,对 GUI 可选。
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_NAME="OpsxAPI"
|
||||
SERVER_PORT="${OPSXAPI_SERVER_PORT:-8787}"
|
||||
WEB_PORT="${OPSXAPI_WEB_PORT:-5173}"
|
||||
SERVER_DIR="apps/server"
|
||||
SERVER_BIN="opsxapi-server"
|
||||
SERVER_LABEL="com.opsx.api.server"
|
||||
WEB_LABEL="com.opsx.api.web"
|
||||
DESKTOP_LABEL="com.opsx.api.desktop"
|
||||
|
||||
# gui 默认是否顺带起 Gin(可用 OPSXAPI_GUI_WITH_SERVER=0 关掉)
|
||||
GUI_WITH_SERVER="${OPSXAPI_GUI_WITH_SERVER:-1}"
|
||||
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
|
||||
info() { echo -e "${BLUE}[INFO]${NC} $*"; }
|
||||
success() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||||
warning() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
error() { echo -e "${RED}[ERR]${NC} $*"; }
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
LOG_DIR="$SCRIPT_DIR/logs"
|
||||
mkdir -p "$LOG_DIR" "$SCRIPT_DIR/$SERVER_DIR/bin"
|
||||
SERVER_LOG="$LOG_DIR/server.log"
|
||||
WEB_LOG="$LOG_DIR/web.log"
|
||||
DESKTOP_LOG="$LOG_DIR/desktop.log"
|
||||
|
||||
export PATH="/Users/logan/.nvm/versions/node/v24.19.0/bin:/opt/homebrew/bin:/usr/local/bin:${HOME}/.cargo/bin:$PATH"
|
||||
|
||||
check_port() { lsof -ti:"$1" 2>/dev/null | head -1 || true; }
|
||||
|
||||
kill_port() {
|
||||
local pids
|
||||
pids="$(lsof -ti:"$1" 2>/dev/null || true)"
|
||||
if [ -n "$pids" ]; then
|
||||
info "释放端口 $1"
|
||||
# shellcheck disable=SC2086
|
||||
kill -9 $pids 2>/dev/null || true
|
||||
sleep 0.3
|
||||
fi
|
||||
}
|
||||
|
||||
start_detached() {
|
||||
local label="$1" log_file="$2" command="$3"
|
||||
if [ "$(uname -s)" = "Darwin" ] && command -v launchctl >/dev/null 2>&1; then
|
||||
launchctl remove "$label" 2>/dev/null || true
|
||||
launchctl submit -l "$label" -o "$log_file" -e "$log_file" -- /bin/bash -lc "$command"
|
||||
else
|
||||
nohup /bin/bash -lc "$command" >>"$log_file" 2>&1 </dev/null &
|
||||
fi
|
||||
}
|
||||
|
||||
stop_detached() {
|
||||
local label="$1"
|
||||
if [ "$(uname -s)" = "Darwin" ] && command -v launchctl >/dev/null 2>&1; then
|
||||
launchctl remove "$label" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_npm() {
|
||||
if [ ! -d "$SCRIPT_DIR/node_modules" ]; then
|
||||
warning "缺少 node_modules,正在 npm install..."
|
||||
npm install
|
||||
fi
|
||||
if [ ! -d "$SCRIPT_DIR/apps/desktop/node_modules" ]; then
|
||||
warning "desktop 缺少依赖,正在安装..."
|
||||
npm --prefix "$SCRIPT_DIR/apps/desktop" install
|
||||
fi
|
||||
}
|
||||
|
||||
build_server() {
|
||||
info "编译 Gin 服务..."
|
||||
(cd "$SCRIPT_DIR/$SERVER_DIR" && go build -o "$SCRIPT_DIR/$SERVER_DIR/bin/$SERVER_BIN" ./cmd/opsxapi)
|
||||
}
|
||||
|
||||
wait_http() {
|
||||
local url="$1" name="$2" retries="${3:-60}"
|
||||
local i=0
|
||||
while ! curl -fsS "$url" >/dev/null 2>&1; do
|
||||
i=$((i + 1))
|
||||
if [ "$i" -ge "$retries" ]; then
|
||||
error "$name 启动超时:$url"
|
||||
return 1
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
}
|
||||
|
||||
start_server() {
|
||||
if curl -fsS "http://127.0.0.1:$SERVER_PORT/health" >/dev/null 2>&1; then
|
||||
success "后端已在运行 :$SERVER_PORT"
|
||||
return 0
|
||||
fi
|
||||
info "启动后端 :$SERVER_PORT ..."
|
||||
: >"$SERVER_LOG"
|
||||
kill_port "$SERVER_PORT"
|
||||
build_server
|
||||
start_detached "$SERVER_LABEL" "$SERVER_LOG" \
|
||||
"export PATH=\"/opt/homebrew/bin:/usr/local/bin:\$PATH\"; cd \"$SCRIPT_DIR/$SERVER_DIR\" && exec env OPSXAPI_ADDR=\":$SERVER_PORT\" GIN_MODE=debug \"./bin/$SERVER_BIN\""
|
||||
wait_http "http://127.0.0.1:$SERVER_PORT/health" "后端"
|
||||
success "后端 UP http://127.0.0.1:$SERVER_PORT/health"
|
||||
}
|
||||
|
||||
stop_server() {
|
||||
stop_detached "$SERVER_LABEL"
|
||||
kill_port "$SERVER_PORT"
|
||||
success "后端已停止"
|
||||
}
|
||||
|
||||
start_web() {
|
||||
if curl -fsS "http://127.0.0.1:$WEB_PORT/" >/dev/null 2>&1; then
|
||||
success "Web 已在运行 :$WEB_PORT"
|
||||
return 0
|
||||
fi
|
||||
info "启动 Web UI :$WEB_PORT ..."
|
||||
: >"$WEB_LOG"
|
||||
ensure_npm
|
||||
kill_port "$WEB_PORT"
|
||||
start_detached "$WEB_LABEL" "$WEB_LOG" \
|
||||
"export PATH=\"/Users/logan/.nvm/versions/node/v24.19.0/bin:/opt/homebrew/bin:/usr/local/bin:\$PATH\"; cd \"$SCRIPT_DIR\" && exec npm run dev -w @opsxapi/web"
|
||||
wait_http "http://127.0.0.1:$WEB_PORT/" "Web UI" 80
|
||||
success "Web UP http://127.0.0.1:$WEB_PORT"
|
||||
}
|
||||
|
||||
stop_web() {
|
||||
stop_detached "$WEB_LABEL"
|
||||
kill_port "$WEB_PORT"
|
||||
success "Web 已停止"
|
||||
}
|
||||
|
||||
start_desktop() {
|
||||
# GUI 依赖同一份 Vite;先保证 5173
|
||||
start_web
|
||||
info "启动桌面 OpsxAPI ..."
|
||||
: >"$DESKTOP_LOG"
|
||||
ensure_npm
|
||||
# 清掉旧的 debug 进程(二进制名 OpsxAPI)
|
||||
pkill -f 'target/debug/OpsxAPI' 2>/dev/null || true
|
||||
pkill -f 'target/debug/opsxapi-desktop' 2>/dev/null || true
|
||||
stop_detached "$DESKTOP_LABEL"
|
||||
start_detached "$DESKTOP_LABEL" "$DESKTOP_LOG" \
|
||||
"export PATH=\"/Users/logan/.nvm/versions/node/v24.19.0/bin:/opt/homebrew/bin:/usr/local/bin:\$HOME/.cargo/bin:\$PATH\"; cd \"$SCRIPT_DIR/apps/desktop\" && exec npm run tauri -- dev"
|
||||
|
||||
local i=0
|
||||
while true; do
|
||||
if pgrep -f 'target/debug/OpsxAPI' >/dev/null 2>&1 \
|
||||
|| pgrep -f 'target/debug/opsxapi-desktop' >/dev/null 2>&1; then
|
||||
success "桌面 OpsxAPI 已启动(Dock 名应为 OpsxAPI)"
|
||||
return 0
|
||||
fi
|
||||
if grep -Eiq 'error:|panicked|could not compile' "$DESKTOP_LOG" 2>/dev/null; then
|
||||
error "桌面启动失败,见 $DESKTOP_LOG"
|
||||
tail -n 40 "$DESKTOP_LOG" || true
|
||||
return 1
|
||||
fi
|
||||
i=$((i + 1))
|
||||
if [ "$i" -ge 120 ]; then
|
||||
error "桌面启动超时,见 $DESKTOP_LOG"
|
||||
tail -n 40 "$DESKTOP_LOG" || true
|
||||
return 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
stop_desktop() {
|
||||
stop_detached "$DESKTOP_LABEL"
|
||||
pkill -f 'target/debug/OpsxAPI' 2>/dev/null || true
|
||||
pkill -f 'target/debug/opsxapi-desktop' 2>/dev/null || true
|
||||
pkill -f 'apps/desktop/node_modules/.bin/tauri' 2>/dev/null || true
|
||||
success "桌面已停止"
|
||||
}
|
||||
|
||||
status() {
|
||||
echo "$PROJECT_NAME 状态"
|
||||
if curl -fsS "http://127.0.0.1:$SERVER_PORT/health" >/dev/null 2>&1; then
|
||||
success "server :$SERVER_PORT UP $(curl -fsS "http://127.0.0.1:$SERVER_PORT/health")"
|
||||
else
|
||||
warning "server :$SERVER_PORT DOWN"
|
||||
fi
|
||||
if curl -fsS "http://127.0.0.1:$WEB_PORT/" >/dev/null 2>&1; then
|
||||
success "web :$WEB_PORT UP http://127.0.0.1:$WEB_PORT"
|
||||
else
|
||||
warning "web :$WEB_PORT DOWN"
|
||||
fi
|
||||
if pgrep -f 'target/debug/OpsxAPI' >/dev/null 2>&1 \
|
||||
|| pgrep -f 'target/debug/opsxapi-desktop' >/dev/null 2>&1; then
|
||||
success "gui OpsxAPI UP"
|
||||
else
|
||||
warning "gui OpsxAPI DOWN"
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<USAGE
|
||||
$PROJECT_NAME 启动脚本(场景 profile)
|
||||
|
||||
./run.sh # 同 web
|
||||
./run.sh web # 浏览器:Gin + Vite
|
||||
./run.sh gui # 桌面:Vite + Tauri(默认也起 Gin,OPSXAPI_GUI_WITH_SERVER=0 可关)
|
||||
./run.sh all # Gin + Vite + Desktop
|
||||
|
||||
./run.sh server # 只 Gin
|
||||
./run.sh web-only # 只 Vite
|
||||
./run.sh desktop # 只 Desktop(会确保 Vite)
|
||||
|
||||
./run.sh stop | restart | status | help
|
||||
|
||||
端口: server $SERVER_PORT / web $WEB_PORT
|
||||
日志: logs/{server,web,desktop}.log
|
||||
USAGE
|
||||
}
|
||||
|
||||
start_web_scene() {
|
||||
start_server
|
||||
start_web
|
||||
echo
|
||||
success "Web 场景就绪 → http://127.0.0.1:$WEB_PORT"
|
||||
}
|
||||
|
||||
start_gui_scene() {
|
||||
if [ "$GUI_WITH_SERVER" = "1" ]; then
|
||||
start_server
|
||||
else
|
||||
info "跳过 Gin(OPSXAPI_GUI_WITH_SERVER=0);桌面 HTTP 走 tauri-native"
|
||||
fi
|
||||
start_desktop
|
||||
echo
|
||||
success "GUI 场景就绪 → 桌面窗口 OpsxAPI"
|
||||
}
|
||||
|
||||
start_all_scene() {
|
||||
start_server
|
||||
start_web
|
||||
start_desktop
|
||||
echo
|
||||
success "All 就绪:Web + Desktop + Gin"
|
||||
}
|
||||
|
||||
stop_all() {
|
||||
stop_desktop || true
|
||||
stop_web || true
|
||||
stop_server || true
|
||||
}
|
||||
|
||||
cmd="${1:-web}"
|
||||
case "$cmd" in
|
||||
web|start) start_web_scene ;;
|
||||
gui|desktop-scene) start_gui_scene ;;
|
||||
all) start_all_scene ;;
|
||||
server) start_server ;;
|
||||
web-only) start_web ;;
|
||||
desktop|gui-only) start_desktop ;;
|
||||
stop) stop_all ;;
|
||||
restart)
|
||||
stop_all || true
|
||||
start_web_scene
|
||||
;;
|
||||
status) status ;;
|
||||
help|-h|--help) usage ;;
|
||||
*) error "未知命令: $cmd"; usage; exit 1 ;;
|
||||
esac
|
||||
Reference in new issue
Block a user