feat: OpsxDB 桌面数据库客户端首版入库

含工作台/连库多引擎字段与 SSH·SSL、结果编辑、Redis 键浏览、
Tauri 桌面与 docs/落地页;排除本地构建产物与 sidecar 二进制。
This commit is contained in:
logan committed 2026-09-19 22:43:45 +08:00
commit f8740d27f7
240 files changed
+21625

No files matched your search

Executable
+308
View File
@@ -0,0 +1,308 @@
#!/usr/bin/env bash
# OpsxDB 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 package # Tauri 安装包 + sidecar
# ./run.sh stop|restart|status|help
#
# 设计:一份 Vite UI,Web/GUI 共用;Gin 对 Web 刚需,对 GUI 可选。
set -euo pipefail
PROJECT_NAME="OpsxDB"
SERVER_PORT="${OPSXDB_SERVER_PORT:-8788}"
WEB_PORT="${OPSXDB_WEB_PORT:-5174}"
SERVER_DIR="apps/server"
SERVER_BIN="opsxdb-server"
SERVER_LABEL="com.opsx.db.server"
WEB_LABEL="com.opsx.db.web"
DESKTOP_LABEL="com.opsx.db.desktop"
# gui 默认是否顺带起 Gin(可用 OPSXDB_GUI_WITH_SERVER=0 关掉)
GUI_WITH_SERVER="${OPSXDB_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="${HOME}/.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/opsxdb)
}
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
# 默认仅本机;对外需 OPSXDB_BIND_PUBLIC=1
local bind_env="OPSXDB_ADDR=127.0.0.1:$SERVER_PORT"
if [ -n "${OPSXDB_ADDR:-}" ]; then
bind_env="OPSXDB_ADDR=$OPSXDB_ADDR"
elif [ "${OPSXDB_BIND_PUBLIC:-0}" = "1" ] || [ "${OPSXDB_BIND_PUBLIC:-}" = "true" ]; then
bind_env="OPSXDB_BIND_PUBLIC=1"
fi
start_detached "$SERVER_LABEL" "$SERVER_LOG" \
"export PATH=\"/opt/homebrew/bin:/usr/local/bin:\$PATH\"; cd \"$SCRIPT_DIR/$SERVER_DIR\" && exec env $bind_env 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 @opsxdb/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;先保证 5174
start_web
info "启动桌面 OpsxDB ..."
: >"$DESKTOP_LOG"
ensure_npm
# 清掉旧的 debug 进程(二进制名 OpsxDB)
pkill -f 'target/debug/OpsxDB' 2>/dev/null || true
pkill -f 'target/debug/opsxdb-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/OpsxDB' >/dev/null 2>&1 \
|| pgrep -f 'target/debug/opsxdb-desktop' >/dev/null 2>&1; then
success "桌面 OpsxDB 已启动(Dock 名应为 OpsxDB)"
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/OpsxDB' 2>/dev/null || true
pkill -f 'target/debug/opsxdb-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/OpsxDB' >/dev/null 2>&1 \
|| pgrep -f 'target/debug/opsxdb-desktop' >/dev/null 2>&1; then
success "gui OpsxDB UP"
else
warning "gui OpsxDB DOWN"
fi
}
package_desktop() {
info "构建桌面可安装包(含本机 sidecar)..."
ensure_npm
build_server
local triple
triple="$(rustc -vV 2>/dev/null | awk '/host:/ {print $2}')"
if [ -z "$triple" ]; then
error "无法检测 rustc host triple"
return 1
fi
local bin_dir="$SCRIPT_DIR/apps/desktop/src-tauri/binaries"
mkdir -p "$bin_dir"
cp "$SCRIPT_DIR/$SERVER_DIR/bin/$SERVER_BIN" "$bin_dir/opsxdb-server-$triple"
chmod +x "$bin_dir/opsxdb-server-$triple"
success "sidecar → binaries/opsxdb-server-$triple"
(
cd "$SCRIPT_DIR/apps/desktop"
export VITE_OPSXDB_API="http://127.0.0.1:$SERVER_PORT"
npm run tauri -- build
)
success "桌面包构建完成(见 apps/desktop/src-tauri/target/release/bundle)"
}
usage() {
cat <<USAGE
$PROJECT_NAME 启动脚本(场景 profile)
./run.sh # 同 web
./run.sh web # 浏览器:Gin + Vite
./run.sh gui # 桌面:Vite + Tauri(默认也起 Gin,OPSXDB_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(OPSXDB_GUI_WITH_SERVER=0);桌面 HTTP 走 tauri-native"
fi
start_desktop
echo
success "GUI 场景就绪 → 桌面窗口 OpsxDB"
}
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 ;;
package|dist) package_desktop ;;
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