feat: button-driven Telegram menu (reply keyboard + commands), reachability diagnostic, How-To update
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNQ8ghPfzAfsyVYd6HgFb6
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
import net from 'node:net';
|
||||
import dns from 'node:dns/promises';
|
||||
import { one } from '../../../lib/db';
|
||||
|
||||
export const prerender = false;
|
||||
const json = (b: unknown, s = 200) =>
|
||||
new Response(JSON.stringify(b), { status: s, headers: { 'Content-Type': 'application/json' } });
|
||||
|
||||
/** TCP-Verbindungstest aus dem Container heraus (mit Timeout). */
|
||||
function tcpProbe(host: string, port: number, timeoutMs = 6000): Promise<{ ok: boolean; ms: number; error?: string }> {
|
||||
return new Promise((resolve) => {
|
||||
const start = Date.now();
|
||||
const sock = new net.Socket();
|
||||
let done = false;
|
||||
const finish = (ok: boolean, error?: string) => {
|
||||
if (done) return; done = true;
|
||||
try { sock.destroy(); } catch { /* egal */ }
|
||||
resolve({ ok, ms: Date.now() - start, error });
|
||||
};
|
||||
sock.setTimeout(timeoutMs);
|
||||
sock.once('connect', () => finish(true));
|
||||
sock.once('timeout', () => finish(false, 'Timeout — keine Antwort (Firewall/Route?)'));
|
||||
sock.once('error', (e: any) => finish(false, e?.code || e?.message || 'Verbindungsfehler'));
|
||||
sock.connect(port, host);
|
||||
});
|
||||
}
|
||||
|
||||
/** Prüft, ob ein Host:Port aus dem Container erreichbar ist. Body {host,port} oder
|
||||
* ohne Angabe der konfigurierte NAS-Host. Testet zusätzlich DNS-Auflösung. */
|
||||
export const POST: APIRoute = async ({ request }) => {
|
||||
const b = await request.json().catch(() => ({} as any));
|
||||
let host = (b.host || '').trim();
|
||||
let port = Number(b.port) || 0;
|
||||
if (!host) {
|
||||
const s = await one<{ nas_host: string | null; nas_port: number | null; nas_protocol: string | null }>(
|
||||
'SELECT nas_host, nas_port, nas_protocol FROM settings WHERE id=1');
|
||||
host = (s?.nas_host || '').trim();
|
||||
port = s?.nas_port || (s?.nas_protocol === 'ftps' ? 21 : 22);
|
||||
}
|
||||
if (!host) return json({ error: 'Kein Host angegeben.' }, 400);
|
||||
if (!port) port = 22;
|
||||
|
||||
const out: any = { host, port };
|
||||
// DNS: nur wenn kein reines IP.
|
||||
const isIp = net.isIP(host) !== 0;
|
||||
if (!isIp) {
|
||||
try { const a = await dns.lookup(host); out.resolve = { ok: true, address: a.address }; }
|
||||
catch (e: any) { out.resolve = { ok: false, error: e?.code || 'DNS fehlgeschlagen' }; }
|
||||
} else {
|
||||
out.resolve = { ok: true, address: host, note: 'IP-Adresse' };
|
||||
}
|
||||
out.tcp = await tcpProbe(host, port);
|
||||
out.reachable = out.tcp.ok;
|
||||
return json(out);
|
||||
};
|
||||
Reference in New Issue
Block a user