You've already forked Atomcms-edit
391458ce49
Add fallback logic to try capitalized branch name if the specified branch is not found, with a clear error message if neither exists.
584 lines
22 KiB
Bash
Executable File
584 lines
22 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
# =============================================================================
|
|
# EPIC WEB CONTROL — Enterprise Update Script
|
|
# Compatible with Laravel 13 + Nitro V3 + MariaDB
|
|
# =============================================================================
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
# --- Load .env ---------------------------------------------------------------
|
|
if [ -f "$SCRIPT_DIR/.env" ]; then
|
|
set -a
|
|
. "$SCRIPT_DIR/.env"
|
|
set +a
|
|
fi
|
|
|
|
# --- Logging -----------------------------------------------------------------
|
|
LOG_DIR="${NITRO_LOG_DIR:-$SCRIPT_DIR/storage/logs}"
|
|
mkdir -p "$LOG_DIR"
|
|
LOG_FILE="$LOG_DIR/update-$(date +%Y%m%d-%H%M%S).log"
|
|
exec > >(tee -a "$LOG_FILE") 2>&1
|
|
|
|
STEP_NUM=0
|
|
STEP_TOTAL=8
|
|
START_TIME=$(date +%s)
|
|
|
|
step() {
|
|
STEP_NUM=$((STEP_NUM + 1))
|
|
echo ""
|
|
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
printf "║ Step %d/%d — %-49s║\n" "$STEP_NUM" "$STEP_TOTAL" "$1"
|
|
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
}
|
|
|
|
info() { echo " --> $1"; }
|
|
ok() { echo " [OK] $1"; }
|
|
warn() { echo " [WARN] $1"; }
|
|
fail() { echo " [FAIL] $1"; }
|
|
die() { echo ""; echo "=== ❌ $1 ==="; cleanup_notify_failure "$1"; exit 1; }
|
|
|
|
# --- Notifications -----------------------------------------------------------
|
|
NOTIFY_URL="${NITRO_NOTIFY_URL:-}"
|
|
NOTIFY_FAILED=false
|
|
|
|
notify() {
|
|
local status="$1"
|
|
local message="$2"
|
|
[ -z "$NOTIFY_URL" ] && return 0
|
|
local elapsed=$(( $(date +%s) - START_TIME ))
|
|
local elapsed_fmt
|
|
elapsed_fmt=$(printf '%dm %ds' $((elapsed/60)) $((elapsed%60)))
|
|
curl -s -o /dev/null -X POST "$NOTIFY_URL" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"text\": \"[Nitro Update] $status\",
|
|
\"attachments\": [{
|
|
\"color\": \"$([ "$status" = "SUCCESS" ] && echo \"good\" || echo \"danger\")\",
|
|
\"fields\": [
|
|
{\"title\": \"Status\", \"value\": \"$message\", \"short\": true},
|
|
{\"title\": \"Duration\", \"value\": \"$elapsed_fmt\", \"short\": true},
|
|
{\"title\": \"Server\", \"value\": \"$(hostname)\", \"short\": true},
|
|
{\"title\": \"Log\", \"value\": \"$LOG_FILE\", \"short\": false}
|
|
]
|
|
}]
|
|
}" 2>/dev/null || true
|
|
}
|
|
|
|
cleanup_notify_failure() {
|
|
$NOTIFY_FAILED && return
|
|
NOTIFY_FAILED=true
|
|
notify "FAILED" "$1"
|
|
}
|
|
|
|
# --- Rollback support --------------------------------------------------------
|
|
LAST_BACKUP=""
|
|
ROLLBACK_NEEDED=false
|
|
|
|
rollback_db() {
|
|
[ -z "$LAST_BACKUP" ] && { warn "No backup file known — cannot rollback DB."; return 1; }
|
|
[ ! -f "$LAST_BACKUP" ] && { warn "Backup file not found: $LAST_BACKUP"; return 1; }
|
|
info "Rolling back database from: $LAST_BACKUP"
|
|
mariadb $MYSQL_CRED "$DB_NAME" < "$LAST_BACKUP" && ok "Database restored." || warn "Rollback failed."
|
|
}
|
|
|
|
cleanup_on_exit() {
|
|
local exit_code=$?
|
|
if [ $exit_code -ne 0 ] && [ "$ROLLBACK_NEEDED" = true ]; then
|
|
echo ""
|
|
echo "=== ⚠️ Update failed — initiating rollback ==="
|
|
rollback_db
|
|
fi
|
|
[ $exit_code -ne 0 ] && cleanup_notify_failure "Script exited with code $exit_code"
|
|
}
|
|
|
|
trap cleanup_on_exit EXIT
|
|
trap 'echo ""; die "Interrupted by user"' SIGINT SIGTERM
|
|
|
|
# --- Pre-flight: interactive prompts (must be before unbuffer) ---------------
|
|
|
|
# Site URL
|
|
if [ -z "${NITRO_SITE_URL:-}" ] && [ -n "${APP_URL:-}" ]; then
|
|
NITRO_SITE_URL="$APP_URL"
|
|
info "Using APP_URL from .env: $NITRO_SITE_URL"
|
|
fi
|
|
if [ -z "${NITRO_SITE_URL:-}" ]; then
|
|
read -r -p " Enter your site URL (e.g. https://example.com): " NITRO_SITE_URL
|
|
NITRO_SITE_URL="${NITRO_SITE_URL%/}"
|
|
[ -z "$NITRO_SITE_URL" ] && die "NITRO_SITE_URL is required"
|
|
export NITRO_SITE_URL
|
|
fi
|
|
|
|
# Branch
|
|
if [ -z "${NITRO_BRANCH:-}" ]; then
|
|
read -r -p " Enter branch (main/dev) [main]: " NITRO_BRANCH
|
|
NITRO_BRANCH="${NITRO_BRANCH:-main}"
|
|
case "$NITRO_BRANCH" in main|dev) ;; *) die "Invalid branch '$NITRO_BRANCH'. Use main or dev." ;; esac
|
|
export NITRO_BRANCH
|
|
fi
|
|
|
|
# Dry-run mode
|
|
DRY_RUN=false
|
|
if [ "${1:-}" = "--dry-run" ] || [ "${1:-}" = "-n" ]; then
|
|
DRY_RUN=true
|
|
echo ""
|
|
info "DRY-RUN mode: no changes will be made"
|
|
fi
|
|
|
|
# --- Unbuffer re-exec --------------------------------------------------------
|
|
if [ -z "${_UNBUFFERED:-}" ] && command -v unbuffer &> /dev/null; then
|
|
export _UNBUFFERED=1
|
|
exec unbuffer bash "$0" "$@"
|
|
fi
|
|
|
|
# --- Single-instance lock ----------------------------------------------------
|
|
LOCKFILE="/tmp/$(basename "$0").lock"
|
|
exec 200>"$LOCKFILE"
|
|
flock -n 200 || die "Another instance is already running"
|
|
|
|
# --- Configuration -----------------------------------------------------------
|
|
DB_NAME="${NITRO_DB_NAME:-habbo}"
|
|
DB_HOST="${NITRO_DB_HOST:-127.0.0.1}"
|
|
DB_PORT="${NITRO_DB_PORT:-3306}"
|
|
DB_USER="${NITRO_DB_USER:-root}"
|
|
DB_PASS="${NITRO_DB_PASS:-}"
|
|
EMULATOR_SERVICE="${NITRO_EMULATOR_SERVICE:-emulator}"
|
|
EMULATOR_DIR="${NITRO_EMULATOR_PATH:-/var/www/emulator}"
|
|
SQL_DIR="${NITRO_SQL_DIR:-$EMULATOR_DIR/Database Updates}"
|
|
GAMEDATA_CONF_DIR="${NITRO_GAMEDATA_DIR:-/var/www/Gamedata/config}"
|
|
NITRO_SRC_DIR="${NITRO_CLIENT_DIR:-/var/www/Nitro-V3/public/configuration}"
|
|
BACKUP_DIR="${NITRO_BACKUP_DIR:-$EMULATOR_DIR/Database Updates/backups}"
|
|
NITRO_CLIENT="${NITRO_CLIENT_SRC:-/var/www/Nitro-V3}"
|
|
NITRO_RENDERER="${NITRO_RENDERER_SRC:-/var/www/Nitro_Render_V3}"
|
|
NITRO_BRANCH="${NITRO_BRANCH:-main}"
|
|
MIN_DISK_GB="${NITRO_MIN_DISK_GB:-5}"
|
|
HEALTH_RETRIES="${NITRO_HEALTH_RETRIES:-12}"
|
|
HEALTH_INTERVAL="${NITRO_HEALTH_INTERVAL:-5}"
|
|
|
|
# Derive ws/wss protocol and domain
|
|
case "$NITRO_SITE_URL" in
|
|
https://*) NITRO_WS_PROTO="wss://" ; NITRO_DOMAIN="${NITRO_SITE_URL#https://}" ;;
|
|
http://*) NITRO_WS_PROTO="ws://" ; NITRO_DOMAIN="${NITRO_SITE_URL#http://}" ;;
|
|
*) NITRO_WS_PROTO="wss://" ; NITRO_DOMAIN="$NITRO_SITE_URL" ;;
|
|
esac
|
|
|
|
# Critical URLs (override via NITRO_* env vars)
|
|
NITRO_IMAGE_LIBRARY_URL="${NITRO_IMAGE_LIBRARY_URL:-$NITRO_SITE_URL/gamedata/c_images/}"
|
|
NITRO_HOF_FURNITURE_URL="${NITRO_HOF_FURNITURE_URL:-$NITRO_SITE_URL/gamedata/icons}"
|
|
NITRO_API_URL="${NITRO_API_URL:-$NITRO_SITE_URL}"
|
|
NITRO_SOCKET_URL="${NITRO_SOCKET_URL:-${NITRO_WS_PROTO}ws.${NITRO_DOMAIN}}"
|
|
NITRO_CAMERA_URL="${NITRO_CAMERA_URL:-$NITRO_SITE_URL/camera/photo/}"
|
|
NITRO_GAMEDATA_URL="${NITRO_GAMEDATA_URL:-$NITRO_SITE_URL/gamedata}"
|
|
NITRO_ASSET_URL="${NITRO_ASSET_URL:-$NITRO_SITE_URL/gamedata/bundled}"
|
|
NITRO_FURNI_ASSET_ICON_URL="${NITRO_FURNI_ASSET_ICON_URL:-$NITRO_SITE_URL/gamedata/icons/%libname%%param%_icon.png}"
|
|
|
|
# MySQL credentials
|
|
MYSQL_CRED="-h $DB_HOST -P $DB_PORT -u $DB_USER --ssl-verify-server-cert=OFF"
|
|
[ -n "$DB_PASS" ] && export MYSQL_PWD="$DB_PASS"
|
|
|
|
# =============================================================================
|
|
# PRE-FLIGHT CHECKS
|
|
# =============================================================================
|
|
step "Pre-flight Checks"
|
|
|
|
info "Checking required commands..."
|
|
for cmd in git mariadb mariadb-dump mvn node python3 yarn; do
|
|
command -v "$cmd" &>/dev/null || die "Required command not found: $cmd"
|
|
done
|
|
ok "All required commands available"
|
|
|
|
info "Checking directories..."
|
|
REQUIRED_DIRS=(
|
|
"$EMULATOR_DIR/Emulator"
|
|
"$NITRO_RENDERER"
|
|
"$NITRO_CLIENT"
|
|
"$NITRO_SRC_DIR"
|
|
)
|
|
for dir in "${REQUIRED_DIRS[@]}"; do
|
|
[ -d "$dir" ] || die "Required directory not found: $dir"
|
|
ok "Found: $dir"
|
|
done
|
|
|
|
info "Checking disk space..."
|
|
AVAIL_KB=$(df --output=avail "$EMULATOR_DIR" 2>/dev/null | tail -1)
|
|
AVAIL_GB=$(( AVAIL_KB / 1024 / 1024 ))
|
|
[ "$AVAIL_GB" -lt "$MIN_DISK_GB" ] && die "Only ${AVAIL_GB}GB free on $EMULATOR_DIR (min ${MIN_DISK_GB}GB required)"
|
|
ok "${AVAIL_GB}GB disk space available"
|
|
|
|
info "Checking database connection..."
|
|
mariadb $MYSQL_CRED -e "SELECT 1" "$DB_NAME" &>/dev/null || die "Cannot connect to database $DB_NAME on $DB_HOST:$DB_PORT"
|
|
ok "Database connection OK"
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
echo ""
|
|
warn "DRY-RUN — skipping actual update"
|
|
echo " Site: $NITRO_SITE_URL"
|
|
echo " Branch: $NITRO_BRANCH"
|
|
echo " Emulator: $EMULATOR_DIR/Emulator"
|
|
echo " Nitro-V3: $NITRO_CLIENT"
|
|
echo " Renderer: $NITRO_RENDERER"
|
|
echo ""
|
|
info "Dry-run complete. Pass --dry-run or -n to preview."
|
|
exit 0
|
|
fi
|
|
|
|
echo ""
|
|
info "Site: $NITRO_SITE_URL | Branch: $NITRO_BRANCH"
|
|
info "Log: $LOG_FILE"
|
|
|
|
# =============================================================================
|
|
# HELPERS
|
|
# =============================================================================
|
|
clean_node_modules() {
|
|
rm -rf node_modules 2>/dev/null || sudo rm -rf node_modules 2>/dev/null || true
|
|
if [ "$(stat -c '%U' .)" != "$(whoami)" ] && command -v sudo &> /dev/null; then
|
|
sudo chown -R "$(whoami)":"$(whoami)" .
|
|
fi
|
|
}
|
|
|
|
git_update() {
|
|
local repo="$1"
|
|
local branch="$2"
|
|
cd "$repo"
|
|
git stash --include-untracked || true
|
|
local old_head
|
|
old_head=$(git rev-parse HEAD)
|
|
if ! git checkout "$branch" 2>/dev/null; then
|
|
local alt="${branch^}"
|
|
if [ "$alt" != "$branch" ] && git checkout "$alt" 2>/dev/null; then
|
|
info "Branch '$branch' not found, using '$alt' instead"
|
|
branch="$alt"
|
|
else
|
|
die "Branch '$branch' (or '$alt') not found in $repo"
|
|
fi
|
|
fi
|
|
git pull
|
|
[ "$(git rev-parse HEAD)" != "$old_head" ]
|
|
}
|
|
|
|
HAD_UPDATES=false
|
|
NITRO_BUILT=false
|
|
|
|
# =============================================================================
|
|
# 1. UPDATE & BUILD EMULATOR
|
|
# =============================================================================
|
|
step "Update & Build Emulator"
|
|
|
|
if git_update "$EMULATOR_DIR/Emulator" "$NITRO_BRANCH"; then
|
|
info "New commits detected"
|
|
HAD_UPDATES=true
|
|
ROLLBACK_NEEDED=true
|
|
|
|
# Database backup
|
|
info "Creating database backup..."
|
|
mkdir -p "$BACKUP_DIR"
|
|
BACKUP_FILE="$BACKUP_DIR/backup_$(date +%Y%m%d_%H%M%S).sql"
|
|
if mariadb-dump $MYSQL_CRED --force --skip-lock-tables --routines --events --triggers "$DB_NAME" > "$BACKUP_FILE"; then
|
|
LAST_BACKUP="$BACKUP_FILE"
|
|
BK_SIZE=$(stat -c%s "$BACKUP_FILE" 2>/dev/null || echo 0)
|
|
[ "$BK_SIZE" -lt 1024 ] && { rm -f "$BACKUP_FILE"; die "Backup is too small (${BK_SIZE}B) — possible corruption, aborting"; }
|
|
ok "Backup saved: $(numfmt --to=iec "$BK_SIZE") — $BACKUP_FILE"
|
|
else
|
|
die "Database backup failed"
|
|
fi
|
|
|
|
# SQL imports
|
|
info "Checking for new SQL files..."
|
|
if [ -d "$SQL_DIR" ]; then
|
|
SQL_COUNT=0
|
|
while IFS= read -r -d '' sql_file; do
|
|
info "Importing: $(basename "$sql_file")"
|
|
mariadb $MYSQL_CRED --force "$DB_NAME" < "$sql_file" || warn "Import failed for $(basename "$sql_file")"
|
|
SQL_COUNT=$((SQL_COUNT + 1))
|
|
done < <(find "$SQL_DIR" -name '*.sql' -mmin -10 -not -path "$BACKUP_DIR/*" -print0 2>/dev/null)
|
|
[ "$SQL_COUNT" -gt 0 ] && ok "$SQL_COUNT SQL file(s) imported" || info "No new SQL files found"
|
|
else
|
|
info "SQL directory not found, skipping"
|
|
fi
|
|
|
|
# Maven build
|
|
info "Building emulator (mvn package)..."
|
|
cd "$EMULATOR_DIR/Emulator"
|
|
mvn package -q || die "Maven build failed"
|
|
ok "Build complete"
|
|
|
|
JAR_FILE=$(find target -maxdepth 1 -name 'Habbo-*-jar-with-dependencies.jar' -printf '%T@ %p\n' 2>/dev/null | sort -rn | sed -n '1s/^[0-9.]* //p' | xargs basename)
|
|
[ -z "$JAR_FILE" ] && die "No jar file found in target/"
|
|
ok "Jar: $JAR_FILE"
|
|
|
|
info "Updating emulator launch script..."
|
|
cd target/
|
|
cat << EOF > emulator
|
|
#!/bin/sh
|
|
file_name_emulator=emulator.log
|
|
current_time=\$(date "+%H%M_%d-%m-%Y")
|
|
file_name=\$file_name_emulator.\$current_time
|
|
mv /var/log/emu/emulator.log /var/log/emu/\$file_name
|
|
java -Dfile.encoding=UTF8 -Xmx2G -jar $JAR_FILE
|
|
EOF
|
|
chmod +x emulator
|
|
ok "Launch script updated"
|
|
ROLLBACK_NEEDED=false
|
|
else
|
|
info "Already up to date, skipping"
|
|
fi
|
|
|
|
# =============================================================================
|
|
# 2. UPDATE NITRO_RENDER_V3
|
|
# =============================================================================
|
|
step "Update Nitro_Render_V3"
|
|
|
|
if git_update "$NITRO_RENDERER" "$NITRO_BRANCH"; then
|
|
info "New commits detected"
|
|
HAD_UPDATES=true
|
|
yarn install --frozen-lockfile || { info "Retrying with clean node_modules..."; clean_node_modules && yarn install; } || die "yarn install failed for Nitro_Render_V3"
|
|
ok "Dependencies installed"
|
|
else
|
|
info "Already up to date, skipping"
|
|
fi
|
|
|
|
# =============================================================================
|
|
# 3. UPDATE & BUILD NITRO-V3
|
|
# =============================================================================
|
|
step "Update & Build Nitro-V3"
|
|
|
|
if git_update "$NITRO_CLIENT" "$NITRO_BRANCH"; then
|
|
info "New commits detected"
|
|
HAD_UPDATES=true
|
|
NITRO_BUILT=true
|
|
yarn install --frozen-lockfile || { info "Retrying with clean node_modules..."; clean_node_modules && yarn install; } || die "yarn install failed for Nitro-V3"
|
|
ok "Dependencies installed"
|
|
info "Building Nitro-V3 (yarn build)..."
|
|
yarn build || die "yarn build failed"
|
|
ok "Build complete"
|
|
else
|
|
info "Already up to date, skipping build"
|
|
fi
|
|
|
|
# custom-themes/index.json
|
|
mkdir -p "$NITRO_CLIENT/dist/custom-themes"
|
|
if [ ! -f "$NITRO_CLIENT/dist/custom-themes/index.json" ]; then
|
|
echo '{"themes":[]}' > "$NITRO_CLIENT/dist/custom-themes/index.json"
|
|
ok "Created custom-themes/index.json"
|
|
else
|
|
ok "custom-themes/index.json exists"
|
|
fi
|
|
|
|
# =============================================================================
|
|
# 4. SYNC CONFIGS
|
|
# =============================================================================
|
|
step "Sync Configurations"
|
|
|
|
mkdir -p "$GAMEDATA_CONF_DIR"
|
|
MERGE_SCRIPT="$(dirname "$0")/scripts/merge-config.cjs"
|
|
NITRO_DIST_CONFIG_DIR="$NITRO_CLIENT/dist/configuration"
|
|
|
|
# Make dirs writable
|
|
for dir in "$NITRO_SRC_DIR" "$GAMEDATA_CONF_DIR"; do
|
|
if [ -d "$dir" ] && [ ! -w "$dir" ] && command -v sudo &> /dev/null; then
|
|
sudo chown -R "$(whoami)":"$(whoami)" "$dir" 2>/dev/null || true
|
|
fi
|
|
done
|
|
|
|
EXAMPLE_COUNT=0
|
|
for example_file in "$NITRO_SRC_DIR"/*.example; do
|
|
[ -f "$example_file" ] || continue
|
|
base=$(basename "$example_file")
|
|
target_name="${base%.example}"
|
|
case "$target_name" in *.*) ;; *) target_name="$target_name.json" ;; esac
|
|
node "$MERGE_SCRIPT" "$example_file" "$NITRO_SRC_DIR/$target_name" 2>/dev/null
|
|
node "$MERGE_SCRIPT" "$example_file" "$GAMEDATA_CONF_DIR/$target_name" 2>/dev/null
|
|
if [ -d "$NITRO_DIST_CONFIG_DIR" ]; then
|
|
cp "$NITRO_SRC_DIR/$target_name" "$NITRO_DIST_CONFIG_DIR/$target_name" 2>/dev/null || true
|
|
fi
|
|
EXAMPLE_COUNT=$((EXAMPLE_COUNT + 1))
|
|
done
|
|
ok "$EXAMPLE_COUNT .example file(s) processed"
|
|
|
|
# Force critical URLs
|
|
info "Applying critical config URLs..."
|
|
FORCE_CONFIG_SCRIPT=$(cat << 'PYEOF'
|
|
import json, sys, os
|
|
|
|
paths = [
|
|
os.path.join(os.environ.get('NITRO_SRC_DIR', ''), 'renderer-config.json'),
|
|
os.path.join(os.environ.get('NITRO_DIST_CONFIG_DIR', ''), 'renderer-config.json'),
|
|
os.path.join(os.environ.get('NITRO_SRC_DIR', ''), 'ui-config.json'),
|
|
os.path.join(os.environ.get('NITRO_DIST_CONFIG_DIR', ''), 'ui-config.json'),
|
|
]
|
|
|
|
for path in paths:
|
|
if not os.path.exists(path):
|
|
continue
|
|
with open(path, 'r') as f:
|
|
data = json.load(f)
|
|
for key in ['image.library.url', 'hof.furni.url', 'gamedata.url', 'asset.url']:
|
|
env_val = os.environ.get(f'NITRO_{key.upper().replace(".", "_")}')
|
|
if env_val:
|
|
data[key] = env_val
|
|
for key in ['api.url', 'socket.url', 'furni.asset.icon.url']:
|
|
if key in data:
|
|
env_val = os.environ.get(f'NITRO_{key.upper().replace(".", "_")}')
|
|
if env_val:
|
|
data[key] = env_val
|
|
if 'gamedata.url' in data:
|
|
data['radio.url'] = data['gamedata.url'] + '/config/radio-stations.json5?t=%timestamp%'
|
|
data['soundboard.url'] = data['gamedata.url'] + '/config/soundboard-sounds.json5?t=%timestamp%'
|
|
if 'show.google.ads' in data:
|
|
data['show.google.ads'] = False
|
|
with open(path, 'w') as f:
|
|
json.dump(data, f, indent=(4 if 'dist' not in path else None), separators=(',', ':') if 'dist' in path else (',', ': '))
|
|
print(f' [OK] Fixed: {os.path.basename(path)}')
|
|
|
|
print(' [OK] All config URLs synced')
|
|
PYEOF
|
|
)
|
|
cd "$NITRO_CLIENT" && NITRO_SRC_DIR="$NITRO_SRC_DIR" NITRO_DIST_CONFIG_DIR="$NITRO_DIST_CONFIG_DIR" \
|
|
NITRO_IMAGE_LIBRARY_URL="$NITRO_IMAGE_LIBRARY_URL" NITRO_HOF_FURNITURE_URL="$NITRO_HOF_FURNITURE_URL" \
|
|
NITRO_API_URL="$NITRO_API_URL" NITRO_SOCKET_URL="$NITRO_SOCKET_URL" \
|
|
NITRO_GAMEDATA_URL="$NITRO_GAMEDATA_URL" NITRO_ASSET_URL="$NITRO_ASSET_URL" \
|
|
NITRO_FURNI_ASSET_ICON_URL="$NITRO_FURNI_ASSET_ICON_URL" \
|
|
python3 -c "$FORCE_CONFIG_SCRIPT"
|
|
|
|
# =============================================================================
|
|
# 5. CLEANUP
|
|
# =============================================================================
|
|
step "Cleanup"
|
|
|
|
info "Removing logs older than 14 days..."
|
|
find "$EMULATOR_DIR" -name "*.log" -mtime +14 -exec rm -f {} \; 2>/dev/null || true
|
|
|
|
info "Managing backups (keeping max 5)..."
|
|
if [ -d "$BACKUP_DIR" ]; then
|
|
find "$BACKUP_DIR" -maxdepth 1 -name '*.sql' -printf '%T@ %p\n' 2>/dev/null | sort -rn | tail -n +6 | sed 's/^[0-9.]* //' | xargs -r rm -f || true
|
|
fi
|
|
|
|
if [ "$HAD_UPDATES" = true ]; then
|
|
info "Cleaning Yarn cache..."
|
|
yarn cache clean 2>/dev/null || true
|
|
info "Removing old .jar files..."
|
|
find "$EMULATOR_DIR/Emulator/target" -maxdepth 1 -name 'Habbo-*-jar-with-dependencies.jar' -printf '%T@ %p\n' 2>/dev/null | sort -rn | tail -n +2 | sed 's/^[0-9.]* //' | xargs -r rm -f || true
|
|
fi
|
|
ok "Cleanup complete"
|
|
|
|
# =============================================================================
|
|
# 6. PERMISSIONS
|
|
# =============================================================================
|
|
step "Set Permissions"
|
|
|
|
if command -v sudo &> /dev/null; then
|
|
for dir in "$NITRO_CLIENT" "$NITRO_RENDERER" "$EMULATOR_DIR" "$GAMEDATA_CONF_DIR"; do
|
|
if [ -d "$dir" ]; then
|
|
sudo chown -R www-data:www-data "$dir" 2>/dev/null || warn "Could not chown $dir"
|
|
fi
|
|
done
|
|
ok "Permissions set to www-data:www-data"
|
|
else
|
|
warn "sudo not available, skipping chown"
|
|
fi
|
|
|
|
# =============================================================================
|
|
# 7. RESTART SERVICES
|
|
# =============================================================================
|
|
step "Restart Services"
|
|
|
|
RESTART_OK=false
|
|
if [ "$HAD_UPDATES" = true ]; then
|
|
if systemctl cat "$EMULATOR_SERVICE" &>/dev/null; then
|
|
if command -v sudo &> /dev/null; then
|
|
info "Restarting $EMULATOR_SERVICE..."
|
|
sudo systemctl restart "$EMULATOR_SERVICE" || die "Failed to restart $EMULATOR_SERVICE"
|
|
RESTART_OK=true
|
|
fi
|
|
elif command -v pm2 &> /dev/null; then
|
|
info "Restarting PM2 processes..."
|
|
pm2 restart all || warn "PM2 restart had issues"
|
|
RESTART_OK=true
|
|
else
|
|
warn "No systemd or PM2 found — restart manually"
|
|
fi
|
|
|
|
if [ "$RESTART_OK" = true ]; then
|
|
ok "Services restarted"
|
|
fi
|
|
else
|
|
info "No updates applied, no restart needed"
|
|
fi
|
|
|
|
# =============================================================================
|
|
# 8. HEALTH CHECK & VALIDATION
|
|
# =============================================================================
|
|
step "Health Check & Validation"
|
|
|
|
ERRORS=0
|
|
|
|
# Build output check
|
|
if [ "$NITRO_BUILT" = true ]; then
|
|
if [ -d "$NITRO_CLIENT/dist/assets" ]; then
|
|
ASSET_COUNT=$(find "$NITRO_CLIENT/dist/assets" -type f 2>/dev/null | wc -l)
|
|
ok "Nitro-V3 built: $ASSET_COUNT assets in dist/assets"
|
|
else
|
|
fail "Nitro-V3 build assets missing!"
|
|
ERRORS=$((ERRORS + 1))
|
|
fi
|
|
else
|
|
info "Skipping build check (no new commits)"
|
|
fi
|
|
|
|
# Health check with retries for emulator
|
|
if [ "$HAD_UPDATES" = true ] && systemctl cat "$EMULATOR_SERVICE" &>/dev/null; then
|
|
info "Waiting for $EMULATOR_SERVICE to become active..."
|
|
HEALTHY=false
|
|
for i in $(seq 1 "$HEALTH_RETRIES"); do
|
|
sleep "$HEALTH_INTERVAL"
|
|
STATUS=$(systemctl is-active "$EMULATOR_SERVICE" 2>/dev/null || echo "unknown")
|
|
if [ "$STATUS" = "active" ]; then
|
|
HEALTHY=true
|
|
break
|
|
fi
|
|
info " Attempt $i/$HEALTH_RETRIES — status: $STATUS"
|
|
done
|
|
if [ "$HEALTHY" = true ]; then
|
|
ok "$EMULATOR_SERVICE is active ($(( i * HEALTH_INTERVAL ))s to start)"
|
|
else
|
|
fail "$EMULATOR_SERVICE did not become active after ${HEALTH_RETRIES} retries"
|
|
ERRORS=$((ERRORS + 1))
|
|
fi
|
|
fi
|
|
|
|
# Permission audit
|
|
for dir in "$NITRO_CLIENT" "$NITRO_RENDERER" "$EMULATOR_DIR" "$GAMEDATA_CONF_DIR"; do
|
|
if [ -d "$dir" ]; then
|
|
OWNER=$(stat -c '%U:%G' "$dir" 2>/dev/null || echo "unknown")
|
|
if [ "$OWNER" = "www-data:www-data" ] || [ "$(id -u)" -ne 0 ]; then
|
|
ok "$(basename "$dir") ($OWNER)"
|
|
else
|
|
warn "$(basename "$dir") owner is $OWNER (should be www-data:www-data)"
|
|
sudo chown -R www-data:www-data "$dir" 2>/dev/null || true
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# =============================================================================
|
|
# SUMMARY
|
|
# =============================================================================
|
|
ELAPSED=$(( $(date +%s) - START_TIME ))
|
|
ELAPSED_FMT=$(printf '%dm %ds' $((ELAPSED/60)) $((ELAPSED%60)))
|
|
|
|
echo ""
|
|
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
if [ "$ERRORS" -eq 0 ]; then
|
|
echo "║ ✅ UPDATE SUCCESSFULLY COMPLETED ║"
|
|
else
|
|
echo "║ ⚠️ UPDATE COMPLETED WITH $ERRORS WARNING(S) ║"
|
|
fi
|
|
echo "╠══════════════════════════════════════════════════════════════╣"
|
|
printf "║ Duration: %-46s║\n" "$ELAPSED_FMT"
|
|
printf "║ Updates: %-46s║\n" "$([ "$HAD_UPDATES" = true ] && echo "Yes" || echo "No")"
|
|
printf "║ Nitro build: %-46s║\n" "$([ "$NITRO_BUILT" = true ] && echo "Yes" || echo "No")"
|
|
printf "║ Log file: %-46s║\n" "$LOG_FILE"
|
|
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
echo ""
|
|
|
|
notify "SUCCESS" "Completed in $ELAPSED_FMT (${ERRORS} warnings)" |