mirror of
https://github.com/anten-ka/gotelegram_pro.git
synced 2026-05-19 17:26:13 +00:00
v2.5.0: add legacy state migration
This commit is contained in:
15
DOCS_AI.md
15
DOCS_AI.md
@@ -437,6 +437,21 @@ switch_language ru|en
|
||||
|
||||
`restore_backup` разворачивает архив обратно, перезапускает telemt и nginx.
|
||||
|
||||
### 13.1 Upgrade migration (v2.5.0)
|
||||
|
||||
`install.sh` вызывает `auto_migrate_legacy_state` перед интерактивным меню и перед non-interactive `--action=...` для бота. Цель — комфортно обновляться даже с кривой старой логики без переустановки прокси:
|
||||
|
||||
- перед изменениями создаётся `/opt/gotelegram/backups/preupgrade_2.5.0_*.tar.gz`;
|
||||
- из старого `/etc/telemt/config.toml` вытаскиваются все строки `[access.users]`, а не только `main`;
|
||||
- если `main` отсутствует, он добавляется с первым найденным секретом, чтобы старые ссылки не потерялись;
|
||||
- сохраняются порт, `tls_domain`, `mask_port`, режим Lite/Pro, домен, язык, `stats_enabled`;
|
||||
- старый telemt TOML нормализуется под v2.5.0 с `[server.api]` и metrics, затем в него возвращается полный users block;
|
||||
- если сайт уже развёрнут, но template id неизвестен или старый `config.json` врёт, в `/var/www/gotelegram-site/.gotelegram_template_id` пишется `deployed_site`;
|
||||
- `config.json` переписывается в актуальный формат, но с сохранением `installed_at` и пользовательских настроек;
|
||||
- если telemt был активен и TOML был изменён, сервис перезапускается один раз.
|
||||
|
||||
Инвариант: миграция должна быть идемпотентной. Маркер `/opt/gotelegram/.migrated_2.5.0` предотвращает повторную нормализацию без причины.
|
||||
|
||||
---
|
||||
|
||||
## 14. Checklist: как обновить один файл и запушить
|
||||
|
||||
@@ -142,6 +142,8 @@ CLI и бот переведены на русский и английский.
|
||||
|
||||
Bootstrap.sh умеет сам обновлять всё, если запустить его повторно.
|
||||
|
||||
Начиная с **2.5.0** первый запуск новой версии делает автоматическую миграцию старого состояния: создаёт pre-upgrade архив в `/opt/gotelegram/backups/`, вытаскивает все ключи из `[access.users]`, сохраняет домен, порт, режим, язык, историю статистики и фактически развёрнутый сайт. Если старый `template_id` был неправильным или отсутствовал, сайт помечается как `deployed_site`, чтобы Telegram-бот не показывал первый установленный шаблон вместо текущего.
|
||||
|
||||
---
|
||||
|
||||
## 9. Удаление
|
||||
|
||||
@@ -348,6 +348,8 @@ def template_display_name(template_id: str) -> str:
|
||||
"""Resolve a template id to a human-friendly name from catalog/config."""
|
||||
if not template_id:
|
||||
return ""
|
||||
if template_id in ("deployed_site", "existing_site"):
|
||||
return "Existing deployed site"
|
||||
if template_id.startswith("custom_"):
|
||||
config = load_json(GOTELEGRAM_CONFIG) or {}
|
||||
source = config.get("template_source", "")
|
||||
|
||||
192
install.sh
192
install.sh
@@ -245,6 +245,195 @@ menu_version() {
|
||||
echo -e " ${DIM}$(printf '─%.0s' {1..54})${NC}"
|
||||
}
|
||||
|
||||
# ── Upgrade migration ────────────────────────────────────────────────────────
|
||||
snapshot_preupgrade_state() {
|
||||
local marker="$GOTELEGRAM_DIR/.preupgrade_${GOTELEGRAM_VERSION}_done"
|
||||
[ -f "$marker" ] && return 0
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
local ts tmp archive
|
||||
ts=$(date +%Y%m%d_%H%M%S)
|
||||
tmp="/tmp/gotelegram_preupgrade_${ts}"
|
||||
archive="$BACKUP_DIR/preupgrade_${GOTELEGRAM_VERSION}_${ts}.tar.gz"
|
||||
mkdir -p "$tmp"
|
||||
|
||||
[ -f "$GOTELEGRAM_CONFIG" ] && mkdir -p "$tmp/opt/gotelegram" && cp "$GOTELEGRAM_CONFIG" "$tmp/opt/gotelegram/config.json" 2>/dev/null
|
||||
[ -f "$TELEMT_CONFIG" ] && mkdir -p "$tmp/etc/telemt" && cp "$TELEMT_CONFIG" "$tmp/etc/telemt/config.toml" 2>/dev/null
|
||||
[ -f "$NGINX_SITE_CONF" ] && mkdir -p "$tmp/etc/nginx/sites-available" && cp "$NGINX_SITE_CONF" "$tmp/etc/nginx/sites-available/gotelegram" 2>/dev/null
|
||||
[ -d "$WEBSITE_ROOT" ] && mkdir -p "$tmp/var/www/gotelegram-site" && cp -a "$WEBSITE_ROOT/." "$tmp/var/www/gotelegram-site/" 2>/dev/null
|
||||
[ -f "$BOT_DIR/.env" ] && mkdir -p "$tmp/opt/gotelegram-bot" && cp "$BOT_DIR/.env" "$tmp/opt/gotelegram-bot/.env" 2>/dev/null
|
||||
|
||||
if tar czf "$archive" -C "$tmp" . 2>/dev/null; then
|
||||
log_dim "Pre-upgrade snapshot: $archive"
|
||||
touch "$marker" 2>/dev/null || true
|
||||
fi
|
||||
rm -rf "$tmp"
|
||||
}
|
||||
|
||||
read_config_or_default() {
|
||||
local key="$1" fallback="$2"
|
||||
config_get "$key" 2>/dev/null || echo "$fallback"
|
||||
}
|
||||
|
||||
detect_deployed_template_id() {
|
||||
local tpl=""
|
||||
if [ -f "$WEBSITE_ROOT/.gotelegram_template_id" ]; then
|
||||
tpl=$(head -1 "$WEBSITE_ROOT/.gotelegram_template_id" 2>/dev/null || echo "")
|
||||
[ -n "$tpl" ] && { echo "$tpl"; return 0; }
|
||||
fi
|
||||
if [ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ]; then
|
||||
echo "deployed_site"
|
||||
return 0
|
||||
fi
|
||||
tpl=$(read_config_or_default template_id "")
|
||||
[ -n "$tpl" ] && { echo "$tpl"; return 0; }
|
||||
echo ""
|
||||
}
|
||||
|
||||
detect_template_source() {
|
||||
local src
|
||||
if [ -f "$WEBSITE_ROOT/.gotelegram_template_source" ]; then
|
||||
src=$(head -1 "$WEBSITE_ROOT/.gotelegram_template_source" 2>/dev/null || echo "")
|
||||
[ -n "$src" ] && { echo "$src"; return 0; }
|
||||
fi
|
||||
[ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ] && return 0
|
||||
read_config_or_default template_source ""
|
||||
}
|
||||
|
||||
write_normalized_gotelegram_config() {
|
||||
local mode="$1" port="$2" secret="$3" mask_host="$4" domain="$5" tpl_id="$6" tpl_source="$7"
|
||||
local lang installed_at stats_enabled tmp
|
||||
lang=$(read_config_or_default language "$(get_language 2>/dev/null || echo en)")
|
||||
installed_at=$(read_config_or_default installed_at "$(date -Iseconds)")
|
||||
stats_enabled=$(read_config_or_default stats_enabled "")
|
||||
tmp=$(mktemp) || return 1
|
||||
|
||||
jq -n \
|
||||
--arg version "$GOTELEGRAM_VERSION" \
|
||||
--arg engine "telemt" \
|
||||
--arg mode "$mode" \
|
||||
--argjson port "$port" \
|
||||
--arg secret "$secret" \
|
||||
--arg mask_host "$mask_host" \
|
||||
--arg domain "$domain" \
|
||||
--arg template_id "$tpl_id" \
|
||||
--arg template_source "$tpl_source" \
|
||||
--arg language "$lang" \
|
||||
--arg installed_at "$installed_at" \
|
||||
--arg updated_at "$(date -Iseconds)" \
|
||||
--arg stats_enabled "$stats_enabled" \
|
||||
'{
|
||||
version: $version,
|
||||
engine: $engine,
|
||||
mode: $mode,
|
||||
port: $port,
|
||||
secret: $secret,
|
||||
mask_host: $mask_host,
|
||||
domain: $domain,
|
||||
template_id: $template_id,
|
||||
language: $language,
|
||||
installed_at: $installed_at,
|
||||
updated_at: $updated_at
|
||||
}
|
||||
+ (if $template_source != "" then {template_source: $template_source} else {} end)
|
||||
+ (if $stats_enabled == "true" then {stats_enabled: true} elif $stats_enabled == "false" then {stats_enabled: false} else {} end)' \
|
||||
> "$tmp" || { rm -f "$tmp"; return 1; }
|
||||
|
||||
mkdir -p "$(dirname "$GOTELEGRAM_CONFIG")"
|
||||
mv "$tmp" "$GOTELEGRAM_CONFIG"
|
||||
chmod 600 "$GOTELEGRAM_CONFIG"
|
||||
}
|
||||
|
||||
auto_migrate_legacy_state() {
|
||||
local marker="$GOTELEGRAM_DIR/.migrated_${GOTELEGRAM_VERSION}"
|
||||
local current_version
|
||||
current_version=$(read_config_or_default version "")
|
||||
if [ -f "$marker" ] && [ "$current_version" = "$GOTELEGRAM_VERSION" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
[ -f "$TELEMT_CONFIG" ] || [ -f "$GOTELEGRAM_CONFIG" ] || [ -d "$WEBSITE_ROOT" ] || return 0
|
||||
|
||||
log_step "Миграция состояния GoTelegram"
|
||||
snapshot_preupgrade_state
|
||||
|
||||
local mode port secret mask_host domain mask_port tpl_id tpl_source users_block tls_emulation changed=0 users_block_needs_write=0
|
||||
users_block=$(get_telemt_users_block "$TELEMT_CONFIG" 2>/dev/null || true)
|
||||
secret=$(get_config_value secret "$TELEMT_CONFIG" 2>/dev/null || echo "")
|
||||
[ -z "$secret" ] && secret=$(read_config_or_default secret "")
|
||||
[ -z "$secret" ] && secret=$(first_telemt_user_secret "$TELEMT_CONFIG" 2>/dev/null || echo "")
|
||||
[ -z "$secret" ] && secret=$(generate_hex 32)
|
||||
|
||||
if [ -n "$users_block" ] && ! printf '%s\n' "$users_block" | grep -qE '^[[:space:]]*main[[:space:]]*='; then
|
||||
users_block=$(printf 'main = "%s"\n%s\n' "$secret" "$users_block")
|
||||
users_block_needs_write=1
|
||||
fi
|
||||
if [ -z "$users_block" ]; then
|
||||
users_block="main = \"$secret\""
|
||||
users_block_needs_write=1
|
||||
fi
|
||||
|
||||
port=$(get_config_value port "$TELEMT_CONFIG" 2>/dev/null || echo "")
|
||||
[ -z "$port" ] && port=$(read_config_or_default port "443")
|
||||
[[ "$port" =~ ^[0-9]+$ ]] || port=443
|
||||
|
||||
mask_host=$(get_config_value mask_host "$TELEMT_CONFIG" 2>/dev/null || echo "")
|
||||
[ -z "$mask_host" ] && mask_host=$(read_config_or_default mask_host "google.com")
|
||||
domain=$(read_config_or_default domain "")
|
||||
mask_port=$(get_config_value mask_port "$TELEMT_CONFIG" 2>/dev/null || echo "")
|
||||
[ -z "$mask_port" ] && mask_port="443"
|
||||
tls_emulation=$(toml_bool_value censorship tls_emulation "$TELEMT_CONFIG" 2>/dev/null || echo "")
|
||||
|
||||
mode=$(read_config_or_default mode "")
|
||||
if [ -z "$mode" ]; then
|
||||
if [ -n "$domain" ] || [ "$tls_emulation" = "false" ] || grep -q 'dns_overrides' "$TELEMT_CONFIG" 2>/dev/null; then
|
||||
mode="pro"
|
||||
else
|
||||
mode="lite"
|
||||
fi
|
||||
fi
|
||||
if [ "$mode" = "pro" ]; then
|
||||
[ -z "$domain" ] && domain="$mask_host"
|
||||
[ -n "$domain" ] && mask_host="$domain"
|
||||
[ "$mask_port" = "443" ] && mask_port="8443"
|
||||
else
|
||||
domain=""
|
||||
mask_port="443"
|
||||
fi
|
||||
|
||||
tpl_id=$(detect_deployed_template_id)
|
||||
tpl_source=$(detect_template_source || echo "")
|
||||
if [ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ] && [ -n "$tpl_id" ]; then
|
||||
echo "$tpl_id" > "$WEBSITE_ROOT/.gotelegram_template_id" 2>/dev/null || true
|
||||
[ -n "$tpl_source" ] && echo "$tpl_source" > "$WEBSITE_ROOT/.gotelegram_template_source" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
if [ -f "$TELEMT_CONFIG" ]; then
|
||||
if ! grep -q '\[server.api\]' "$TELEMT_CONFIG" 2>/dev/null || \
|
||||
! grep -q 'metrics_listen' "$TELEMT_CONFIG" 2>/dev/null || \
|
||||
! grep -q "GoTelegram v${GOTELEGRAM_VERSION}" "$TELEMT_CONFIG" 2>/dev/null; then
|
||||
generate_telemt_toml "$secret" "$port" "$mode" "$mask_host" "$mask_port" "$TELEMT_CONFIG" >&2
|
||||
replace_telemt_users_block "$users_block" "$TELEMT_CONFIG"
|
||||
changed=1
|
||||
users_block_needs_write=0
|
||||
elif [ "$users_block_needs_write" = "1" ]; then
|
||||
replace_telemt_users_block "$users_block" "$TELEMT_CONFIG"
|
||||
changed=1
|
||||
fi
|
||||
fi
|
||||
|
||||
write_normalized_gotelegram_config "$mode" "$port" "$secret" "$mask_host" "$domain" "$tpl_id" "$tpl_source" || \
|
||||
log_warning "Не удалось нормализовать config.json"
|
||||
|
||||
if [ "$changed" = "1" ] && systemctl is-active --quiet "$TELEMT_SERVICE" 2>/dev/null; then
|
||||
log_info "Перезапускаю telemt, чтобы применить нормализованный конфиг..."
|
||||
restart_telemt || log_warning "telemt не перезапустился после миграции; проверьте journalctl -u telemt"
|
||||
fi
|
||||
|
||||
touch "$marker" 2>/dev/null || true
|
||||
log_success "Миграция завершена: ключи, режим, домен и сайт сохранены"
|
||||
}
|
||||
|
||||
# ── Install: mode selection ─────────────────────────────────────────────────
|
||||
menu_install() {
|
||||
# Check for v1
|
||||
@@ -1491,6 +1680,7 @@ main() {
|
||||
if ! check_deps_present; then
|
||||
ensure_deps >&2 || exit 1
|
||||
fi
|
||||
auto_migrate_legacy_state >&2 || true
|
||||
bot_action_dispatch "$@"
|
||||
exit $?
|
||||
fi
|
||||
@@ -1509,6 +1699,8 @@ main() {
|
||||
}
|
||||
fi
|
||||
|
||||
auto_migrate_legacy_state || true
|
||||
|
||||
# First-run language picker (before banner so banner appears in chosen lang)
|
||||
first_run_language_picker
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ create_backup() {
|
||||
# Шаблон сайта (если есть)
|
||||
if [ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ]; then
|
||||
mkdir -p "$tmp_dir/site"
|
||||
cp -r "$WEBSITE_ROOT"/* "$tmp_dir/site/"
|
||||
cp -a "$WEBSITE_ROOT/." "$tmp_dir/site/"
|
||||
log_dim "$(_t_or backup_site_included 'Шаблон сайта включён')"
|
||||
fi
|
||||
|
||||
@@ -277,7 +277,7 @@ restore_backup() {
|
||||
# Восстанавливаем шаблон сайта
|
||||
if [ -d "$backup_dir/site" ]; then
|
||||
mkdir -p "$WEBSITE_ROOT"
|
||||
cp -r "$backup_dir/site"/* "$WEBSITE_ROOT/"
|
||||
cp -a "$backup_dir/site/." "$WEBSITE_ROOT/"
|
||||
chown -R www-data:www-data "$WEBSITE_ROOT" 2>/dev/null
|
||||
log_success "$(_t_or backup_restored_site 'Шаблон сайта восстановлен')"
|
||||
fi
|
||||
|
||||
@@ -184,6 +184,72 @@ get_config_value() {
|
||||
esac
|
||||
}
|
||||
|
||||
get_telemt_users_block() {
|
||||
local config="${1:-$TELEMT_CONFIG}"
|
||||
[ -f "$config" ] || return 1
|
||||
awk '
|
||||
/^\[access\.users\]/ { in_users=1; next }
|
||||
/^\[/ && in_users { exit }
|
||||
in_users && /^[[:space:]]*[^#[:space:]][^=]*=/ { print }
|
||||
' "$config"
|
||||
}
|
||||
|
||||
first_telemt_user_secret() {
|
||||
local config="${1:-$TELEMT_CONFIG}"
|
||||
get_telemt_users_block "$config" | head -1 | sed 's/^[^=]*=[[:space:]]*//; s/^"//; s/".*$//' | tr -d ' '
|
||||
}
|
||||
|
||||
replace_telemt_users_block() {
|
||||
local users_block="$1"
|
||||
local config="${2:-$TELEMT_CONFIG}"
|
||||
[ -f "$config" ] || return 1
|
||||
[ -n "$users_block" ] || return 0
|
||||
|
||||
local tmp
|
||||
tmp=$(mktemp) || return 1
|
||||
awk -v users="$users_block" '
|
||||
BEGIN { split(users, lines, "\n") }
|
||||
/^\[access\.users\]/ {
|
||||
found=1
|
||||
print
|
||||
for (i = 1; i in lines; i++) {
|
||||
if (lines[i] != "") print lines[i]
|
||||
}
|
||||
in_users=1
|
||||
next
|
||||
}
|
||||
/^\[/ && in_users { in_users=0 }
|
||||
in_users { next }
|
||||
{ print }
|
||||
END {
|
||||
if (!found) {
|
||||
print ""
|
||||
print "[access.users]"
|
||||
for (i = 1; i in lines; i++) {
|
||||
if (lines[i] != "") print lines[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
' "$config" > "$tmp" && mv "$tmp" "$config"
|
||||
chmod 600 "$config"
|
||||
}
|
||||
|
||||
toml_bool_value() {
|
||||
local table="$1"
|
||||
local key="$2"
|
||||
local config="${3:-$TELEMT_CONFIG}"
|
||||
awk -v table="$table" -v key="$key" '
|
||||
$0 == "[" table "]" { in_table=1; next }
|
||||
/^\[/ && in_table { exit }
|
||||
in_table && $1 == key {
|
||||
sub(/^[^=]*=[[:space:]]*/, "")
|
||||
gsub(/[[:space:]]/, "")
|
||||
print
|
||||
exit
|
||||
}
|
||||
' "$config"
|
||||
}
|
||||
|
||||
# ── Валидация конфига ────────────────────────────────────────────────────────
|
||||
validate_telemt_config() {
|
||||
local config="${1:-$TELEMT_CONFIG}"
|
||||
|
||||
@@ -237,11 +237,15 @@ get_ssl_expiry() {
|
||||
# ── Деплой шаблона сайта ─────────────────────────────────────────────────────
|
||||
deploy_template_to_nginx() {
|
||||
local template_dir="$1"
|
||||
local template_id="${2:-}"
|
||||
local source_url=""
|
||||
|
||||
if [ ! -d "$template_dir" ] || [ ! -f "$template_dir/index.html" ]; then
|
||||
log_error "Шаблон не содержит index.html: $template_dir"
|
||||
return 1
|
||||
fi
|
||||
[ -z "$template_id" ] && template_id=$(basename "$template_dir")
|
||||
[ -f "$template_dir/.custom_git_source" ] && source_url=$(head -1 "$template_dir/.custom_git_source" 2>/dev/null || echo "")
|
||||
|
||||
# Бекапим старый сайт
|
||||
if [ -d "$WEBSITE_ROOT" ] && [ "$(ls -A "$WEBSITE_ROOT" 2>/dev/null)" ]; then
|
||||
@@ -251,7 +255,10 @@ deploy_template_to_nginx() {
|
||||
fi
|
||||
|
||||
mkdir -p "$WEBSITE_ROOT"
|
||||
cp -r "$template_dir"/* "$WEBSITE_ROOT/"
|
||||
cp -a "$template_dir/." "$WEBSITE_ROOT/"
|
||||
rm -f "$WEBSITE_ROOT/.custom_git_source" 2>/dev/null || true
|
||||
echo "$template_id" > "$WEBSITE_ROOT/.gotelegram_template_id" 2>/dev/null || true
|
||||
[ -n "$source_url" ] && echo "$source_url" > "$WEBSITE_ROOT/.gotelegram_template_source" 2>/dev/null || true
|
||||
chown -R www-data:www-data "$WEBSITE_ROOT" 2>/dev/null || chown -R nginx:nginx "$WEBSITE_ROOT" 2>/dev/null
|
||||
chmod -R 755 "$WEBSITE_ROOT"
|
||||
|
||||
@@ -334,7 +341,7 @@ remove_pro_mode() {
|
||||
# ── Смена шаблона ────────────────────────────────────────────────────────────
|
||||
switch_template() {
|
||||
local new_template_dir="$1"
|
||||
deploy_template_to_nginx "$new_template_dir"
|
||||
deploy_template_to_nginx "$new_template_dir" "$(basename "$new_template_dir")"
|
||||
# nginx не требует перезапуска — статика обновилась на месте
|
||||
log_success "Шаблон сайта обновлён"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user