From 0b7ad7903247d49e14f55e74cfbdb19d9e7fee2a8a71e797cab649779a27361b Mon Sep 17 00:00:00 2001 From: AidarKC Date: Tue, 7 Apr 2026 14:25:49 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=9E=D0=90=D0=92=D0=98=D0=9B=20=D0=92?= =?UTF-8?q?=20=D0=93=D0=A0=D0=90=D0=94=D0=9B=D0=95=20=D0=9B=D0=9E=D0=9A?= =?UTF-8?q?=D0=90=D0=9B=D0=AC=D0=9D=D0=AB=D0=99=20=D0=97=D0=90=D0=9F=D0=A3?= =?UTF-8?q?=D0=A1=D0=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 67 +++++++++++++++++++ shine-UI/js/state.js | 22 +++++- .../src/main/java/utils/config/AppConfig.java | 2 + 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ee7e4c6..ba04be6 100644 --- a/build.gradle +++ b/build.gradle @@ -197,3 +197,70 @@ tasks.register('deployAll') { dependsOn tasks.named('deployServer') dependsOn tasks.named('deployWEB') } + +tasks.register('startLocal', Exec) { + group = "!!run" + description = "Builds server, starts local WS server and local HTTP UI for end-to-end local testing" + + dependsOn shadowJar + + workingDir = rootDir + def wsPort = System.getProperty("localWsPort", "7070") + def webPort = System.getProperty("localWebPort", "8088") + + commandLine 'bash', '-lc', """ + set -euo pipefail + JAR_PATH="${file('build/libs/shine-server.jar').absolutePath}" + UI_DIR="${file('shine-UI').absolutePath}" + WS_PORT="${wsPort}" + WEB_PORT="${webPort}" + + is_port_busy() { + local port="\$1" + if command -v ss >/dev/null 2>&1; then + ss -ltnH "sport = :\$port" | grep -q . + elif command -v lsof >/dev/null 2>&1; then + lsof -iTCP:"\$port" -sTCP:LISTEN >/dev/null 2>&1 + else + return 1 + fi + } + + pick_free_port() { + local p="\$1" + while is_port_busy "\$p"; do + p=\$((p + 1)) + done + echo "\$p" + } + + WS_PORT="\$(pick_free_port "\$WS_PORT")" + WEB_PORT="\$(pick_free_port "\$WEB_PORT")" + + echo "Starting SHiNE local stack..." + echo "WS server port: \$WS_PORT" + echo "UI HTTP port: \$WEB_PORT" + echo "Client URL: http://localhost:\$WEB_PORT/?localWsPort=\$WS_PORT" + + java -Dserver.port="\$WS_PORT" -jar "\$JAR_PATH" & + SERVER_PID=\$! + trap 'kill \$SERVER_PID 2>/dev/null || true' EXIT INT TERM + + CLIENT_URL="http://localhost:\$WEB_PORT/?localWsPort=\$WS_PORT" + if command -v xdg-open >/dev/null 2>&1; then + (xdg-open "\$CLIENT_URL" >/dev/null 2>&1 || true) & + elif command -v open >/dev/null 2>&1; then + (open "\$CLIENT_URL" >/dev/null 2>&1 || true) & + elif command -v cmd.exe >/dev/null 2>&1; then + (cmd.exe /c start "" "\$CLIENT_URL" >/dev/null 2>&1 || true) & + else + echo "Browser auto-open is not available on this host. Open manually: \$CLIENT_URL" + fi + + if command -v python3 >/dev/null 2>&1; then + (cd "\$UI_DIR" && python3 -m http.server "\$WEB_PORT") + else + (cd "\$UI_DIR" && python -m http.server "\$WEB_PORT") + fi + """ +} diff --git a/shine-UI/js/state.js b/shine-UI/js/state.js index f03db1a..5d63d4a 100644 --- a/shine-UI/js/state.js +++ b/shine-UI/js/state.js @@ -11,6 +11,22 @@ const INVALID_SESSION_CODES = new Set([ 'SESSION_OF_ANOTHER_USER', ]); +function readLocalWsOverrideUrl() { + try { + const value = new URLSearchParams(window.location.search).get('localWsPort'); + const asNum = Number(value); + if (!Number.isFinite(asNum)) return ''; + const port = Math.trunc(asNum); + if (port <= 0 || port > 65535) return ''; + return `ws://localhost:${port}/ws`; + } catch { + return ''; + } +} + +const LOCAL_WS_OVERRIDE_URL = readLocalWsOverrideUrl(); +const DEFAULT_SHINE_SERVER = 'wss://shineup.me/ws'; + function loadStoredSession() { try { const raw = localStorage.getItem(SESSION_STORAGE_KEY); @@ -39,6 +55,8 @@ function clearStoredSession() { function createInitialState({ withStoredSession = true } = {}) { const storedSession = withStoredSession ? loadStoredSession() : null; + const initialShineServer = LOCAL_WS_OVERRIDE_URL || DEFAULT_SHINE_SERVER; + return { chats: clone(chatMessages), contacts: [], @@ -55,7 +73,7 @@ function createInitialState({ withStoredSession = true } = {}) { entrySettings: { language: 'ru', solanaServer: 'https://api.mainnet-beta.solana.com', - shineServer: 'wss://shineup.me/ws', + shineServer: initialShineServer, arweaveServer: 'https://arweave.net', statuses: { solanaServer: 'idle', @@ -155,9 +173,11 @@ export function checkServerAvailability(address) { } export async function saveEntrySettings(nextSettings) { + const forcedShineServer = LOCAL_WS_OVERRIDE_URL || nextSettings.shineServer; state.entrySettings = { ...state.entrySettings, ...nextSettings, + shineServer: forcedShineServer, statuses: { ...state.entrySettings.statuses, ...(nextSettings.statuses || {}), diff --git a/shine-server-config/src/main/java/utils/config/AppConfig.java b/shine-server-config/src/main/java/utils/config/AppConfig.java index 5cdde05..00adf62 100644 --- a/shine-server-config/src/main/java/utils/config/AppConfig.java +++ b/shine-server-config/src/main/java/utils/config/AppConfig.java @@ -42,6 +42,8 @@ public final class AppConfig { /** Вернёт значение строки или null, если параметр не найден */ public String getParam(String name) { + String fromSystem = System.getProperty(name); + if (fromSystem != null) return fromSystem; return properties.getProperty(name); }