139 lines
3.8 KiB
JavaScript
139 lines
3.8 KiB
JavaScript
import { resolveShineServerByServerLogin } from './shine-server-resolver.js';
|
|
import { SOLANA_ENDPOINT_DEFAULT } from '../solana-programs.js';
|
|
|
|
function normalizeUrl(value) {
|
|
return String(value || '').trim();
|
|
}
|
|
|
|
function normalizeShineWsUrl(rawUrl) {
|
|
const value = normalizeUrl(rawUrl);
|
|
if (!value) return '';
|
|
if (value.startsWith('ws://') || value.startsWith('wss://')) {
|
|
try {
|
|
const parsed = new URL(value);
|
|
if (!parsed.pathname || parsed.pathname === '/') parsed.pathname = '/ws';
|
|
return parsed.toString();
|
|
} catch {
|
|
return value;
|
|
}
|
|
}
|
|
if (value.startsWith('http://') || value.startsWith('https://')) {
|
|
try {
|
|
const parsed = new URL(value);
|
|
parsed.protocol = parsed.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
if (!parsed.pathname || parsed.pathname === '/') parsed.pathname = '/ws';
|
|
return parsed.toString();
|
|
} catch {
|
|
return `${value.replace(/^http/, 'ws').replace(/\/$/, '')}/ws`;
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
async function checkSolanaRpc(url) {
|
|
const endpoint = normalizeUrl(url);
|
|
if (!endpoint) return false;
|
|
try {
|
|
const resp = await fetch(endpoint, {
|
|
method: 'POST',
|
|
cache: 'no-store',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
jsonrpc: '2.0',
|
|
id: 1,
|
|
method: 'getVersion',
|
|
}),
|
|
});
|
|
if (!resp.ok) return false;
|
|
const json = await resp.json();
|
|
return Boolean(json?.result?.['solana-core'] || json?.result);
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function checkArweave(url) {
|
|
const base = normalizeUrl(url).replace(/\/+$/, '');
|
|
if (!base) return false;
|
|
try {
|
|
const resp = await fetch(`${base}/info`, { method: 'GET', cache: 'no-store' });
|
|
if (!resp.ok) return false;
|
|
const json = await resp.json();
|
|
return Boolean(json?.network);
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function checkShineWs(url, timeoutMs = 7000) {
|
|
const wsUrl = normalizeShineWsUrl(url);
|
|
if (!wsUrl) return Promise.resolve(false);
|
|
|
|
return new Promise((resolve) => {
|
|
let done = false;
|
|
const finish = (ok) => {
|
|
if (done) return;
|
|
done = true;
|
|
window.clearTimeout(timer);
|
|
try { ws.close(); } catch {}
|
|
resolve(Boolean(ok));
|
|
};
|
|
|
|
const timer = window.setTimeout(() => finish(false), timeoutMs);
|
|
let ws;
|
|
try {
|
|
ws = new WebSocket(wsUrl);
|
|
} catch {
|
|
finish(false);
|
|
return;
|
|
}
|
|
|
|
ws.addEventListener('open', () => {
|
|
try {
|
|
ws.send(JSON.stringify({
|
|
op: 'Ping',
|
|
requestId: `check-${Date.now()}`,
|
|
payload: { ts: Date.now() },
|
|
}));
|
|
} catch {
|
|
finish(false);
|
|
}
|
|
}, { once: true });
|
|
|
|
ws.addEventListener('message', () => finish(true), { once: true });
|
|
ws.addEventListener('error', () => finish(false), { once: true });
|
|
ws.addEventListener('close', () => finish(false), { once: true });
|
|
});
|
|
}
|
|
|
|
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';
|
|
}
|
|
if (key === 'arweaveServer') {
|
|
return (await checkArweave(url)) ? 'available' : 'unavailable';
|
|
}
|
|
return 'unavailable';
|
|
}
|