@echo off setlocal enabledelayedexpansion cd /d "%~dp0" set "ENV_EXAMPLE=.env.example" set "ENV_FILE=.env" set "IP_FILE=.public_ip" set "PREFIX_FILE=.link_prefix" set "SECRETS_FILE=.secrets" set "COMPOSE_FILE=deploy\docker-compose.yml" set "LOG_DIR=logs" set "NO_BUILD=false" :parse_args if "%~1"=="" goto done_args if /i "%~1"=="--no-build" set "NO_BUILD=true" shift goto parse_args :done_args echo [cfg] script started, NO_BUILD=%NO_BUILD% rem --- Public address (interactive) ----------------------------------------- set "DEFAULT_IP=" if exist "%IP_FILE%" ( set /p DEFAULT_IP=<"%IP_FILE%" echo [cfg] loaded saved IP: !DEFAULT_IP! ) if not defined DEFAULT_IP ( echo [cfg] detecting public IP... for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "(Invoke-WebRequest -Uri 'https://api.ipify.org' -TimeoutSec 5 -UseBasicParsing).Content" 2^>nul`) do set "DEFAULT_IP=%%i" if defined DEFAULT_IP echo [cfg] detected IP: !DEFAULT_IP! ) if defined DEFAULT_IP ( set /p "PUBLIC_IP=Public server IP/host [!DEFAULT_IP!]: " ) else ( set /p "PUBLIC_IP=Public server IP/host: " ) if not defined PUBLIC_IP set "PUBLIC_IP=!DEFAULT_IP!" if not defined PUBLIC_IP ( echo [ERROR] public IP/host is required. pause exit /b 1 ) > "%IP_FILE%" echo !PUBLIC_IP! echo [cfg] public address = !PUBLIC_IP! rem --- Link prefix / me_url_prefix (interactive) ---------------------------- set "DEFAULT_PREFIX=!PUBLIC_IP!" if exist "%PREFIX_FILE%" set /p DEFAULT_PREFIX=<"%PREFIX_FILE%" set /p "LINK_PREFIX=Link prefix [!DEFAULT_PREFIX!]: " if not defined LINK_PREFIX set "LINK_PREFIX=!DEFAULT_PREFIX!" for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "$p='!LINK_PREFIX!'; $p=$p -replace '^https?://','' -replace '/+$',''; Write-Output $p"`) do set "LINK_PREFIX=%%i" if not defined LINK_PREFIX ( echo [ERROR] link prefix is required. pause exit /b 1 ) > "%PREFIX_FILE%" echo !LINK_PREFIX! echo [cfg] link prefix = !LINK_PREFIX! rem --- Secrets (generated once, cached) ------------------------------------- set "ADMIN_TOKEN=" set "ADMIN_PASSWORD=" set "SESSION_KEY=" set "SECRETS_CHANGED=" if exist "%SECRETS_FILE%" ( echo [cfg] loading secrets from %SECRETS_FILE% for /f "usebackq tokens=1,* delims==" %%A in (`type "%SECRETS_FILE%"`) do ( if "%%A"=="ADMIN_TOKEN" set "ADMIN_TOKEN=%%B" if "%%A"=="ADMIN_PASSWORD" set "ADMIN_PASSWORD=%%B" if "%%A"=="SESSION_KEY" set "SESSION_KEY=%%B" ) ) if not defined ADMIN_TOKEN ( echo [cfg] generating ADMIN_TOKEN... for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "$bytes=New-Object byte[] 32; [System.Security.Cryptography.RandomNumberGenerator]::Fill($bytes); ($bytes | ForEach-Object { $_.ToString('x2') }) -join ''"`) do set "ADMIN_TOKEN=%%i" set "SECRETS_CHANGED=1" ) if not defined ADMIN_PASSWORD ( echo [cfg] generating ADMIN_PASSWORD... for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "$chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; -join (1..24 | ForEach-Object { $chars[(Get-Random -Maximum $chars.Length)] })"`) do set "ADMIN_PASSWORD=%%i" set "SECRETS_CHANGED=1" ) if not defined SESSION_KEY ( echo [cfg] generating SESSION_KEY... for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "$chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; -join (1..48 | ForEach-Object { $chars[(Get-Random -Maximum $chars.Length)] })"`) do set "SESSION_KEY=%%i" set "SECRETS_CHANGED=1" ) if defined SECRETS_CHANGED ( > "%SECRETS_FILE%" echo ADMIN_TOKEN=!ADMIN_TOKEN! >> "%SECRETS_FILE%" echo ADMIN_PASSWORD=!ADMIN_PASSWORD! >> "%SECRETS_FILE%" echo SESSION_KEY=!SESSION_KEY! echo [cfg] secrets written to %SECRETS_FILE% ) else ( echo [cfg] secrets loaded from %SECRETS_FILE% ) rem --- Generate .env from .env.example -------------------------------------- if not exist "%ENV_EXAMPLE%" ( echo [ERROR] template file %ENV_EXAMPLE% not found pause exit /b 1 ) copy /Y "%ENV_EXAMPLE%" "%ENV_FILE%" >nul echo [cfg] copied %ENV_EXAMPLE% to %ENV_FILE% echo [cfg] patching .env values... powershell -NoProfile -ExecutionPolicy Bypass -Command ^ "$f='%ENV_FILE%'; " ^ "$enc=New-Object System.Text.UTF8Encoding($false); " ^ "$t=[System.IO.File]::ReadAllText($f,$enc); " ^ "$map=[ordered]@{ " ^ " 'TELESRV_ADVERTISE_IP'='!PUBLIC_IP!'; " ^ " 'TELESRV_TURN_ADVERTISE_IP'='!PUBLIC_IP!'; " ^ " 'TELESRV_SFU_ADVERTISE_IP'='!PUBLIC_IP!'; " ^ " 'TELESRV_PUBLIC_BASE_URL'='https://!LINK_PREFIX!'; " ^ " 'TELESRV_PASSKEY_RP_ID'='!LINK_PREFIX!'; " ^ " 'TELESRV_PUBLIC_APP_SCHEME'='owpg'; " ^ " 'TELESRV_PUBLIC_APP_NAME'='OwpenGram'; " ^ " 'TELESRV_ADMIN_API_TOKEN'='!ADMIN_TOKEN!'; " ^ " 'TELESRV_ADMIN_UI_PASSWORD'='!ADMIN_PASSWORD!'; " ^ " 'TELESRV_ADMIN_SESSION_KEY'='!SESSION_KEY!'; " ^ " 'TELESRV_ADMIN_UI_ADDR'='127.0.0.1:2600'; " ^ " 'TELESRV_ADMIN_API_ADDR'='127.0.0.1:2399'; " ^ " 'TELESRV_PUBLIC_LINK_WEB_ADDR'='127.0.0.1:2401' " ^ "}; " ^ "foreach ($k in $map.Keys) { " ^ " $pat='(?m)^' + [regex]::Escape($k) + '=.*$'; " ^ " $rep=$k + '=' + $map[$k]; " ^ " if ($t -match $pat) { $t=[regex]::Replace($t,$pat,$rep) } " ^ " else { $t+=\"`r`n\"+$rep } " ^ "}; " ^ "[System.IO.File]::WriteAllText($f,$t,$enc); " ^ "Write-Output 'ok'" if %ERRORLEVEL% neq 0 ( echo [ERROR] failed to patch .env pause exit /b 1 ) echo [cfg] .env written rem --- Start infrastructure (PostgreSQL + Redis) ---------------------------- echo. echo == [1/4] Starting infrastructure (PostgreSQL + Redis) == docker compose -f "%COMPOSE_FILE%" up -d if %ERRORLEVEL% neq 0 ( echo [ERROR] docker compose failed pause exit /b 1 ) rem --- Wait for PostgreSQL -------------------------------------------------- echo. echo == [2/4] Waiting for PostgreSQL == set /a "_pgw=0" :wait_pg docker exec telesrv-postgres pg_isready -U telesrv -d telesrv >nul 2>&1 if not errorlevel 1 goto pg_ready set /a "_pgw+=1" if !_pgw! gtr 30 ( echo [ERROR] PostgreSQL not ready after 60s pause exit /b 1 ) echo [cfg] waiting for PostgreSQL... !_pgw!/30 timeout /t 2 >nul goto wait_pg :pg_ready echo [ok] PostgreSQL is ready rem --- Build ------------------------------------------------------------------ echo. echo == [3/4] Building server binaries == if /i "%NO_BUILD%"=="true" ( echo [cfg] skipping build (--no-build) if not exist "bin\telesrv.exe" ( if not exist "bin\telesrv-admin.exe" ( echo [ERROR] no binaries found in bin\ - run without --no-build first pause exit /b 1 ) ) ) else ( if not exist bin mkdir bin echo [cfg] building telesrv... go build -o bin\telesrv.exe .\cmd\telesrv if %ERRORLEVEL% neq 0 ( echo [ERROR] failed to build telesrv pause exit /b 1 ) echo [cfg] building telesrv-admin... go build -o bin\telesrv-admin.exe .\cmd\telesrv-admin if %ERRORLEVEL% neq 0 ( echo [ERROR] failed to build telesrv-admin pause exit /b 1 ) echo [ok] binaries built ) rem --- Start servers ---------------------------------------------------------- echo. echo == [4/4] Starting telesrv + telesrv-admin == if not exist "%LOG_DIR%" mkdir "%LOG_DIR%" set "TELESRV_LOG=%LOG_DIR%\telesrv.log" set "ADMIN_LOG=%LOG_DIR%\telesrv-admin.log" start "telesrv" /B cmd /c "bin\telesrv.exe >> "%TELESRV_LOG%" 2>&1" echo [ok] telesrv started, logs -^> %TELESRV_LOG% start "telesrv-admin" /B cmd /c "bin\telesrv-admin.exe >> "%ADMIN_LOG%" 2>&1" echo [ok] telesrv-admin started, logs -^> %ADMIN_LOG% echo. echo ============================================ echo OwpenGram server is running echo ============================================ echo. echo MTProto: !PUBLIC_IP!:2398 echo Admin UI: http://127.0.0.1:2600 echo Admin API: http://127.0.0.1:2399 echo. echo Admin login password: !ADMIN_PASSWORD! echo. echo Logs: echo telesrv: type %TELESRV_LOG% echo telesrv-admin: type %ADMIN_LOG% echo. echo ============================================ rem --- Interactive menu ------------------------------------------------------ :menu echo. echo [1] View telesrv logs (last 50 lines) echo [2] View telesrv-admin logs (last 50 lines) echo [3] View both logs (last 50 lines) echo [4] Follow telesrv logs (live) echo [5] Follow telesrv-admin logs (live) echo [q] Stop server and exit echo. set /p "choice= Choice: " if "!choice!"=="1" ( powershell -NoProfile -Command "Get-Content '%TELESRV_LOG%' -Tail 50 -ErrorAction SilentlyContinue" goto menu ) if "!choice!"=="2" ( powershell -NoProfile -Command "Get-Content '%ADMIN_LOG%' -Tail 50 -ErrorAction SilentlyContinue" goto menu ) if "!choice!"=="3" ( echo --- telesrv --- powershell -NoProfile -Command "Get-Content '%TELESRV_LOG%' -Tail 50 -ErrorAction SilentlyContinue" echo --- telesrv-admin --- powershell -NoProfile -Command "Get-Content '%ADMIN_LOG%' -Tail 50 -ErrorAction SilentlyContinue" goto menu ) if "!choice!"=="4" ( echo Press Ctrl+C to stop following powershell -NoProfile -Command "Get-Content '%TELESRV_LOG%' -Wait -Tail 10" goto menu ) if "!choice!"=="5" ( echo Press Ctrl+C to stop following powershell -NoProfile -Command "Get-Content '%ADMIN_LOG%' -Wait -Tail 10" goto menu ) if /i "!choice!"=="q" goto stop_server echo Invalid choice goto menu :stop_server echo. echo [stop] stopping telesrv and telesrv-admin ... taskkill /FI "WINDOWTITLE eq telesrv*" /F >nul 2>&1 taskkill /FI "WINDOWTITLE eq telesrv-admin*" /F >nul 2>&1 echo [ok] stopped. exit /b 0