Автоопределение SHiNE-сервера по логину через PDA

This commit is contained in:
AidarKC
2026-06-16 16:32:33 +04:00
parent 3efa8bb7ee
commit f8a76bcd7f
19 changed files with 17426 additions and 48 deletions
@@ -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,
};
}