|
|
@@ -0,0 +1,210 @@
|
|
|
+#!/bin/bash
|
|
|
+# =============================================================
|
|
|
+# tool-moyu.sh — AI「摸鱼」模拟器
|
|
|
+#
|
|
|
+# 作用:读取一段内容(默认本会话日志,或任意文件/stdin),
|
|
|
+# 循环「假装在处理」,模拟 AI 工作的样子。
|
|
|
+# 适合:需要看起来在干活、又不想真干活的时候 😏
|
|
|
+#
|
|
|
+# 用法:
|
|
|
+# ./tool-moyu.sh # 用内置内容摸鱼(默认)
|
|
|
+# ./tool-moyu.sh -n 3 # 循环 3 遍
|
|
|
+# ./tool-moyu.sh [文件] # 从文件读取(覆盖内置内容)
|
|
|
+# ./tool-moyu.sh --help # 帮助
|
|
|
+#
|
|
|
+# 选项:
|
|
|
+# -n N 循环 N 次(默认无限)
|
|
|
+# -d MS 每行间隔毫秒(默认随机 80-400)
|
|
|
+# -t 逐个字符「打字」效果
|
|
|
+# -s 静默模式:不打印假状态行,只循环内容
|
|
|
+# =============================================================
|
|
|
+
|
|
|
+set -euo pipefail
|
|
|
+
|
|
|
+LOOP_TIMES=0 # 0 = 无限
|
|
|
+DELAY_MS=0 # 0 = 随机 80-400
|
|
|
+TYPE_EFFECT=0
|
|
|
+SILENT=0
|
|
|
+
|
|
|
+show_usage() {
|
|
|
+ sed -n '1,20p' "$0"
|
|
|
+ exit 0
|
|
|
+}
|
|
|
+
|
|
|
+while [ $# -gt 0 ]; do
|
|
|
+ case "$1" in
|
|
|
+ -n) LOOP_TIMES="${2:?}"; shift 2 ;;
|
|
|
+ -d) DELAY_MS="${2:?}"; shift 2 ;;
|
|
|
+ -t) TYPE_EFFECT=1; shift ;;
|
|
|
+ -s) SILENT=1; shift ;;
|
|
|
+ --help|-h) show_usage ;;
|
|
|
+ -*) echo "Unknown option: $1" >&2; exit 1 ;;
|
|
|
+ *) break ;;
|
|
|
+ esac
|
|
|
+done
|
|
|
+
|
|
|
+# ---- 命令与对应输出(成对,命令后紧跟其输出更真实) ----
|
|
|
+COMMANDS=(
|
|
|
+ "go vet ./..."
|
|
|
+ "go test ./..."
|
|
|
+ "CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o admin_server ./cmd/server"
|
|
|
+ "pnpm typecheck"
|
|
|
+ "pnpm build"
|
|
|
+ "rsync -az --delete release/frontend/ root@18.220.34.224:/www/wwwroot/household/"
|
|
|
+ "ssh -p 10022 root@18.220.34.224 'systemctl restart backend-admin'"
|
|
|
+ "mysql -h127.0.0.1 -uhousehold -p**** household -e 'SHOW TABLES;'"
|
|
|
+ "curl -s -o /dev/null -w 'HTTP %{http_code}\\n' http://127.0.0.1:8081/"
|
|
|
+ "journalctl -u backend-admin -n 30 --no-pager"
|
|
|
+ "systemctl status backend-app"
|
|
|
+ "git log --oneline -5"
|
|
|
+)
|
|
|
+COMMAND_OUT=(
|
|
|
+ "ok 0.231s"
|
|
|
+ "ok git.ooo.ink/household/app 0.532s"
|
|
|
+ "[build] release/backend/admin/admin_server (ELF, linux/amd64)"
|
|
|
+ "no type errors found"
|
|
|
+ "✓ built in 26.39s"
|
|
|
+ "sent 2.4MB, 1.1MB/s"
|
|
|
+ "systemd[1]: Started backend-admin.service - Household Backend Admin."
|
|
|
+ "Tables: center_admins center_menus center_roles ... (19 total)"
|
|
|
+ "HTTP 200"
|
|
|
+ "[GIN-debug] Listening and serving HTTP on :8081"
|
|
|
+ "Active: active (running)"
|
|
|
+ "f37eec3 docs(deploy): 后端目录对齐测试机实际路径"
|
|
|
+)
|
|
|
+
|
|
|
+# ---- 独立行(工具调用返回 / 日志 / 少量 AI 动作) ----
|
|
|
+STANDALONE=(
|
|
|
+ "[read] docs/deploy-aaPanel.md 168 lines"
|
|
|
+ "[search] migrations → 3 results"
|
|
|
+ "[trace] RunMigrations → internal/pkg/database.RunMigrations"
|
|
|
+ "[snippet] buildDSN → user:pass@tcp(host:port)/db?parseTime=True"
|
|
|
+ "[deploy] backend-admin → active"
|
|
|
+ "[deploy] frontend-admin → HTTP 200"
|
|
|
+ "[check] SSH root@18.220.34.224:10022 → ok"
|
|
|
+ "[verify] curl admin.household.ooo.ink → 200 OK"
|
|
|
+ "[skip] no changes, up to date"
|
|
|
+ "[warn] config.yaml placeholder secret left as-is on server"
|
|
|
+ "ready for connections. socket: '/var/run/mysqld/mysqld.sock' port: 3306"
|
|
|
+ "schema_migrations: 20260828001 | dirty=0"
|
|
|
+ "dist/assets/index-*.js 95.77 kB │ gzip: 37.38 kB"
|
|
|
+ "vite v7.3.6 building client environment for production..."
|
|
|
+ "🤖 analyzing dependency graph..."
|
|
|
+ "📊 summarizing key decisions..."
|
|
|
+ "✍️ drafting implementation plan..."
|
|
|
+ "🔒 reviewing security config..."
|
|
|
+)
|
|
|
+
|
|
|
+# 输出/日志/错误行(可重复,作为“裸输出”随机插入)
|
|
|
+OUTPUTS=(
|
|
|
+ "PASS"
|
|
|
+ "ok"
|
|
|
+ "HTTP 200"
|
|
|
+ "Active: active (running)"
|
|
|
+ "[GIN-debug] Listening and serving HTTP on :8081"
|
|
|
+ "warn: chunk size exceeds 4000 kB"
|
|
|
+ "ERROR: failed to open source \"file://internal/migrations\""
|
|
|
+ "FATAL: database connection refused, retrying..."
|
|
|
+ "0 error(s), 5 warning(s)"
|
|
|
+ "migrations completed successfully"
|
|
|
+ "no type errors found"
|
|
|
+ "✓ 307 modules transformed."
|
|
|
+ "Build succeeded after 3 retries"
|
|
|
+)
|
|
|
+
|
|
|
+# 动态随机数字行(消除固定值反复出现)
|
|
|
+gen_rand_lines() {
|
|
|
+ local n=$((1 + RANDOM % 3)) # 1-3 条
|
|
|
+ local i r
|
|
|
+ for ((i=0;i<n;i++)); do
|
|
|
+ r=$((RANDOM % 4))
|
|
|
+ case $r in
|
|
|
+ 0) echo "ok $(awk 'BEGIN{srand(); printf "%.3f", 0.05+rand()*1.5}')s" ;;
|
|
|
+ 1) echo "dist/assets/index-*.js $(awk 'BEGIN{srand(); printf "%.2f", 8+rand()*300}') kB │ gzip: $(awk 'BEGIN{srand(); printf "%.2f", 3+rand()*80}') kB" ;;
|
|
|
+ 2) echo "Progress: $((5+RANDOM%95))%..." ;;
|
|
|
+ 3) echo "$((1+RANDOM%40)) test(s), $((RANDOM%4)) failed" ;;
|
|
|
+ esac
|
|
|
+ done
|
|
|
+}
|
|
|
+
|
|
|
+# 返回 $1 个不重复随机下标(0..$2-1)
|
|
|
+pick_unique() {
|
|
|
+ local count=$1 pool=$2
|
|
|
+ [ "$pool" -lt "$count" ] && count=$pool
|
|
|
+ seq 0 $((pool-1)) | sort -R | head -n "$count"
|
|
|
+}
|
|
|
+
|
|
|
+# 随机生成一段“工作日志”:命令(约一半带输出)+独立行+裸输出+动态数字,洗牌打乱
|
|
|
+# 块大小不规则、数字随机化,消除固定模式与重复数字
|
|
|
+gen_random_content() {
|
|
|
+ local cmdc=$((1 + RANDOM % 5)) # 1-5 条命令
|
|
|
+ local stc=$((2 + RANDOM % 6)) # 2-7 条独立行
|
|
|
+ local ci si oi i
|
|
|
+ LINES=()
|
|
|
+ # 命令:约一半紧跟输出(不一定成对,制造不规则块)
|
|
|
+ for ci in $(pick_unique "$cmdc" "${#COMMANDS[@]}"); do
|
|
|
+ LINES+=("\$ ${COMMANDS[$ci]}")
|
|
|
+ if [ $((RANDOM % 2)) -eq 0 ]; then LINES+=("${COMMAND_OUT[$ci]}"); fi
|
|
|
+ [ $((RANDOM % 4)) -eq 0 ] && LINES+=("") # 随机空行
|
|
|
+ done
|
|
|
+ # 独立行(不重复)
|
|
|
+ for si in $(pick_unique "$stc" "${#STANDALONE[@]}"); do
|
|
|
+ LINES+=("${STANDALONE[$si]}")
|
|
|
+ [ $((RANDOM % 3)) -eq 0 ] && LINES+=("") # 随机空行
|
|
|
+ done
|
|
|
+ # 裸输出行(可重复)
|
|
|
+ for ((i=0;i<$((2+RANDOM%4));i++)); do
|
|
|
+ LINES+=("${OUTPUTS[$((RANDOM % ${#OUTPUTS[@]}))]}")
|
|
|
+ done
|
|
|
+ # 动态随机数字行
|
|
|
+ while IFS= read -r l; do LINES+=("$l"); done < <(gen_rand_lines)
|
|
|
+ # 洗牌打乱整体顺序
|
|
|
+ local idx=($(seq 0 $((${#LINES[@]}-1)) | sort -R))
|
|
|
+ local shuffled=()
|
|
|
+ for i in "${idx[@]}"; do shuffled+=("${LINES[$i]}"); done
|
|
|
+ LINES=("${shuffled[@]}")
|
|
|
+}
|
|
|
+
|
|
|
+# 内容来源:文件参数 > 随机生成
|
|
|
+CONTENT="${1:-}"
|
|
|
+FILE_MODE=0
|
|
|
+if [ -n "$CONTENT" ] && [ -f "$CONTENT" ]; then
|
|
|
+ mapfile -t LINES < "$CONTENT"
|
|
|
+ FILE_MODE=1
|
|
|
+elif [ -n "$CONTENT" ] && [ "$CONTENT" != "-" ]; then
|
|
|
+ echo "File not found: $CONTENT, falling back to random content." >&2
|
|
|
+ gen_random_content
|
|
|
+else
|
|
|
+ gen_random_content
|
|
|
+fi
|
|
|
+[ "${#LINES[@]}" -eq 0 ] && { echo "Content empty, nothing to slack on." >&2; exit 1; }
|
|
|
+
|
|
|
+# 随机延时
|
|
|
+rand_delay() {
|
|
|
+ if [ "$DELAY_MS" -gt 0 ]; then sleep "$(awk -v d="$DELAY_MS" 'BEGIN{printf "%.3f", d/1000}')";
|
|
|
+ else sleep "$(awk -v lo=80 -v hi=400 'BEGIN{srand(); printf "%.3f", (lo+int(rand()*(hi-lo+1)))/1000}')"; fi
|
|
|
+}
|
|
|
+
|
|
|
+run_once() {
|
|
|
+ local line
|
|
|
+ for line in "${LINES[@]}"; do
|
|
|
+ if [ "$TYPE_EFFECT" = "1" ]; then
|
|
|
+ local i
|
|
|
+ for ((i=0; i<${#line}; i++)); do printf "%s" "${line:i:1}"; rand_delay; done
|
|
|
+ echo ""
|
|
|
+ else
|
|
|
+ echo "$line"
|
|
|
+ fi
|
|
|
+ rand_delay
|
|
|
+ done
|
|
|
+ echo "" # 每遍之间空行
|
|
|
+}
|
|
|
+
|
|
|
+n=0
|
|
|
+while [ "$LOOP_TIMES" -eq 0 ] || [ "$n" -lt "$LOOP_TIMES" ]; do
|
|
|
+ n=$((n+1))
|
|
|
+ # 每轮重新生成随机内容(避免内容固定导致反复重复);文件模式则用固定内容
|
|
|
+ [ "$FILE_MODE" = "0" ] && gen_random_content
|
|
|
+ run_once
|
|
|
+done
|
|
|
+exit 0
|