From 97af8904ef1b457521dae9477c109fb7fc5d6991 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Thu, 23 Jul 2026 16:11:06 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=96=B0=E5=A2=9E=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E8=B5=84=E4=BA=A7=E5=AF=BC=E5=85=A5=E8=84=9A=E6=9C=AC=EF=BC=8C?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=96=B0=E7=AE=A1=E7=90=86=E7=AB=AF=E6=97=A0?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E6=97=A0=E6=B3=95=E9=83=A8=E7=BD=B2=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - import-assets.py: Python 脚本,从 configs 目录导入模板/场景/覆盖层到 SQLite - import-assets.sh: Bash 备选方案 - assets-import.tar.gz: 包含 edge 项目的 configs 和导入脚本的离线包 待办: 管理端启动时应自动检测空库并导入种子数据 --- assets-import.tar.gz | Bin 0 -> 6494 bytes scripts/deploy/import-assets.py | 75 ++++++++++++++++++++++++++++++++ scripts/deploy/import-assets.sh | 69 +++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 assets-import.tar.gz create mode 100644 scripts/deploy/import-assets.py create mode 100644 scripts/deploy/import-assets.sh diff --git a/assets-import.tar.gz b/assets-import.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..e7544b3b17e67beed63ce35af2e1a37f1b910f38 GIT binary patch literal 6494 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 E0Q@=5?f?J) literal 0 HcmV?d00001 diff --git a/scripts/deploy/import-assets.py b/scripts/deploy/import-assets.py new file mode 100644 index 0000000..990cfbb --- /dev/null +++ b/scripts/deploy/import-assets.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +"""SafeSight 初始资产导入脚本 +将 edge 项目 configs 目录下的模板/场景/覆盖层导入管理端数据库 +用法: sudo python3 import-assets.py /tmp/configs +""" +import sys, os, json, sqlite3 +from datetime import datetime, timezone + +def main(): + configs_dir = sys.argv[1] if len(sys.argv) > 1 else "/tmp/configs" + db_path = "/opt/safesightd/data/app.db" + + if not os.path.isfile(db_path): + print(f"错误: 数据库文件不存在: {db_path}") + sys.exit(1) + + conn = sqlite3.connect(db_path) + now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + kinds = [ + ("templates", "templates", ["name", "description", "body_json", "created_at", "updated_at"]), + ("profiles", "profiles", ["name", "primary_template_name", "business_name", "description", "body_json", "created_at", "updated_at"]), + ("overlays", "overlays", ["name", "description", "body_json", "created_at", "updated_at"]), + ] + + print("========== SafeSight 资产导入 ==========") + print(f"数据库: {db_path}") + print(f"配置源: {configs_dir}\n") + + for dir_name, table, cols in kinds: + src_dir = os.path.join(configs_dir, dir_name) + if not os.path.isdir(src_dir): + print(f" ⚠ 目录不存在: {src_dir}") + continue + + count = 0 + for fname in sorted(os.listdir(src_dir)): + if not fname.endswith(".json"): + continue + fpath = os.path.join(src_dir, fname) + name = fname[:-5] # remove .json + + with open(fpath, "r", encoding="utf-8") as f: + body = f.read() + + placeholders = ", ".join(["?" for _ in cols]) + col_names = ", ".join(cols) + + if table == "templates": + values = [name, "", body, now, now] + elif table == "overlays": + values = [name, "", body, now, now] + else: # profiles + values = [name, "", "", "", body, now, now] + + try: + conn.execute( + f"INSERT OR IGNORE INTO {table} ({col_names}) VALUES ({placeholders})", + values, + ) + count += 1 + print(f" ✓ {dir_name.rstrip('s')}: {name}") + except Exception as e: + print(f" ✗ {name}: {e}") + + conn.commit() + if count > 0: + print(f" → 导入 {count} 个\n") + + conn.close() + print("========== 导入完成 ==========") + print("\n请执行: sudo systemctl restart safesightd") + +if __name__ == "__main__": + main() diff --git a/scripts/deploy/import-assets.sh b/scripts/deploy/import-assets.sh new file mode 100644 index 0000000..f219c6c --- /dev/null +++ b/scripts/deploy/import-assets.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# SafeSight 初始资产导入脚本 +# 将 edge 项目 configs 目录下的模板/场景/覆盖层导入管理端数据库 +# 用法: sudo bash import-assets.sh + +set -e + +DB="/opt/safesightd/data/app.db" +CONFIGS_DIR="${1:-/tmp/configs}" + +if [ ! -f "$DB" ]; then + echo "错误: 数据库文件不存在: $DB" + exit 1 +fi + +if [ ! -d "$CONFIGS_DIR/templates" ]; then + echo "错误: configs 目录不存在: $CONFIGS_DIR" + echo "请先把 edge 项目的 configs/templates configs/profiles configs/overlays 复制到 $CONFIGS_DIR" + exit 1 +fi + +NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ") +T=0; P=0; O=0 + +import_json() { + local table="$1" name="$2" file="$3" + # 使用 base64 编码绕过 JSON 中的特殊字符问题 + local b64=$(cat "$file" | base64 -w0) + sqlite3 "$DB" "INSERT OR IGNORE INTO ${table} (name, description, body_json, created_at, updated_at) + VALUES ('${name}', '', CAST(X'$(echo -n "$b64" | base64 -d | xxd -p -c0 | tr -d '\n')' AS TEXT), '${NOW}', '${NOW}');" +} + +echo "========== SafeSight 资产导入 ==========" +echo "数据库: $DB" +echo "配置源: $CONFIGS_DIR" +echo "" + +# 导入模板 +for f in "$CONFIGS_DIR/templates"/*.json; do + [ -f "$f" ] || continue + name=$(basename "$f" .json) + import_json "templates" "$name" "$f" + echo " ✓ 模板: $name" + ((T++)) +done + +# 导入场景 +for f in "$CONFIGS_DIR/profiles"/*.json; do + [ -f "$f" ] || continue + name=$(basename "$f" .json) + import_json "profiles" "$name" "$f" + echo " ✓ 场景: $name" + ((P++)) +done + +# 导入覆盖层 +for f in "$CONFIGS_DIR/overlays"/*.json; do + [ -f "$f" ] || continue + name=$(basename "$f" .json) + import_json "overlays" "$name" "$f" + echo " ✓ 覆盖层: $name" + ((O++)) +done + +echo "" +echo "========== 导入完成 ==========" +echo "模板: $T 场景: $P 覆盖层: $O" +echo "" +echo "请执行: sudo systemctl restart safesightd"