Implement Mihomo external-controller support in configuration and gateway
Publish telemt-api gateway Docker image / test (push) Successful in 34s
Publish telemt-api gateway Docker image / build-and-push (push) Successful in 2m55s

- Added optional Mihomo configuration fields in `config.compose.yaml` and `config.example.yaml` for enhanced integration with the Mihomo external-controller.
- Updated the `Gateway` to handle Mihomo API requests, including proxying and error handling for Mihomo-specific endpoints.
- Enhanced the documentation in `GATEWAY_RUN.md` to guide users on configuring Mihomo integration.
- Introduced new utility functions in the web client for interacting with Mihomo API endpoints, improving the overall user experience.
- Updated the sidebar in the Svelte components to include a link to the Mihomo section, enhancing navigation.
This commit is contained in:
Denozordec
2026-03-31 00:32:19 +07:00
parent bbd9619290
commit 2d7b06260e
17 changed files with 1093 additions and 9 deletions
+58
View File
@@ -7,12 +7,70 @@ import type {
TelemtSuccess,
UserInfo
} from './telemt-v1.js';
import type { MihomoMetaResponse } from './mihomo-types.js';
export function gatewayBase(): string {
const u = PUBLIC_TELEMT_GATEWAY_URL || '';
return u.replace(/\/$/, '');
}
/** Путь к Mihomo external-controller через шлюз: без ведущего слэша. */
export function mihomoUrl(alias: string, path: string): string {
const p = path.replace(/^\/+/, '');
return `${gatewayBase()}/api/${encodeURIComponent(alias)}/mihomo/${p}`;
}
/** WebSocket к тому же origin (ws / wss). */
export function mihomoWsUrl(alias: string, path: string): string {
const p = path.replace(/^\/+/, '');
const base = gatewayBase();
const wsBase = base.replace(/^http/, 'ws');
return `${wsBase}/api/${encodeURIComponent(alias)}/mihomo/${p}`;
}
export async function fetchMihomoMeta(alias: string): Promise<MihomoMetaResponse> {
const res = await fetch(mihomoUrl(alias, 'meta'));
const body = (await parseJson(res)) as Record<string, unknown> | null;
if (res.status === 404) {
throw new ApiError('Mihomo не настроен для этой ноды', 404, body);
}
if (!res.ok) {
throw new ApiError(`Mihomo meta HTTP ${res.status}`, res.status, body);
}
if (!body || body.ok !== true) {
throw new ApiError('Mihomo meta: неверный ответ', res.status, body);
}
return body as unknown as MihomoMetaResponse;
}
export async function fetchMihomoJson<T>(alias: string, path: string): Promise<T> {
const res = await fetch(mihomoUrl(alias, path));
const body = await parseJson(res);
if (res.status === 404) {
throw new ApiError('Mihomo не настроен для этой ноды', 404, body);
}
if (!res.ok) {
throw new ApiError(`Mihomo HTTP ${res.status}`, res.status, body);
}
return body as T;
}
export async function mihomoPut(alias: string, path: string, jsonBody: unknown): Promise<void> {
const res = await fetch(mihomoUrl(alias, path), {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(jsonBody)
});
if (res.status === 404) {
const body = await parseJson(res);
throw new ApiError('Mihomo не настроен для этой ноды', 404, body);
}
if (!res.ok) {
const body = await parseJson(res);
throw new ApiError(`Mihomo PUT HTTP ${res.status}`, res.status, body);
}
}
export type AggEnvelope<T> = {
ok: true;
generated_at: string;
+35
View File
@@ -0,0 +1,35 @@
/** GET /proxies — фрагмент ответа Mihomo external-controller. */
export type MihomoProxiesResponse = {
proxies?: Record<string, MihomoProxyEntry>;
};
export type MihomoProxyEntry = {
type?: string;
name?: string;
now?: string;
all?: string[];
history?: { time: string; delay: number }[];
udp?: boolean;
[key: string]: unknown;
};
export type MihomoConnectionsResponse = {
total?: number;
connections?: MihomoConnection[];
};
export type MihomoConnection = {
metadata?: { network?: string; [k: string]: unknown };
chains?: string[];
[key: string]: unknown;
};
export type MihomoMetaResponse = {
ok: true;
controller_base: string;
};
export type MihomoDelayResponse = {
delay?: number;
message?: string;
};