From ffa00734414af228616f1f2f148f514188df867c Mon Sep 17 00:00:00 2001 From: divocat Date: Tue, 14 Oct 2025 22:36:14 +0300 Subject: [PATCH] feat: migrate to proxied clash api methods --- fe-app-podkop/src/helpers/getBaseUrl.ts | 4 - fe-app-podkop/src/helpers/getClashApiUrl.ts | 6 - fe-app-podkop/src/helpers/index.ts | 1 - .../podkop/methods/clash/getGroupLatency.ts | 18 -- .../src/podkop/methods/clash/getProxies.ts | 14 - .../podkop/methods/clash/getProxyLatency.ts | 18 -- .../src/podkop/methods/clash/index.ts | 11 - .../src/podkop/methods/clash/setProxy.ts | 15 - .../methods/custom/getDashboardSections.ts | 4 +- fe-app-podkop/src/podkop/methods/index.ts | 1 - .../podkop/methods/shell/callBaseMethod.ts | 3 +- .../src/podkop/methods/shell/index.ts | 22 +- .../src/podkop/services/socket.service.ts | 25 +- .../podkop/tabs/dashboard/initController.ts | 15 +- .../tabs/dashboard/partials/renderSections.ts | 6 +- fe-app-podkop/src/podkop/types.ts | 8 + .../luci-static/resources/view/podkop/main.js | 292 ++++++++---------- .../resources/view/podkop/settings.js | 2 +- 18 files changed, 189 insertions(+), 276 deletions(-) delete mode 100644 fe-app-podkop/src/helpers/getBaseUrl.ts delete mode 100644 fe-app-podkop/src/podkop/methods/clash/getGroupLatency.ts delete mode 100644 fe-app-podkop/src/podkop/methods/clash/getProxies.ts delete mode 100644 fe-app-podkop/src/podkop/methods/clash/getProxyLatency.ts delete mode 100644 fe-app-podkop/src/podkop/methods/clash/index.ts delete mode 100644 fe-app-podkop/src/podkop/methods/clash/setProxy.ts diff --git a/fe-app-podkop/src/helpers/getBaseUrl.ts b/fe-app-podkop/src/helpers/getBaseUrl.ts deleted file mode 100644 index 88b82ff..0000000 --- a/fe-app-podkop/src/helpers/getBaseUrl.ts +++ /dev/null @@ -1,4 +0,0 @@ -export function getBaseUrl(): string { - const { protocol, hostname } = window.location; - return `${protocol}//${hostname}`; -} diff --git a/fe-app-podkop/src/helpers/getClashApiUrl.ts b/fe-app-podkop/src/helpers/getClashApiUrl.ts index 27032a0..0428f3d 100644 --- a/fe-app-podkop/src/helpers/getClashApiUrl.ts +++ b/fe-app-podkop/src/helpers/getClashApiUrl.ts @@ -1,9 +1,3 @@ -export function getClashApiUrl(): string { - const { hostname } = window.location; - - return `http://${hostname}:9090`; -} - export function getClashWsUrl(): string { const { hostname } = window.location; diff --git a/fe-app-podkop/src/helpers/index.ts b/fe-app-podkop/src/helpers/index.ts index 3ec39ab..06baeb7 100644 --- a/fe-app-podkop/src/helpers/index.ts +++ b/fe-app-podkop/src/helpers/index.ts @@ -1,4 +1,3 @@ -export * from './getBaseUrl'; export * from './parseValueList'; export * from './injectGlobalStyles'; export * from './withTimeout'; diff --git a/fe-app-podkop/src/podkop/methods/clash/getGroupLatency.ts b/fe-app-podkop/src/podkop/methods/clash/getGroupLatency.ts deleted file mode 100644 index 7b26ac7..0000000 --- a/fe-app-podkop/src/podkop/methods/clash/getGroupLatency.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { getClashApiUrl } from '../../../helpers'; -import { createBaseApiRequest, IBaseApiResponse } from '../../api'; - -export async function getGroupLatency( - tag: string, - timeout: number = 5000, - url: string = 'https://www.gstatic.com/generate_204', -): Promise> { - return createBaseApiRequest(() => - fetch( - `${getClashApiUrl()}/group/${tag}/delay?url=${encodeURIComponent(url)}&timeout=${timeout}`, - { - method: 'GET', - headers: { 'Content-Type': 'application/json' }, - }, - ), - ); -} diff --git a/fe-app-podkop/src/podkop/methods/clash/getProxies.ts b/fe-app-podkop/src/podkop/methods/clash/getProxies.ts deleted file mode 100644 index 2c8d90c..0000000 --- a/fe-app-podkop/src/podkop/methods/clash/getProxies.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ClashAPI } from '../../types'; -import { getClashApiUrl } from '../../../helpers'; -import { createBaseApiRequest, IBaseApiResponse } from '../../api'; - -export async function getProxies(): Promise< - IBaseApiResponse -> { - return createBaseApiRequest(() => - fetch(`${getClashApiUrl()}/proxies`, { - method: 'GET', - headers: { 'Content-Type': 'application/json' }, - }), - ); -} diff --git a/fe-app-podkop/src/podkop/methods/clash/getProxyLatency.ts b/fe-app-podkop/src/podkop/methods/clash/getProxyLatency.ts deleted file mode 100644 index 6714efa..0000000 --- a/fe-app-podkop/src/podkop/methods/clash/getProxyLatency.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { getClashApiUrl } from '../../../helpers'; -import { createBaseApiRequest, IBaseApiResponse } from '../../api'; - -export async function getProxyLatency( - tag: string, - timeout: number = 2000, - url: string = 'https://www.gstatic.com/generate_204', -): Promise> { - return createBaseApiRequest(() => - fetch( - `${getClashApiUrl()}/proxies/${tag}/delay?url=${encodeURIComponent(url)}&timeout=${timeout}`, - { - method: 'GET', - headers: { 'Content-Type': 'application/json' }, - }, - ), - ); -} diff --git a/fe-app-podkop/src/podkop/methods/clash/index.ts b/fe-app-podkop/src/podkop/methods/clash/index.ts deleted file mode 100644 index d40db47..0000000 --- a/fe-app-podkop/src/podkop/methods/clash/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { getGroupLatency } from './getGroupLatency'; -import { getProxies } from './getProxies'; -import { getProxyLatency } from './getProxyLatency'; -import { setProxy } from './setProxy'; - -export const ClashMethods = { - getGroupLatency, - getProxies, - getProxyLatency, - setProxy, -}; diff --git a/fe-app-podkop/src/podkop/methods/clash/setProxy.ts b/fe-app-podkop/src/podkop/methods/clash/setProxy.ts deleted file mode 100644 index 4642230..0000000 --- a/fe-app-podkop/src/podkop/methods/clash/setProxy.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { getClashApiUrl } from '../../../helpers'; -import { createBaseApiRequest, IBaseApiResponse } from '../../api'; - -export async function setProxy( - selector: string, - outbound: string, -): Promise> { - return createBaseApiRequest(() => - fetch(`${getClashApiUrl()}/proxies/${selector}`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name: outbound }), - }), - ); -} diff --git a/fe-app-podkop/src/podkop/methods/custom/getDashboardSections.ts b/fe-app-podkop/src/podkop/methods/custom/getDashboardSections.ts index 96ff4b1..709d6a1 100644 --- a/fe-app-podkop/src/podkop/methods/custom/getDashboardSections.ts +++ b/fe-app-podkop/src/podkop/methods/custom/getDashboardSections.ts @@ -1,7 +1,7 @@ import { getConfigSections } from './getConfigSections'; import { Podkop } from '../../types'; -import { ClashMethods } from '../clash'; import { getProxyUrlName, splitProxyString } from '../../../helpers'; +import { PodkopShellMethods } from '../shell'; interface IGetDashboardSectionsResponse { success: boolean; @@ -10,7 +10,7 @@ interface IGetDashboardSectionsResponse { export async function getDashboardSections(): Promise { const configSections = await getConfigSections(); - const clashProxies = await ClashMethods.getProxies(); + const clashProxies = await PodkopShellMethods.getClashApiProxies(); if (!clashProxies.success) { return { diff --git a/fe-app-podkop/src/podkop/methods/index.ts b/fe-app-podkop/src/podkop/methods/index.ts index 28101c6..fca93a4 100644 --- a/fe-app-podkop/src/podkop/methods/index.ts +++ b/fe-app-podkop/src/podkop/methods/index.ts @@ -1,4 +1,3 @@ -export * from './clash'; export * from './custom'; export * from './fakeip'; export * from './shell'; diff --git a/fe-app-podkop/src/podkop/methods/shell/callBaseMethod.ts b/fe-app-podkop/src/podkop/methods/shell/callBaseMethod.ts index 55da36e..37c1b37 100644 --- a/fe-app-podkop/src/podkop/methods/shell/callBaseMethod.ts +++ b/fe-app-podkop/src/podkop/methods/shell/callBaseMethod.ts @@ -3,10 +3,11 @@ import { Podkop } from '../../types'; export async function callBaseMethod( method: Podkop.AvailableMethods, + args: string[] = [], ): Promise> { const response = await executeShellCommand({ command: '/usr/bin/podkop', - args: [method], + args: [method as string, ...args], timeout: 10000, }); diff --git a/fe-app-podkop/src/podkop/methods/shell/index.ts b/fe-app-podkop/src/podkop/methods/shell/index.ts index 9b1cd93..8f8394f 100644 --- a/fe-app-podkop/src/podkop/methods/shell/index.ts +++ b/fe-app-podkop/src/podkop/methods/shell/index.ts @@ -1,5 +1,5 @@ import { callBaseMethod } from './callBaseMethod'; -import { Podkop } from '../../types'; +import { ClashAPI, Podkop } from '../../types'; export const PodkopShellMethods = { checkDNSAvailable: async () => @@ -24,4 +24,24 @@ export const PodkopShellMethods = { callBaseMethod( Podkop.AvailableMethods.GET_SING_BOX_STATUS, ), + getClashApiProxies: async () => + callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.GET_PROXIES, + ]), + getClashApiProxyLatency: async (tag: string) => + callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY, + tag, + ]), + getClashApiGroupLatency: async (tag: string) => + callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY, + tag, + ]), + setClashApiGroupProxy: async (group: string, proxy: string) => + callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.SET_GROUP_PROXY, + group, + proxy, + ]), }; diff --git a/fe-app-podkop/src/podkop/services/socket.service.ts b/fe-app-podkop/src/podkop/services/socket.service.ts index 5a401b8..5210155 100644 --- a/fe-app-podkop/src/podkop/services/socket.service.ts +++ b/fe-app-podkop/src/podkop/services/socket.service.ts @@ -21,7 +21,16 @@ class SocketManager { connect(url: string): void { if (this.sockets.has(url)) return; - const ws = new WebSocket(url); + let ws: WebSocket; + + try { + ws = new WebSocket(url); + } catch (err) { + console.error(`Failed to construct WebSocket for ${url}:`, err); + this.triggerError(url, err instanceof Event ? err : String(err)); + return; + } + this.sockets.set(url, ws); this.connected.set(url, false); this.listeners.set(url, new Set()); @@ -58,15 +67,21 @@ class SocketManager { } subscribe(url: string, listener: Listener, onError?: ErrorListener): void { + if (!this.errorListeners.has(url)) { + this.errorListeners.set(url, new Set()); + } + if (onError) { + this.errorListeners.get(url)?.add(onError); + } + if (!this.sockets.has(url)) { this.connect(url); } - this.listeners.get(url)?.add(listener); - - if (onError) { - this.errorListeners.get(url)?.add(onError); + if (!this.listeners.has(url)) { + this.listeners.set(url, new Set()); } + this.listeners.get(url)?.add(listener); } unsubscribe(url: string, listener: Listener, onError?: ErrorListener): void { diff --git a/fe-app-podkop/src/podkop/tabs/dashboard/initController.ts b/fe-app-podkop/src/podkop/tabs/dashboard/initController.ts index d10eb11..a5e1ae2 100644 --- a/fe-app-podkop/src/podkop/tabs/dashboard/initController.ts +++ b/fe-app-podkop/src/podkop/tabs/dashboard/initController.ts @@ -1,15 +1,10 @@ import { - getClashApiUrl, getClashWsUrl, onMount, preserveScrollForPage, } from '../../../helpers'; import { prettyBytes } from '../../../helpers/prettyBytes'; -import { - ClashMethods, - CustomPodkopMethods, - PodkopShellMethods, -} from '../../methods'; +import { CustomPodkopMethods, PodkopShellMethods } from '../../methods'; import { socket, store, StoreType } from '../../services'; import { renderSections, renderWidget } from './partials'; @@ -28,7 +23,7 @@ async function fetchDashboardSections() { const { data, success } = await CustomPodkopMethods.getDashboardSections(); if (!success) { - console.log('[fetchDashboardSections]: failed to fetch', getClashApiUrl()); + console.log('[fetchDashboardSections]: failed to fetch'); } store.set({ @@ -148,7 +143,7 @@ async function connectToClashSockets() { // Handlers async function handleChooseOutbound(selector: string, tag: string) { - await ClashMethods.setProxy(selector, tag); + await PodkopShellMethods.setClashApiGroupProxy(selector, tag); await fetchDashboardSections(); } @@ -160,7 +155,7 @@ async function handleTestGroupLatency(tag: string) { }, }); - await ClashMethods.getGroupLatency(tag); + await PodkopShellMethods.getClashApiGroupLatency(tag); await fetchDashboardSections(); store.set({ @@ -179,7 +174,7 @@ async function handleTestProxyLatency(tag: string) { }, }); - await ClashMethods.getProxyLatency(tag); + await PodkopShellMethods.getClashApiProxyLatency(tag); await fetchDashboardSections(); store.set({ diff --git a/fe-app-podkop/src/podkop/tabs/dashboard/partials/renderSections.ts b/fe-app-podkop/src/podkop/tabs/dashboard/partials/renderSections.ts index 2389379..bf78e7e 100644 --- a/fe-app-podkop/src/podkop/tabs/dashboard/partials/renderSections.ts +++ b/fe-app-podkop/src/podkop/tabs/dashboard/partials/renderSections.ts @@ -1,5 +1,4 @@ import { Podkop } from '../../../types'; -import { getClashApiUrl } from '../../../../helpers'; interface IRenderSectionsProps { loading: boolean; @@ -17,10 +16,7 @@ function renderFailedState() { class: 'pdk_dashboard-page__outbound-section centered', style: 'height: 127px', }, - E('span', {}, [ - E('span', {}, _('Dashboard currently unavailable')), - E('div', { style: 'text-align: center;' }, `API: ${getClashApiUrl()}`), - ]), + E('span', {}, [E('span', {}, _('Dashboard currently unavailable'))]), ); } diff --git a/fe-app-podkop/src/podkop/types.ts b/fe-app-podkop/src/podkop/types.ts index 32c0447..358e9a4 100644 --- a/fe-app-podkop/src/podkop/types.ts +++ b/fe-app-podkop/src/podkop/types.ts @@ -28,6 +28,14 @@ export namespace Podkop { GET_STATUS = 'get_status', CHECK_SING_BOX = 'check_sing_box', GET_SING_BOX_STATUS = 'get_sing_box_status', + CLASH_API = 'clash_api', + } + + export enum AvailableClashAPIMethods { + GET_PROXIES = 'get_proxies', + GET_PROXY_LATENCY = 'get_proxy_latency', + GET_GROUP_LATENCY = 'get_group_latency', + SET_GROUP_PROXY = 'set_group_proxy', } export interface Outbound { diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js index 08517ae..c7a8948 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js @@ -393,110 +393,97 @@ function validateProxyUrl(url) { }; } -// src/helpers/getBaseUrl.ts -function getBaseUrl() { - const { protocol, hostname } = window.location; - return `${protocol}//${hostname}`; -} - // src/helpers/parseValueList.ts function parseValueList(value) { return value.split(/\n/).map((line) => line.split("//")[0]).join(" ").split(/[,\s]+/).map((s) => s.trim()).filter(Boolean); } -// src/podkop/api.ts -async function createBaseApiRequest(fetchFn, options) { - const wrappedFn = () => options?.timeoutMs && options?.operationName ? withTimeout( - fetchFn(), - options.timeoutMs, - options.operationName, - options.timeoutMessage - ) : fetchFn(); - try { - const response = await wrappedFn(); - if (!response.ok) { - return { - success: false, - message: `${_("HTTP error")} ${response.status}: ${response.statusText}` - }; - } - const data = await response.json(); - return { - success: true, - data - }; - } catch (e) { - return { - success: false, - message: e instanceof Error ? e.message : _("Unknown error") - }; - } -} - -// src/podkop/methods/clash/getGroupLatency.ts -async function getGroupLatency(tag, timeout = 5e3, url = "https://www.gstatic.com/generate_204") { - return createBaseApiRequest( - () => fetch( - `${getClashApiUrl()}/group/${tag}/delay?url=${encodeURIComponent(url)}&timeout=${timeout}`, - { - method: "GET", - headers: { "Content-Type": "application/json" } - } - ) - ); -} - -// src/podkop/methods/clash/getProxies.ts -async function getProxies() { - return createBaseApiRequest( - () => fetch(`${getClashApiUrl()}/proxies`, { - method: "GET", - headers: { "Content-Type": "application/json" } - }) - ); -} - -// src/podkop/methods/clash/getProxyLatency.ts -async function getProxyLatency(tag, timeout = 2e3, url = "https://www.gstatic.com/generate_204") { - return createBaseApiRequest( - () => fetch( - `${getClashApiUrl()}/proxies/${tag}/delay?url=${encodeURIComponent(url)}&timeout=${timeout}`, - { - method: "GET", - headers: { "Content-Type": "application/json" } - } - ) - ); -} - -// src/podkop/methods/clash/setProxy.ts -async function setProxy(selector, outbound) { - return createBaseApiRequest( - () => fetch(`${getClashApiUrl()}/proxies/${selector}`, { - method: "PUT", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ name: outbound }) - }) - ); -} - -// src/podkop/methods/clash/index.ts -var ClashMethods = { - getGroupLatency, - getProxies, - getProxyLatency, - setProxy -}; - // src/podkop/methods/custom/getConfigSections.ts async function getConfigSections() { return uci.load("podkop").then(() => uci.sections("podkop")); } +// src/podkop/methods/shell/callBaseMethod.ts +async function callBaseMethod(method, args = []) { + const response = await executeShellCommand({ + command: "/usr/bin/podkop", + args: [method, ...args], + timeout: 1e4 + }); + if (response.stdout) { + return { + success: true, + data: JSON.parse(response.stdout) + }; + } + return { + success: false, + error: "" + }; +} + +// src/podkop/types.ts +var Podkop; +((Podkop2) => { + let AvailableMethods; + ((AvailableMethods2) => { + AvailableMethods2["CHECK_DNS_AVAILABLE"] = "check_dns_available"; + AvailableMethods2["CHECK_FAKEIP"] = "check_fakeip"; + AvailableMethods2["CHECK_NFT_RULES"] = "check_nft_rules"; + AvailableMethods2["GET_STATUS"] = "get_status"; + AvailableMethods2["CHECK_SING_BOX"] = "check_sing_box"; + AvailableMethods2["GET_SING_BOX_STATUS"] = "get_sing_box_status"; + AvailableMethods2["CLASH_API"] = "clash_api"; + })(AvailableMethods = Podkop2.AvailableMethods || (Podkop2.AvailableMethods = {})); + let AvailableClashAPIMethods; + ((AvailableClashAPIMethods2) => { + AvailableClashAPIMethods2["GET_PROXIES"] = "get_proxies"; + AvailableClashAPIMethods2["GET_PROXY_LATENCY"] = "get_proxy_latency"; + AvailableClashAPIMethods2["GET_GROUP_LATENCY"] = "get_group_latency"; + AvailableClashAPIMethods2["SET_GROUP_PROXY"] = "set_group_proxy"; + })(AvailableClashAPIMethods = Podkop2.AvailableClashAPIMethods || (Podkop2.AvailableClashAPIMethods = {})); +})(Podkop || (Podkop = {})); + +// src/podkop/methods/shell/index.ts +var PodkopShellMethods = { + checkDNSAvailable: async () => callBaseMethod( + Podkop.AvailableMethods.CHECK_DNS_AVAILABLE + ), + checkFakeIP: async () => callBaseMethod( + Podkop.AvailableMethods.CHECK_FAKEIP + ), + checkNftRules: async () => callBaseMethod( + Podkop.AvailableMethods.CHECK_NFT_RULES + ), + getStatus: async () => callBaseMethod(Podkop.AvailableMethods.GET_STATUS), + checkSingBox: async () => callBaseMethod( + Podkop.AvailableMethods.CHECK_SING_BOX + ), + getSingBoxStatus: async () => callBaseMethod( + Podkop.AvailableMethods.GET_SING_BOX_STATUS + ), + getClashApiProxies: async () => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.GET_PROXIES + ]), + getClashApiProxyLatency: async (tag) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY, + tag + ]), + getClashApiGroupLatency: async (tag) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY, + tag + ]), + setClashApiGroupProxy: async (group, proxy) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.SET_GROUP_PROXY, + group, + proxy + ]) +}; + // src/podkop/methods/custom/getDashboardSections.ts async function getDashboardSections() { const configSections = await getConfigSections(); - const clashProxies = await ClashMethods.getProxies(); + const clashProxies = await PodkopShellMethods.getClashApiProxies(); if (!clashProxies.success) { return { success: false, @@ -736,6 +723,35 @@ var COMMAND_SCHEDULING = { // Lowest priority }; +// src/podkop/api.ts +async function createBaseApiRequest(fetchFn, options) { + const wrappedFn = () => options?.timeoutMs && options?.operationName ? withTimeout( + fetchFn(), + options.timeoutMs, + options.operationName, + options.timeoutMessage + ) : fetchFn(); + try { + const response = await wrappedFn(); + if (!response.ok) { + return { + success: false, + message: `${_("HTTP error")} ${response.status}: ${response.statusText}` + }; + } + const data = await response.json(); + return { + success: true, + data + }; + } catch (e) { + return { + success: false, + message: e instanceof Error ? e.message : _("Unknown error") + }; + } +} + // src/podkop/methods/fakeip/getFakeIpCheck.ts async function getFakeIpCheck() { return createBaseApiRequest( @@ -770,59 +786,6 @@ var RemoteFakeIPMethods = { getIpCheck }; -// src/podkop/methods/shell/callBaseMethod.ts -async function callBaseMethod(method) { - const response = await executeShellCommand({ - command: "/usr/bin/podkop", - args: [method], - timeout: 1e4 - }); - if (response.stdout) { - return { - success: true, - data: JSON.parse(response.stdout) - }; - } - return { - success: false, - error: "" - }; -} - -// src/podkop/types.ts -var Podkop; -((Podkop2) => { - let AvailableMethods; - ((AvailableMethods2) => { - AvailableMethods2["CHECK_DNS_AVAILABLE"] = "check_dns_available"; - AvailableMethods2["CHECK_FAKEIP"] = "check_fakeip"; - AvailableMethods2["CHECK_NFT_RULES"] = "check_nft_rules"; - AvailableMethods2["GET_STATUS"] = "get_status"; - AvailableMethods2["CHECK_SING_BOX"] = "check_sing_box"; - AvailableMethods2["GET_SING_BOX_STATUS"] = "get_sing_box_status"; - })(AvailableMethods = Podkop2.AvailableMethods || (Podkop2.AvailableMethods = {})); -})(Podkop || (Podkop = {})); - -// src/podkop/methods/shell/index.ts -var PodkopShellMethods = { - checkDNSAvailable: async () => callBaseMethod( - Podkop.AvailableMethods.CHECK_DNS_AVAILABLE - ), - checkFakeIP: async () => callBaseMethod( - Podkop.AvailableMethods.CHECK_FAKEIP - ), - checkNftRules: async () => callBaseMethod( - Podkop.AvailableMethods.CHECK_NFT_RULES - ), - getStatus: async () => callBaseMethod(Podkop.AvailableMethods.GET_STATUS), - checkSingBox: async () => callBaseMethod( - Podkop.AvailableMethods.CHECK_SING_BOX - ), - getSingBoxStatus: async () => callBaseMethod( - Podkop.AvailableMethods.GET_SING_BOX_STATUS - ) -}; - // src/podkop/services/tab.service.ts var TabService = class _TabService { constructor() { @@ -1142,7 +1105,14 @@ var SocketManager = class _SocketManager { } connect(url) { if (this.sockets.has(url)) return; - const ws = new WebSocket(url); + let ws; + try { + ws = new WebSocket(url); + } catch (err) { + console.error(`Failed to construct WebSocket for ${url}:`, err); + this.triggerError(url, err instanceof Event ? err : String(err)); + return; + } this.sockets.set(url, ws); this.connected.set(url, false); this.listeners.set(url, /* @__PURE__ */ new Set()); @@ -1174,13 +1144,19 @@ var SocketManager = class _SocketManager { }); } subscribe(url, listener, onError) { - if (!this.sockets.has(url)) { - this.connect(url); + if (!this.errorListeners.has(url)) { + this.errorListeners.set(url, /* @__PURE__ */ new Set()); } - this.listeners.get(url)?.add(listener); if (onError) { this.errorListeners.get(url)?.add(onError); } + if (!this.sockets.has(url)) { + this.connect(url); + } + if (!this.listeners.has(url)) { + this.listeners.set(url, /* @__PURE__ */ new Set()); + } + this.listeners.get(url)?.add(listener); } unsubscribe(url, listener, onError) { this.listeners.get(url)?.delete(listener); @@ -1236,10 +1212,7 @@ function renderFailedState() { class: "pdk_dashboard-page__outbound-section centered", style: "height: 127px" }, - E("span", {}, [ - E("span", {}, _("Dashboard currently unavailable")), - E("div", { style: "text-align: center;" }, `API: ${getClashApiUrl()}`) - ]) + E("span", {}, [E("span", {}, _("Dashboard currently unavailable"))]) ); } function renderLoadingState() { @@ -1476,7 +1449,7 @@ async function fetchDashboardSections() { }); const { data, success } = await CustomPodkopMethods.getDashboardSections(); if (!success) { - console.log("[fetchDashboardSections]: failed to fetch", getClashApiUrl()); + console.log("[fetchDashboardSections]: failed to fetch"); } store.set({ sectionsWidget: { @@ -1585,7 +1558,7 @@ async function connectToClashSockets() { ); } async function handleChooseOutbound(selector, tag) { - await ClashMethods.setProxy(selector, tag); + await PodkopShellMethods.setClashApiGroupProxy(selector, tag); await fetchDashboardSections(); } async function handleTestGroupLatency(tag) { @@ -1595,7 +1568,7 @@ async function handleTestGroupLatency(tag) { latencyFetching: true } }); - await ClashMethods.getGroupLatency(tag); + await PodkopShellMethods.getClashApiGroupLatency(tag); await fetchDashboardSections(); store.set({ sectionsWidget: { @@ -1611,7 +1584,7 @@ async function handleTestProxyLatency(tag) { latencyFetching: true } }); - await ClashMethods.getProxyLatency(tag); + await PodkopShellMethods.getClashApiProxyLatency(tag); await fetchDashboardSections(); store.set({ sectionsWidget: { @@ -3141,10 +3114,6 @@ async function onMount(id) { } // src/helpers/getClashApiUrl.ts -function getClashApiUrl() { - const { hostname } = window.location; - return `http://${hostname}:9090`; -} function getClashWsUrl() { const { hostname } = window.location; return `ws://${hostname}:9090`; @@ -3193,7 +3162,6 @@ return baseclass.extend({ CACHE_TIMEOUT, COMMAND_SCHEDULING, COMMAND_TIMEOUT, - ClashMethods, CustomPodkopMethods, DIAGNOSTICS_INITIAL_DELAY, DIAGNOSTICS_UPDATE_INTERVAL, @@ -3216,8 +3184,6 @@ return baseclass.extend({ bulkValidate, coreService, executeShellCommand, - getBaseUrl, - getClashApiUrl, getClashUIUrl, getClashWsUrl, getProxyUrlName, diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js index 6c26ad9..0715a65 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js @@ -170,7 +170,7 @@ function createSettingsContent(section) { form.Flag, 'enable_yacd', _('Enable YACD'), - `${main.getClashApiUrl()}/ui`, + `${main.getClashUIUrl()}`, ); o.default = '0'; o.rmempty = false;