mirror of
https://github.com/anten-ka/gotelegram_pro.git
synced 2026-05-19 14:36:05 +00:00
feat(v2.4.2): bot non-interactive install.sh actions
- install.sh: new bot_action_dispatch entry point for --action=X --json CLI invocation from the bot/scripts - install.sh: bot_action_change_template — reuses download_template + deploy_template_to_nginx, updates config.json template_id - install.sh: bot_action_change_lite_domain — regenerates telemt TOML with new fake-TLS mask domain, restarts telemt - bot.py: run_bot_action() subprocess wrapper parses JSON result - bot.py: cb_pro_confirm now performs real change-template when already in pro mode (fresh install still routes to CLI) - bot.py: cb_lite_domain now performs real change-lite-domain when already in lite mode - version -> 2.4.2
This commit is contained in:
246
install.sh
246
install.sh
@@ -1136,11 +1136,257 @@ menu_language() {
|
||||
esac
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
# Non-interactive action dispatcher (bot / CI / scripting interface)
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
# Usage examples:
|
||||
# gotelegram --action=change-template --template=th_ariclaw --json
|
||||
# gotelegram --action=change-lite-domain --domain=google.com --json
|
||||
#
|
||||
# Rules for action handlers:
|
||||
# - Only JSON may be written to stdout (the caller parses it).
|
||||
# - All human-oriented logging must go to stderr (log_* already do that).
|
||||
# - Exit code 0 on success, non-zero on failure (caller still parses JSON).
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
bot_emit_json() {
|
||||
# bot_emit_json <status> <message> [key=value ...]
|
||||
local status="$1"; shift
|
||||
local message="$1"; shift
|
||||
local extra="" kv k v
|
||||
for kv in "$@"; do
|
||||
k="${kv%%=*}"
|
||||
v="${kv#*=}"
|
||||
# escape backslashes and double quotes in value
|
||||
v="${v//\\/\\\\}"
|
||||
v="${v//\"/\\\"}"
|
||||
extra="${extra},\"${k}\":\"${v}\""
|
||||
done
|
||||
# escape message
|
||||
local msg_esc="${message//\\/\\\\}"
|
||||
msg_esc="${msg_esc//\"/\\\"}"
|
||||
printf '{"status":"%s","message":"%s"%s}\n' "$status" "$msg_esc" "$extra"
|
||||
}
|
||||
|
||||
# Update a single key in config.json without rewriting the whole file
|
||||
bot_update_config_field() {
|
||||
local key="$1"
|
||||
local value="$2"
|
||||
if [ ! -f "$GOTELEGRAM_CONFIG" ]; then
|
||||
return 1
|
||||
fi
|
||||
local tmp
|
||||
tmp=$(mktemp) || return 1
|
||||
if jq --arg k "$key" --arg v "$value" \
|
||||
'.[$k] = $v | .updated_at = (now | todate)' \
|
||||
"$GOTELEGRAM_CONFIG" > "$tmp" 2>/dev/null; then
|
||||
mv "$tmp" "$GOTELEGRAM_CONFIG"
|
||||
chmod 600 "$GOTELEGRAM_CONFIG"
|
||||
return 0
|
||||
fi
|
||||
rm -f "$tmp"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ── Action: change-template (pro mode only) ──────────────────────────────────
|
||||
bot_action_change_template() {
|
||||
local tpl_id="$1"
|
||||
local json_out="${2:-0}"
|
||||
|
||||
if [ -z "$tpl_id" ]; then
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "template id is required" "code=missing_arg"
|
||||
log_error "change-template: --template is required"
|
||||
return 2
|
||||
fi
|
||||
|
||||
# Must be in pro mode
|
||||
local mode
|
||||
mode=$(config_get mode 2>/dev/null || echo "")
|
||||
if [ "$mode" != "pro" ]; then
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "change-template requires pro mode (current: ${mode:-none})" "code=wrong_mode"
|
||||
log_error "change-template: current mode is '${mode:-none}', requires 'pro'"
|
||||
return 3
|
||||
fi
|
||||
|
||||
# Validate template id exists in catalog
|
||||
if ! get_template_info "$tpl_id" >/dev/null 2>&1; then
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "unknown template: $tpl_id" "code=unknown_template"
|
||||
log_error "change-template: template not found in catalog: $tpl_id"
|
||||
return 4
|
||||
fi
|
||||
|
||||
# Make sure git (and other deps) are present. download_template uses git
|
||||
# clone under the hood — on a minimal host (bootstrap-only install) git may
|
||||
# not be installed yet, and the clone would fail silently.
|
||||
ensure_deps >&2
|
||||
|
||||
log_info "change-template: downloading $tpl_id..."
|
||||
local template_dir
|
||||
template_dir=$(download_template "$tpl_id")
|
||||
if [ $? -ne 0 ] || [ -z "$template_dir" ] || [ ! -d "$template_dir" ] || [ ! -f "$template_dir/index.html" ]; then
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "download failed for $tpl_id" "code=download_failed"
|
||||
log_error "change-template: download_template failed for $tpl_id"
|
||||
return 5
|
||||
fi
|
||||
|
||||
log_info "change-template: deploying to nginx..."
|
||||
if ! deploy_template_to_nginx "$template_dir" >&2; then
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "deploy failed" "code=deploy_failed"
|
||||
return 6
|
||||
fi
|
||||
|
||||
# Reload nginx (no full restart needed for static files — but be safe)
|
||||
systemctl reload nginx 2>/dev/null || systemctl restart nginx 2>/dev/null
|
||||
|
||||
# Update config.json template_id field
|
||||
bot_update_config_field "template_id" "$tpl_id" || \
|
||||
log_warning "change-template: could not update config.json template_id"
|
||||
|
||||
local domain
|
||||
domain=$(config_get domain 2>/dev/null || echo "")
|
||||
log_success "change-template: $tpl_id deployed"
|
||||
|
||||
if [ "$json_out" = "1" ]; then
|
||||
bot_emit_json "success" "template changed to $tpl_id" \
|
||||
"template=$tpl_id" "domain=$domain" "mode=pro"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# ── Action: change-lite-domain ───────────────────────────────────────────────
|
||||
# Regenerates telemt TOML with a new fake-TLS mask domain. Lite mode only.
|
||||
bot_action_change_lite_domain() {
|
||||
local new_domain="$1"
|
||||
local json_out="${2:-0}"
|
||||
|
||||
if [ -z "$new_domain" ]; then
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "domain is required" "code=missing_arg"
|
||||
log_error "change-lite-domain: --domain is required"
|
||||
return 2
|
||||
fi
|
||||
|
||||
if ! validate_domain "$new_domain" 2>/dev/null; then
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "invalid domain: $new_domain" "code=invalid_domain"
|
||||
log_error "change-lite-domain: invalid domain: $new_domain"
|
||||
return 3
|
||||
fi
|
||||
|
||||
local mode
|
||||
mode=$(config_get mode 2>/dev/null || echo "")
|
||||
if [ "$mode" != "lite" ]; then
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "change-lite-domain requires lite mode (current: ${mode:-none})" "code=wrong_mode"
|
||||
log_error "change-lite-domain: current mode is '${mode:-none}', requires 'lite'"
|
||||
return 4
|
||||
fi
|
||||
|
||||
local secret port
|
||||
secret=$(get_config_value secret 2>/dev/null || echo "")
|
||||
port=$(get_config_value port 2>/dev/null || echo "443")
|
||||
|
||||
if [ -z "$secret" ]; then
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "no secret in config" "code=no_secret"
|
||||
log_error "change-lite-domain: no secret in config.json"
|
||||
return 5
|
||||
fi
|
||||
|
||||
log_info "change-lite-domain: regenerating telemt TOML..."
|
||||
generate_telemt_toml "$secret" "$port" "lite" "$new_domain" "443" >&2 || {
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "config generation failed" "code=gen_failed"
|
||||
return 6
|
||||
}
|
||||
|
||||
validate_telemt_config >&2 || {
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "config validation failed" "code=validate_failed"
|
||||
return 7
|
||||
}
|
||||
|
||||
restart_telemt >&2 || {
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "telemt restart failed" "code=restart_failed"
|
||||
return 8
|
||||
}
|
||||
|
||||
# Update both domain and mask_host fields in config.json
|
||||
bot_update_config_field "mask_host" "$new_domain" || \
|
||||
log_warning "change-lite-domain: could not update mask_host"
|
||||
bot_update_config_field "domain" "$new_domain" || \
|
||||
log_warning "change-lite-domain: could not update domain"
|
||||
|
||||
log_success "change-lite-domain: switched to $new_domain"
|
||||
|
||||
if [ "$json_out" = "1" ]; then
|
||||
bot_emit_json "success" "lite mask domain changed to $new_domain" \
|
||||
"domain=$new_domain" "mode=lite" "port=$port"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Main dispatcher — called from main() when --action=X is present
|
||||
bot_action_dispatch() {
|
||||
local action="" tpl_id="" domain="" json_out=0 arg
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--action=*) action="${arg#--action=}" ;;
|
||||
--template=*) tpl_id="${arg#--template=}" ;;
|
||||
--domain=*) domain="${arg#--domain=}" ;;
|
||||
--json) json_out=1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "$action" in
|
||||
change-template)
|
||||
bot_action_change_template "$tpl_id" "$json_out"
|
||||
return $?
|
||||
;;
|
||||
change-lite-domain)
|
||||
bot_action_change_lite_domain "$domain" "$json_out"
|
||||
return $?
|
||||
;;
|
||||
"")
|
||||
log_error "no --action specified"
|
||||
return 64
|
||||
;;
|
||||
*)
|
||||
[ "$json_out" = "1" ] && bot_emit_json "error" "unknown action: $action" "code=unknown_action"
|
||||
log_error "unknown action: $action"
|
||||
return 64
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ── Точка входа / Entry point ───────────────────────────────────────────────
|
||||
main() {
|
||||
# Non-interactive action mode: if --action=X is in args, dispatch and exit.
|
||||
# Must run BEFORE interactive banner/menus so the bot gets clean JSON.
|
||||
local a has_action=0
|
||||
for a in "$@"; do
|
||||
case "$a" in --action=*) has_action=1; break ;; esac
|
||||
done
|
||||
if [ "$has_action" = "1" ]; then
|
||||
check_root
|
||||
init_dirs
|
||||
# Для bot-экшенов тоже нужны зависимости (git для change-template), но
|
||||
# без шумного apt-get update если всё уже на месте.
|
||||
if ! check_deps_present; then
|
||||
ensure_deps >&2 || exit 1
|
||||
fi
|
||||
bot_action_dispatch "$@"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
check_root
|
||||
init_dirs
|
||||
|
||||
# Первый запуск: если критические зависимости отсутствуют — ставим их ДО
|
||||
# того как пользователь дойдёт до меню. На последующих запусках это просто
|
||||
# дёшево проверяет command -v по всем командам и ничего не делает.
|
||||
if ! check_deps_present; then
|
||||
log_step "Первый запуск: проверяю зависимости..."
|
||||
ensure_deps || {
|
||||
log_error "Не удалось установить зависимости. См. сообщения выше."
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# First-run language picker (before banner so banner appears in chosen lang)
|
||||
first_run_language_picker
|
||||
|
||||
|
||||
Reference in New Issue
Block a user