SHA256
Автоопределение SHiNE-сервера по логину через PDA
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@
|
||||
<link rel="manifest" href="./manifest.webmanifest" />
|
||||
<title>Shine UI Demo</title>
|
||||
<script>
|
||||
window.__SHINE_BUILD_HASH__ = '20260616091500';
|
||||
window.__SHINE_BUILD_HASH__ = '20260616124000';
|
||||
window.__SHINE_CLIENT_VERSION__ = '1.2.8';
|
||||
</script>
|
||||
<script>
|
||||
|
||||
+2
-2
@@ -33,7 +33,7 @@ import {
|
||||
} from './state.js';
|
||||
|
||||
import * as startView from './pages/start-view.js?v=202606142105';
|
||||
import * as entrySettingsView from './pages/entry-settings-view.js';
|
||||
import * as entrySettingsView from './pages/entry-settings-view.js?v=202606161240';
|
||||
import * as registerView from './pages/register-view.js';
|
||||
import * as registrationPaymentView from './pages/registration-payment-view.js';
|
||||
import * as registrationKeysView from './pages/registration-keys-view.js';
|
||||
@@ -51,7 +51,7 @@ import * as profileEditView from './pages/profile-edit-view.js';
|
||||
import * as walletView from './pages/wallet-view.js?v=202605300007';
|
||||
import * as settingsView from './pages/settings-view.js';
|
||||
import * as developerSettingsView from './pages/developer-settings-view.js';
|
||||
import * as serverSettingsView from './pages/server-settings-view.js';
|
||||
import * as serverSettingsView from './pages/server-settings-view.js?v=202606161240';
|
||||
import * as toolsSettingsView from './pages/tools-settings-view.js';
|
||||
import * as deviceView from './pages/device-view.js?v=202606131435';
|
||||
import * as connectDeviceView from './pages/connect-device-view.js?v=202606142055';
|
||||
|
||||
@@ -173,7 +173,7 @@ export function render({ navigate }) {
|
||||
let cleanupEvent = () => {};
|
||||
let disposed = false;
|
||||
let settingsBusy = false;
|
||||
let pairingPasswordConfigured = loadLocalPairingPasswordState(state.session.login, state.entrySettings.shineServer);
|
||||
let pairingPasswordConfigured = loadLocalPairingPasswordState(state.session.login, state.entrySettings.shineServerLogin || state.entrySettings.shineServerHttp);
|
||||
let dialogMode = '';
|
||||
|
||||
screen.append(
|
||||
@@ -357,7 +357,7 @@ export function render({ navigate }) {
|
||||
ttlSeconds: 180,
|
||||
}));
|
||||
pairingPasswordConfigured = false;
|
||||
saveLocalPairingPasswordState(state.session.login, state.entrySettings.shineServer, false);
|
||||
saveLocalPairingPasswordState(state.session.login, state.entrySettings.shineServerLogin || state.entrySettings.shineServerHttp, false);
|
||||
setAuthInfo(`Подключение по коду без дополнительного пароля включено. TTL: ${payload?.ttlSeconds || 180} сек.`);
|
||||
setStatus(status, 'Дополнительный пароль убран. Подключение по коду теперь работает без него.', 'info');
|
||||
};
|
||||
@@ -598,7 +598,7 @@ export function render({ navigate }) {
|
||||
ttlSeconds: 180,
|
||||
}));
|
||||
pairingPasswordConfigured = true;
|
||||
saveLocalPairingPasswordState(state.session.login, state.entrySettings.shineServer, true);
|
||||
saveLocalPairingPasswordState(state.session.login, state.entrySettings.shineServerLogin || state.entrySettings.shineServerHttp, true);
|
||||
closePasswordDialog();
|
||||
renderSettingsCard();
|
||||
setAuthInfo(`Подключение по коду включено с дополнительным паролем. TTL: ${payload?.ttlSeconds || 180} сек.`);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { renderHeader } from '../components/header.js';
|
||||
import { saveEntrySettings, state } from '../state.js';
|
||||
import { checkServerAvailabilityByKey } from '../services/server-health-service.js';
|
||||
import { checkServerAvailabilityByKey, resolveAndCheckShineServerLogin } from '../services/server-health-service.js';
|
||||
|
||||
export const pageMeta = { id: 'entry-settings-view', title: 'Настройки входа', showAppChrome: false };
|
||||
|
||||
const SERVER_FIELDS = [
|
||||
{ key: 'solanaServer', label: 'Адрес Solana сервера' },
|
||||
{ key: 'shineServer', label: 'Адрес сервера Сияние' },
|
||||
{ key: 'shineServerLogin', label: 'Логин сервера Сияние' },
|
||||
{ key: 'arweaveServer', label: 'Адрес сервера Arweave' },
|
||||
];
|
||||
|
||||
@@ -17,7 +17,8 @@ export function render({ navigate }) {
|
||||
const draft = {
|
||||
language: state.entrySettings.language,
|
||||
solanaServer: state.entrySettings.solanaServer,
|
||||
shineServer: state.entrySettings.shineServer,
|
||||
shineServerLogin: state.entrySettings.shineServerLogin,
|
||||
shineServerHttp: state.entrySettings.shineServerHttp,
|
||||
arweaveServer: state.entrySettings.arweaveServer,
|
||||
statuses: { ...state.entrySettings.statuses },
|
||||
};
|
||||
@@ -69,13 +70,15 @@ export function render({ navigate }) {
|
||||
const status = document.createElement('span');
|
||||
status.className = 'status-line';
|
||||
|
||||
const applyStatus = (value) => {
|
||||
const applyStatus = (value, exactAddress = '') => {
|
||||
draft.statuses[field.key] = value;
|
||||
checkButton.classList.remove('is-available', 'is-unavailable');
|
||||
status.classList.remove('is-available', 'is-unavailable');
|
||||
|
||||
if (value === 'available') {
|
||||
status.textContent = 'Доступен';
|
||||
status.textContent = field.key === 'shineServerLogin' && exactAddress
|
||||
? `Доступен: ${exactAddress}`
|
||||
: 'Доступен';
|
||||
checkButton.classList.add('is-available');
|
||||
status.classList.add('is-available');
|
||||
} else if (value === 'unavailable') {
|
||||
@@ -83,7 +86,9 @@ export function render({ navigate }) {
|
||||
checkButton.classList.add('is-unavailable');
|
||||
status.classList.add('is-unavailable');
|
||||
} else {
|
||||
status.textContent = 'Статус не проверен';
|
||||
status.textContent = field.key === 'shineServerLogin' && draft.shineServerHttp
|
||||
? `Текущий адрес: ${draft.shineServerHttp}`
|
||||
: 'Статус не проверен';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -92,8 +97,15 @@ export function render({ navigate }) {
|
||||
checkButton.disabled = true;
|
||||
checkButton.textContent = 'Проверка...';
|
||||
try {
|
||||
const next = await checkServerAvailabilityByKey(field.key, input.value);
|
||||
applyStatus(next);
|
||||
if (field.key === 'shineServerLogin') {
|
||||
const resolved = await resolveAndCheckShineServerLogin(input.value, draft.solanaServer);
|
||||
draft.shineServerHttp = resolved.httpBase;
|
||||
draft.shineServer = resolved.wsUrl;
|
||||
applyStatus(resolved.status, resolved.httpBase);
|
||||
} else {
|
||||
const next = await checkServerAvailabilityByKey(field.key, input.value);
|
||||
applyStatus(next);
|
||||
}
|
||||
} finally {
|
||||
checkButton.disabled = false;
|
||||
checkButton.textContent = 'Проверить';
|
||||
@@ -148,9 +160,13 @@ export function render({ navigate }) {
|
||||
saveButton.className = 'primary-btn';
|
||||
saveButton.type = 'button';
|
||||
saveButton.textContent = 'Сохранить';
|
||||
saveButton.addEventListener('click', () => {
|
||||
saveEntrySettings(draft);
|
||||
navigate('start-view');
|
||||
saveButton.addEventListener('click', async () => {
|
||||
try {
|
||||
await saveEntrySettings(draft);
|
||||
navigate('start-view');
|
||||
} catch (error) {
|
||||
window.alert(error?.message || 'Не удалось сохранить настройки входа.');
|
||||
}
|
||||
});
|
||||
|
||||
actions.append(serverUiButton, cancelButton, saveButton);
|
||||
@@ -161,7 +177,7 @@ export function render({ navigate }) {
|
||||
help.textContent = '?';
|
||||
help.addEventListener('click', () => {
|
||||
window.alert(
|
||||
'Текст для разработчиков: после ввода адреса любого сервера автопроверка запускается по кнопке "Проверить", после перехода в другое поле или если подождать больше 3 секунд. Зелёный статус означает доступность, красный — недоступность.',
|
||||
'Текст для разработчиков: для SHiNE вводится логин серверного аккаунта. Клиент читает его PDA, берёт server_address, показывает точный https-адрес и проверяет доступность WS-канала автоматически.',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { renderHeader } from '../components/header.js';
|
||||
import { saveEntrySettings, state } from '../state.js';
|
||||
import { checkServerAvailabilityByKey } from '../services/server-health-service.js';
|
||||
import { checkServerAvailabilityByKey, resolveAndCheckShineServerLogin } from '../services/server-health-service.js';
|
||||
|
||||
export const pageMeta = { id: 'server-settings-view', title: 'Настройки серверов' };
|
||||
|
||||
const SERVER_FIELDS = [
|
||||
{ key: 'solanaServer', label: 'Адрес Solana сервера' },
|
||||
{ key: 'shineServer', label: 'Адрес сервера Сияние' },
|
||||
{ key: 'shineServerLogin', label: 'Логин сервера Сияние' },
|
||||
{ key: 'arweaveServer', label: 'Адрес сервера Arweave' },
|
||||
];
|
||||
|
||||
@@ -17,7 +17,8 @@ export function render({ navigate }) {
|
||||
const draft = {
|
||||
language: state.entrySettings.language,
|
||||
solanaServer: state.entrySettings.solanaServer,
|
||||
shineServer: state.entrySettings.shineServer,
|
||||
shineServerLogin: state.entrySettings.shineServerLogin,
|
||||
shineServerHttp: state.entrySettings.shineServerHttp,
|
||||
arweaveServer: state.entrySettings.arweaveServer,
|
||||
callPreflightTimeoutMs: Number(state.entrySettings.callPreflightTimeoutMs || 6000),
|
||||
statuses: { ...state.entrySettings.statuses },
|
||||
@@ -52,13 +53,15 @@ export function render({ navigate }) {
|
||||
const status = document.createElement('span');
|
||||
status.className = 'status-line';
|
||||
|
||||
const applyStatus = (value) => {
|
||||
const applyStatus = (value, exactAddress = '') => {
|
||||
draft.statuses[field.key] = value;
|
||||
checkButton.classList.remove('is-available', 'is-unavailable');
|
||||
status.classList.remove('is-available', 'is-unavailable');
|
||||
|
||||
if (value === 'available') {
|
||||
status.textContent = 'Доступен';
|
||||
status.textContent = field.key === 'shineServerLogin' && exactAddress
|
||||
? `Доступен: ${exactAddress}`
|
||||
: 'Доступен';
|
||||
checkButton.classList.add('is-available');
|
||||
status.classList.add('is-available');
|
||||
} else if (value === 'unavailable') {
|
||||
@@ -66,7 +69,9 @@ export function render({ navigate }) {
|
||||
checkButton.classList.add('is-unavailable');
|
||||
status.classList.add('is-unavailable');
|
||||
} else {
|
||||
status.textContent = 'Статус не проверен';
|
||||
status.textContent = field.key === 'shineServerLogin' && draft.shineServerHttp
|
||||
? `Текущий адрес: ${draft.shineServerHttp}`
|
||||
: 'Статус не проверен';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,8 +80,15 @@ export function render({ navigate }) {
|
||||
checkButton.disabled = true;
|
||||
checkButton.textContent = 'Проверка...';
|
||||
try {
|
||||
const next = await checkServerAvailabilityByKey(field.key, input.value);
|
||||
applyStatus(next);
|
||||
if (field.key === 'shineServerLogin') {
|
||||
const resolved = await resolveAndCheckShineServerLogin(input.value, draft.solanaServer);
|
||||
draft.shineServerHttp = resolved.httpBase;
|
||||
draft.shineServer = resolved.wsUrl;
|
||||
applyStatus(resolved.status, resolved.httpBase);
|
||||
} else {
|
||||
const next = await checkServerAvailabilityByKey(field.key, input.value);
|
||||
applyStatus(next);
|
||||
}
|
||||
} finally {
|
||||
checkButton.disabled = false;
|
||||
checkButton.textContent = 'Проверить';
|
||||
@@ -149,9 +161,13 @@ export function render({ navigate }) {
|
||||
saveButton.className = 'primary-btn';
|
||||
saveButton.type = 'button';
|
||||
saveButton.textContent = 'Сохранить';
|
||||
saveButton.addEventListener('click', () => {
|
||||
saveEntrySettings(draft);
|
||||
navigate('settings-view');
|
||||
saveButton.addEventListener('click', async () => {
|
||||
try {
|
||||
await saveEntrySettings(draft);
|
||||
navigate('settings-view');
|
||||
} catch (error) {
|
||||
window.alert(error?.message || 'Не удалось сохранить настройки серверов.');
|
||||
}
|
||||
});
|
||||
|
||||
actions.append(cancelButton, saveButton);
|
||||
@@ -162,7 +178,7 @@ export function render({ navigate }) {
|
||||
help.textContent = '?';
|
||||
help.addEventListener('click', () => {
|
||||
window.alert(
|
||||
'Текст для разработчиков: после ввода адреса любого сервера автопроверка запускается по кнопке "Проверить", после перехода в другое поле или если подождать больше 3 секунд. Зелёный статус означает доступность, красный — недоступность.',
|
||||
'Текст для разработчиков: для SHiNE вводится логин серверного аккаунта. Клиент читает его PDA, берёт server_address, показывает точный https-адрес и проверяет доступность WS-канала автоматически.',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { resolveShineServerByServerLogin } from './shine-server-resolver.js';
|
||||
import { SOLANA_ENDPOINT_DEFAULT } from '../solana-programs.js';
|
||||
|
||||
function normalizeUrl(value) {
|
||||
return String(value || '').trim();
|
||||
}
|
||||
@@ -103,10 +106,28 @@ function checkShineWs(url, timeoutMs = 7000) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function resolveAndCheckShineServerLogin(serverLogin, solanaEndpoint) {
|
||||
const resolved = await resolveShineServerByServerLogin({
|
||||
serverLogin,
|
||||
solanaEndpoint,
|
||||
});
|
||||
const available = await checkShineWs(resolved.wsUrl);
|
||||
return {
|
||||
status: available ? 'available' : 'unavailable',
|
||||
serverLogin: resolved.serverLogin,
|
||||
serverAddress: resolved.serverAddress,
|
||||
httpBase: resolved.httpBase,
|
||||
wsUrl: resolved.wsUrl,
|
||||
};
|
||||
}
|
||||
|
||||
export async function checkServerAvailabilityByKey(key, url) {
|
||||
if (key === 'solanaServer') {
|
||||
return (await checkSolanaRpc(url)) ? 'available' : 'unavailable';
|
||||
}
|
||||
if (key === 'shineServerLogin') {
|
||||
return (await resolveAndCheckShineServerLogin(url, SOLANA_ENDPOINT_DEFAULT)).status;
|
||||
}
|
||||
if (key === 'shineServer') {
|
||||
return (await checkShineWs(url)) ? 'available' : 'unavailable';
|
||||
}
|
||||
@@ -115,4 +136,3 @@ export async function checkServerAvailabilityByKey(key, url) {
|
||||
}
|
||||
return 'unavailable';
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import { readShineUserPda } from './shine-user-pda-service.js';
|
||||
|
||||
export const DEFAULT_SHINE_SERVER_LOGIN = 'shineupme';
|
||||
export const DEFAULT_SHINE_SERVER_ADDRESS = 'shineup.me';
|
||||
export const DEFAULT_SHINE_SERVER_HTTP = `https://${DEFAULT_SHINE_SERVER_ADDRESS}`;
|
||||
export const DEFAULT_SHINE_SERVER_WS = `wss://${DEFAULT_SHINE_SERVER_ADDRESS}/ws`;
|
||||
|
||||
function normalizeHostLike(value) {
|
||||
const raw = String(value || '').trim();
|
||||
if (!raw) return '';
|
||||
try {
|
||||
const withScheme = /^[a-z]+:\/\//i.test(raw) ? raw : `https://${raw}`;
|
||||
const parsed = new URL(withScheme);
|
||||
return String(parsed.host || '').trim().toLowerCase();
|
||||
} catch {
|
||||
return raw.replace(/^https?:\/\//i, '').replace(/^wss?:\/\//i, '').replace(/\/.*$/, '').trim().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeShineServerLogin(value) {
|
||||
return String(value || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
export function buildShineHttpUrlFromAddress(address) {
|
||||
const host = normalizeHostLike(address);
|
||||
if (!host) return DEFAULT_SHINE_SERVER_HTTP;
|
||||
return `https://${host}`;
|
||||
}
|
||||
|
||||
export function buildShineWsUrlFromAddress(address) {
|
||||
const host = normalizeHostLike(address);
|
||||
if (!host) return DEFAULT_SHINE_SERVER_WS;
|
||||
return `wss://${host}/ws`;
|
||||
}
|
||||
|
||||
export async function resolveShineServerByServerLogin({ serverLogin, solanaEndpoint }) {
|
||||
const cleanServerLogin = normalizeShineServerLogin(serverLogin) || DEFAULT_SHINE_SERVER_LOGIN;
|
||||
const parsed = await readShineUserPda({
|
||||
login: cleanServerLogin,
|
||||
solanaEndpoint,
|
||||
});
|
||||
if (!parsed?.isServer) {
|
||||
throw new Error(`Логин @${cleanServerLogin} не опубликован как сервер SHiNE.`);
|
||||
}
|
||||
const serverAddress = normalizeHostLike(parsed?.serverAddress || '');
|
||||
if (!serverAddress) {
|
||||
throw new Error(`У server PDA пользователя @${cleanServerLogin} не задан server_address.`);
|
||||
}
|
||||
return {
|
||||
serverLogin: cleanServerLogin,
|
||||
serverAddress,
|
||||
httpBase: buildShineHttpUrlFromAddress(serverAddress),
|
||||
wsUrl: buildShineWsUrlFromAddress(serverAddress),
|
||||
userPda: parsed,
|
||||
};
|
||||
}
|
||||
|
||||
export async function resolveShineServerForUserLogin({ login, solanaEndpoint, fallbackServerLogin = '' }) {
|
||||
const cleanLogin = normalizeShineServerLogin(login);
|
||||
if (!cleanLogin) throw new Error('Не указан логин пользователя для поиска сервера доступа.');
|
||||
const parsedUser = await readShineUserPda({
|
||||
login: cleanLogin,
|
||||
solanaEndpoint,
|
||||
});
|
||||
const accessServers = Array.isArray(parsedUser?.accessServers)
|
||||
? parsedUser.accessServers.map((value) => normalizeShineServerLogin(value)).filter(Boolean)
|
||||
: [];
|
||||
const pickedServerLogin = accessServers[0] || normalizeShineServerLogin(fallbackServerLogin);
|
||||
if (!pickedServerLogin) {
|
||||
throw new Error(`У пользователя @${cleanLogin} в PDA не указан access server.`);
|
||||
}
|
||||
const resolved = await resolveShineServerByServerLogin({
|
||||
serverLogin: pickedServerLogin,
|
||||
solanaEndpoint,
|
||||
});
|
||||
return {
|
||||
...resolved,
|
||||
accessServerLogin: pickedServerLogin,
|
||||
userPda: parsedUser,
|
||||
};
|
||||
}
|
||||
+34
-5
@@ -1,6 +1,12 @@
|
||||
import { AuthService } from './services/auth-service.js';
|
||||
import { listStoredMessages, putStoredMessage, clearStoredMessages } from './services/message-store.js';
|
||||
import { SOLANA_ENDPOINT_DEFAULT } from './solana-programs.js';
|
||||
import {
|
||||
DEFAULT_SHINE_SERVER_HTTP,
|
||||
DEFAULT_SHINE_SERVER_LOGIN,
|
||||
DEFAULT_SHINE_SERVER_WS,
|
||||
resolveShineServerByServerLogin,
|
||||
} from './services/shine-server-resolver.js';
|
||||
|
||||
const clone = (value) => JSON.parse(JSON.stringify(value));
|
||||
const SESSION_STORAGE_KEY = 'shine-ui-current-session-v1';
|
||||
@@ -78,7 +84,9 @@ function inferTunnelWsUrl() {
|
||||
|
||||
const LOCAL_WS_OVERRIDE_URL = readLocalWsOverrideUrl() || inferTunnelWsUrl();
|
||||
const DEFAULT_SOLANA_SERVER = SOLANA_ENDPOINT_DEFAULT;
|
||||
const DEFAULT_SHINE_SERVER = 'wss://shineup.me/ws';
|
||||
const DEFAULT_SHINE_SERVER = DEFAULT_SHINE_SERVER_WS;
|
||||
const DEFAULT_SHINE_SERVER_LOGIN_VALUE = DEFAULT_SHINE_SERVER_LOGIN;
|
||||
const DEFAULT_SHINE_SERVER_HTTP_VALUE = DEFAULT_SHINE_SERVER_HTTP;
|
||||
const DEFAULT_ARWEAVE_SERVER = 'https://arweave.net';
|
||||
const DEFAULT_CALL_PREFLIGHT_TIMEOUT_MS = 6000;
|
||||
const DEFAULT_OPENAI_BASE_URL = 'https://api.openai.com/v1';
|
||||
@@ -171,11 +179,13 @@ function persistEntrySettings(settings) {
|
||||
language: String(settings?.language || 'ru'),
|
||||
solanaServer: String(settings?.solanaServer || DEFAULT_SOLANA_SERVER),
|
||||
shineServer: String(settings?.shineServer || DEFAULT_SHINE_SERVER),
|
||||
shineServerLogin: String(settings?.shineServerLogin || DEFAULT_SHINE_SERVER_LOGIN_VALUE),
|
||||
shineServerHttp: String(settings?.shineServerHttp || DEFAULT_SHINE_SERVER_HTTP_VALUE),
|
||||
arweaveServer: String(settings?.arweaveServer || DEFAULT_ARWEAVE_SERVER),
|
||||
callPreflightTimeoutMs: Math.max(1000, Math.min(20000, Number(settings?.callPreflightTimeoutMs || DEFAULT_CALL_PREFLIGHT_TIMEOUT_MS) || DEFAULT_CALL_PREFLIGHT_TIMEOUT_MS)),
|
||||
statuses: {
|
||||
solanaServer: String(settings?.statuses?.solanaServer || 'idle'),
|
||||
shineServer: String(settings?.statuses?.shineServer || 'idle'),
|
||||
shineServerLogin: String(settings?.statuses?.shineServerLogin || settings?.statuses?.shineServer || 'idle'),
|
||||
arweaveServer: String(settings?.statuses?.arweaveServer || 'idle'),
|
||||
},
|
||||
tools: normalizeToolsSettings(settings?.tools),
|
||||
@@ -235,11 +245,13 @@ function createInitialState({ withStoredSession = true } = {}) {
|
||||
language: String(storedEntrySettings?.language || 'ru'),
|
||||
solanaServer: String(storedEntrySettings?.solanaServer || DEFAULT_SOLANA_SERVER),
|
||||
shineServer: String(LOCAL_WS_OVERRIDE_URL || storedEntrySettings?.shineServer || initialShineServer),
|
||||
shineServerLogin: String(storedEntrySettings?.shineServerLogin || DEFAULT_SHINE_SERVER_LOGIN_VALUE),
|
||||
shineServerHttp: String(storedEntrySettings?.shineServerHttp || DEFAULT_SHINE_SERVER_HTTP_VALUE),
|
||||
arweaveServer: String(storedEntrySettings?.arweaveServer || DEFAULT_ARWEAVE_SERVER),
|
||||
callPreflightTimeoutMs: Math.max(1000, Math.min(20000, Number(storedEntrySettings?.callPreflightTimeoutMs || DEFAULT_CALL_PREFLIGHT_TIMEOUT_MS) || DEFAULT_CALL_PREFLIGHT_TIMEOUT_MS)),
|
||||
statuses: {
|
||||
solanaServer: String(storedEntrySettings?.statuses?.solanaServer || 'idle'),
|
||||
shineServer: String(storedEntrySettings?.statuses?.shineServer || 'idle'),
|
||||
shineServerLogin: String(storedEntrySettings?.statuses?.shineServerLogin || storedEntrySettings?.statuses?.shineServer || 'idle'),
|
||||
arweaveServer: String(storedEntrySettings?.statuses?.arweaveServer || 'idle'),
|
||||
},
|
||||
tools: normalizeToolsSettings(storedEntrySettings?.tools),
|
||||
@@ -649,11 +661,28 @@ export function checkServerAvailability(address) {
|
||||
}
|
||||
|
||||
export async function saveEntrySettings(nextSettings) {
|
||||
const forcedShineServer = LOCAL_WS_OVERRIDE_URL || nextSettings.shineServer;
|
||||
const nextSolanaServer = String(nextSettings?.solanaServer || state.entrySettings.solanaServer || DEFAULT_SOLANA_SERVER);
|
||||
const nextShineServerLogin = String(nextSettings?.shineServerLogin || state.entrySettings.shineServerLogin || DEFAULT_SHINE_SERVER_LOGIN_VALUE).trim().toLowerCase()
|
||||
|| DEFAULT_SHINE_SERVER_LOGIN_VALUE;
|
||||
let forcedShineServer = LOCAL_WS_OVERRIDE_URL || '';
|
||||
let resolvedShineServerHttp = String(state.entrySettings.shineServerHttp || DEFAULT_SHINE_SERVER_HTTP_VALUE).trim() || DEFAULT_SHINE_SERVER_HTTP_VALUE;
|
||||
|
||||
if (!forcedShineServer) {
|
||||
const resolved = await resolveShineServerByServerLogin({
|
||||
serverLogin: nextShineServerLogin,
|
||||
solanaEndpoint: nextSolanaServer,
|
||||
});
|
||||
forcedShineServer = resolved.wsUrl;
|
||||
resolvedShineServerHttp = resolved.httpBase;
|
||||
}
|
||||
|
||||
state.entrySettings = {
|
||||
...state.entrySettings,
|
||||
...nextSettings,
|
||||
solanaServer: nextSolanaServer,
|
||||
shineServer: forcedShineServer,
|
||||
shineServerLogin: nextShineServerLogin,
|
||||
shineServerHttp: resolvedShineServerHttp,
|
||||
statuses: {
|
||||
...state.entrySettings.statuses,
|
||||
...(nextSettings.statuses || {}),
|
||||
@@ -662,7 +691,7 @@ export async function saveEntrySettings(nextSettings) {
|
||||
};
|
||||
persistEntrySettings(state.entrySettings);
|
||||
await authService.reconnect(state.entrySettings.shineServer);
|
||||
state.startHint = 'Настройки входа сохранены, адреса серверов обновлены.';
|
||||
state.startHint = `Настройки входа сохранены. SHiNE: ${state.entrySettings.shineServerHttp}`;
|
||||
}
|
||||
|
||||
export function clearStartHint() {
|
||||
|
||||
Reference in New Issue
Block a user