mirror of
https://github.com/itdoginfo/podkop.git
synced 2026-01-31 06:40:46 +03:00
feat: migrate to proxied clash api methods
This commit is contained in:
@@ -1,4 +0,0 @@
|
|||||||
export function getBaseUrl(): string {
|
|
||||||
const { protocol, hostname } = window.location;
|
|
||||||
return `${protocol}//${hostname}`;
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
export function getClashApiUrl(): string {
|
|
||||||
const { hostname } = window.location;
|
|
||||||
|
|
||||||
return `http://${hostname}:9090`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getClashWsUrl(): string {
|
export function getClashWsUrl(): string {
|
||||||
const { hostname } = window.location;
|
const { hostname } = window.location;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
export * from './getBaseUrl';
|
|
||||||
export * from './parseValueList';
|
export * from './parseValueList';
|
||||||
export * from './injectGlobalStyles';
|
export * from './injectGlobalStyles';
|
||||||
export * from './withTimeout';
|
export * from './withTimeout';
|
||||||
|
|||||||
@@ -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<IBaseApiResponse<void>> {
|
|
||||||
return createBaseApiRequest<void>(() =>
|
|
||||||
fetch(
|
|
||||||
`${getClashApiUrl()}/group/${tag}/delay?url=${encodeURIComponent(url)}&timeout=${timeout}`,
|
|
||||||
{
|
|
||||||
method: 'GET',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { ClashAPI } from '../../types';
|
|
||||||
import { getClashApiUrl } from '../../../helpers';
|
|
||||||
import { createBaseApiRequest, IBaseApiResponse } from '../../api';
|
|
||||||
|
|
||||||
export async function getProxies(): Promise<
|
|
||||||
IBaseApiResponse<ClashAPI.Proxies>
|
|
||||||
> {
|
|
||||||
return createBaseApiRequest<ClashAPI.Proxies>(() =>
|
|
||||||
fetch(`${getClashApiUrl()}/proxies`, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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<IBaseApiResponse<void>> {
|
|
||||||
return createBaseApiRequest<void>(() =>
|
|
||||||
fetch(
|
|
||||||
`${getClashApiUrl()}/proxies/${tag}/delay?url=${encodeURIComponent(url)}&timeout=${timeout}`,
|
|
||||||
{
|
|
||||||
method: 'GET',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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,
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import { getClashApiUrl } from '../../../helpers';
|
|
||||||
import { createBaseApiRequest, IBaseApiResponse } from '../../api';
|
|
||||||
|
|
||||||
export async function setProxy(
|
|
||||||
selector: string,
|
|
||||||
outbound: string,
|
|
||||||
): Promise<IBaseApiResponse<void>> {
|
|
||||||
return createBaseApiRequest<void>(() =>
|
|
||||||
fetch(`${getClashApiUrl()}/proxies/${selector}`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ name: outbound }),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { getConfigSections } from './getConfigSections';
|
import { getConfigSections } from './getConfigSections';
|
||||||
import { Podkop } from '../../types';
|
import { Podkop } from '../../types';
|
||||||
import { ClashMethods } from '../clash';
|
|
||||||
import { getProxyUrlName, splitProxyString } from '../../../helpers';
|
import { getProxyUrlName, splitProxyString } from '../../../helpers';
|
||||||
|
import { PodkopShellMethods } from '../shell';
|
||||||
|
|
||||||
interface IGetDashboardSectionsResponse {
|
interface IGetDashboardSectionsResponse {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
@@ -10,7 +10,7 @@ interface IGetDashboardSectionsResponse {
|
|||||||
|
|
||||||
export async function getDashboardSections(): Promise<IGetDashboardSectionsResponse> {
|
export async function getDashboardSections(): Promise<IGetDashboardSectionsResponse> {
|
||||||
const configSections = await getConfigSections();
|
const configSections = await getConfigSections();
|
||||||
const clashProxies = await ClashMethods.getProxies();
|
const clashProxies = await PodkopShellMethods.getClashApiProxies();
|
||||||
|
|
||||||
if (!clashProxies.success) {
|
if (!clashProxies.success) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
export * from './clash';
|
|
||||||
export * from './custom';
|
export * from './custom';
|
||||||
export * from './fakeip';
|
export * from './fakeip';
|
||||||
export * from './shell';
|
export * from './shell';
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ import { Podkop } from '../../types';
|
|||||||
|
|
||||||
export async function callBaseMethod<T>(
|
export async function callBaseMethod<T>(
|
||||||
method: Podkop.AvailableMethods,
|
method: Podkop.AvailableMethods,
|
||||||
|
args: string[] = [],
|
||||||
): Promise<Podkop.MethodResponse<T>> {
|
): Promise<Podkop.MethodResponse<T>> {
|
||||||
const response = await executeShellCommand({
|
const response = await executeShellCommand({
|
||||||
command: '/usr/bin/podkop',
|
command: '/usr/bin/podkop',
|
||||||
args: [method],
|
args: [method as string, ...args],
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { callBaseMethod } from './callBaseMethod';
|
import { callBaseMethod } from './callBaseMethod';
|
||||||
import { Podkop } from '../../types';
|
import { ClashAPI, Podkop } from '../../types';
|
||||||
|
|
||||||
export const PodkopShellMethods = {
|
export const PodkopShellMethods = {
|
||||||
checkDNSAvailable: async () =>
|
checkDNSAvailable: async () =>
|
||||||
@@ -24,4 +24,24 @@ export const PodkopShellMethods = {
|
|||||||
callBaseMethod<Podkop.GetSingBoxStatus>(
|
callBaseMethod<Podkop.GetSingBoxStatus>(
|
||||||
Podkop.AvailableMethods.GET_SING_BOX_STATUS,
|
Podkop.AvailableMethods.GET_SING_BOX_STATUS,
|
||||||
),
|
),
|
||||||
|
getClashApiProxies: async () =>
|
||||||
|
callBaseMethod<ClashAPI.Proxies>(Podkop.AvailableMethods.CLASH_API, [
|
||||||
|
Podkop.AvailableClashAPIMethods.GET_PROXIES,
|
||||||
|
]),
|
||||||
|
getClashApiProxyLatency: async (tag: string) =>
|
||||||
|
callBaseMethod<unknown>(Podkop.AvailableMethods.CLASH_API, [
|
||||||
|
Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY,
|
||||||
|
tag,
|
||||||
|
]),
|
||||||
|
getClashApiGroupLatency: async (tag: string) =>
|
||||||
|
callBaseMethod<unknown>(Podkop.AvailableMethods.CLASH_API, [
|
||||||
|
Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY,
|
||||||
|
tag,
|
||||||
|
]),
|
||||||
|
setClashApiGroupProxy: async (group: string, proxy: string) =>
|
||||||
|
callBaseMethod<unknown>(Podkop.AvailableMethods.CLASH_API, [
|
||||||
|
Podkop.AvailableClashAPIMethods.SET_GROUP_PROXY,
|
||||||
|
group,
|
||||||
|
proxy,
|
||||||
|
]),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,16 @@ class SocketManager {
|
|||||||
connect(url: string): void {
|
connect(url: string): void {
|
||||||
if (this.sockets.has(url)) return;
|
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.sockets.set(url, ws);
|
||||||
this.connected.set(url, false);
|
this.connected.set(url, false);
|
||||||
this.listeners.set(url, new Set());
|
this.listeners.set(url, new Set());
|
||||||
@@ -58,15 +67,21 @@ class SocketManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
subscribe(url: string, listener: Listener, onError?: ErrorListener): void {
|
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)) {
|
if (!this.sockets.has(url)) {
|
||||||
this.connect(url);
|
this.connect(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.listeners.get(url)?.add(listener);
|
if (!this.listeners.has(url)) {
|
||||||
|
this.listeners.set(url, new Set());
|
||||||
if (onError) {
|
|
||||||
this.errorListeners.get(url)?.add(onError);
|
|
||||||
}
|
}
|
||||||
|
this.listeners.get(url)?.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsubscribe(url: string, listener: Listener, onError?: ErrorListener): void {
|
unsubscribe(url: string, listener: Listener, onError?: ErrorListener): void {
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
getClashApiUrl,
|
|
||||||
getClashWsUrl,
|
getClashWsUrl,
|
||||||
onMount,
|
onMount,
|
||||||
preserveScrollForPage,
|
preserveScrollForPage,
|
||||||
} from '../../../helpers';
|
} from '../../../helpers';
|
||||||
import { prettyBytes } from '../../../helpers/prettyBytes';
|
import { prettyBytes } from '../../../helpers/prettyBytes';
|
||||||
import {
|
import { CustomPodkopMethods, PodkopShellMethods } from '../../methods';
|
||||||
ClashMethods,
|
|
||||||
CustomPodkopMethods,
|
|
||||||
PodkopShellMethods,
|
|
||||||
} from '../../methods';
|
|
||||||
import { socket, store, StoreType } from '../../services';
|
import { socket, store, StoreType } from '../../services';
|
||||||
import { renderSections, renderWidget } from './partials';
|
import { renderSections, renderWidget } from './partials';
|
||||||
|
|
||||||
@@ -28,7 +23,7 @@ async function fetchDashboardSections() {
|
|||||||
const { data, success } = await CustomPodkopMethods.getDashboardSections();
|
const { data, success } = await CustomPodkopMethods.getDashboardSections();
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
console.log('[fetchDashboardSections]: failed to fetch', getClashApiUrl());
|
console.log('[fetchDashboardSections]: failed to fetch');
|
||||||
}
|
}
|
||||||
|
|
||||||
store.set({
|
store.set({
|
||||||
@@ -148,7 +143,7 @@ async function connectToClashSockets() {
|
|||||||
// Handlers
|
// Handlers
|
||||||
|
|
||||||
async function handleChooseOutbound(selector: string, tag: string) {
|
async function handleChooseOutbound(selector: string, tag: string) {
|
||||||
await ClashMethods.setProxy(selector, tag);
|
await PodkopShellMethods.setClashApiGroupProxy(selector, tag);
|
||||||
await fetchDashboardSections();
|
await fetchDashboardSections();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +155,7 @@ async function handleTestGroupLatency(tag: string) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await ClashMethods.getGroupLatency(tag);
|
await PodkopShellMethods.getClashApiGroupLatency(tag);
|
||||||
await fetchDashboardSections();
|
await fetchDashboardSections();
|
||||||
|
|
||||||
store.set({
|
store.set({
|
||||||
@@ -179,7 +174,7 @@ async function handleTestProxyLatency(tag: string) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await ClashMethods.getProxyLatency(tag);
|
await PodkopShellMethods.getClashApiProxyLatency(tag);
|
||||||
await fetchDashboardSections();
|
await fetchDashboardSections();
|
||||||
|
|
||||||
store.set({
|
store.set({
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Podkop } from '../../../types';
|
import { Podkop } from '../../../types';
|
||||||
import { getClashApiUrl } from '../../../../helpers';
|
|
||||||
|
|
||||||
interface IRenderSectionsProps {
|
interface IRenderSectionsProps {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@@ -17,10 +16,7 @@ function renderFailedState() {
|
|||||||
class: 'pdk_dashboard-page__outbound-section centered',
|
class: 'pdk_dashboard-page__outbound-section centered',
|
||||||
style: 'height: 127px',
|
style: 'height: 127px',
|
||||||
},
|
},
|
||||||
E('span', {}, [
|
E('span', {}, [E('span', {}, _('Dashboard currently unavailable'))]),
|
||||||
E('span', {}, _('Dashboard currently unavailable')),
|
|
||||||
E('div', { style: 'text-align: center;' }, `API: ${getClashApiUrl()}`),
|
|
||||||
]),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,14 @@ export namespace Podkop {
|
|||||||
GET_STATUS = 'get_status',
|
GET_STATUS = 'get_status',
|
||||||
CHECK_SING_BOX = 'check_sing_box',
|
CHECK_SING_BOX = 'check_sing_box',
|
||||||
GET_SING_BOX_STATUS = 'get_sing_box_status',
|
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 {
|
export interface Outbound {
|
||||||
|
|||||||
@@ -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
|
// src/helpers/parseValueList.ts
|
||||||
function parseValueList(value) {
|
function parseValueList(value) {
|
||||||
return value.split(/\n/).map((line) => line.split("//")[0]).join(" ").split(/[,\s]+/).map((s) => s.trim()).filter(Boolean);
|
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
|
// src/podkop/methods/custom/getConfigSections.ts
|
||||||
async function getConfigSections() {
|
async function getConfigSections() {
|
||||||
return uci.load("podkop").then(() => uci.sections("podkop"));
|
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
|
// src/podkop/methods/custom/getDashboardSections.ts
|
||||||
async function getDashboardSections() {
|
async function getDashboardSections() {
|
||||||
const configSections = await getConfigSections();
|
const configSections = await getConfigSections();
|
||||||
const clashProxies = await ClashMethods.getProxies();
|
const clashProxies = await PodkopShellMethods.getClashApiProxies();
|
||||||
if (!clashProxies.success) {
|
if (!clashProxies.success) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
@@ -736,6 +723,35 @@ var COMMAND_SCHEDULING = {
|
|||||||
// Lowest priority
|
// 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
|
// src/podkop/methods/fakeip/getFakeIpCheck.ts
|
||||||
async function getFakeIpCheck() {
|
async function getFakeIpCheck() {
|
||||||
return createBaseApiRequest(
|
return createBaseApiRequest(
|
||||||
@@ -770,59 +786,6 @@ var RemoteFakeIPMethods = {
|
|||||||
getIpCheck
|
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
|
// src/podkop/services/tab.service.ts
|
||||||
var TabService = class _TabService {
|
var TabService = class _TabService {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -1142,7 +1105,14 @@ var SocketManager = class _SocketManager {
|
|||||||
}
|
}
|
||||||
connect(url) {
|
connect(url) {
|
||||||
if (this.sockets.has(url)) return;
|
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.sockets.set(url, ws);
|
||||||
this.connected.set(url, false);
|
this.connected.set(url, false);
|
||||||
this.listeners.set(url, /* @__PURE__ */ new Set());
|
this.listeners.set(url, /* @__PURE__ */ new Set());
|
||||||
@@ -1174,13 +1144,19 @@ var SocketManager = class _SocketManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
subscribe(url, listener, onError) {
|
subscribe(url, listener, onError) {
|
||||||
if (!this.sockets.has(url)) {
|
if (!this.errorListeners.has(url)) {
|
||||||
this.connect(url);
|
this.errorListeners.set(url, /* @__PURE__ */ new Set());
|
||||||
}
|
}
|
||||||
this.listeners.get(url)?.add(listener);
|
|
||||||
if (onError) {
|
if (onError) {
|
||||||
this.errorListeners.get(url)?.add(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) {
|
unsubscribe(url, listener, onError) {
|
||||||
this.listeners.get(url)?.delete(listener);
|
this.listeners.get(url)?.delete(listener);
|
||||||
@@ -1236,10 +1212,7 @@ function renderFailedState() {
|
|||||||
class: "pdk_dashboard-page__outbound-section centered",
|
class: "pdk_dashboard-page__outbound-section centered",
|
||||||
style: "height: 127px"
|
style: "height: 127px"
|
||||||
},
|
},
|
||||||
E("span", {}, [
|
E("span", {}, [E("span", {}, _("Dashboard currently unavailable"))])
|
||||||
E("span", {}, _("Dashboard currently unavailable")),
|
|
||||||
E("div", { style: "text-align: center;" }, `API: ${getClashApiUrl()}`)
|
|
||||||
])
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
function renderLoadingState() {
|
function renderLoadingState() {
|
||||||
@@ -1476,7 +1449,7 @@ async function fetchDashboardSections() {
|
|||||||
});
|
});
|
||||||
const { data, success } = await CustomPodkopMethods.getDashboardSections();
|
const { data, success } = await CustomPodkopMethods.getDashboardSections();
|
||||||
if (!success) {
|
if (!success) {
|
||||||
console.log("[fetchDashboardSections]: failed to fetch", getClashApiUrl());
|
console.log("[fetchDashboardSections]: failed to fetch");
|
||||||
}
|
}
|
||||||
store.set({
|
store.set({
|
||||||
sectionsWidget: {
|
sectionsWidget: {
|
||||||
@@ -1585,7 +1558,7 @@ async function connectToClashSockets() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
async function handleChooseOutbound(selector, tag) {
|
async function handleChooseOutbound(selector, tag) {
|
||||||
await ClashMethods.setProxy(selector, tag);
|
await PodkopShellMethods.setClashApiGroupProxy(selector, tag);
|
||||||
await fetchDashboardSections();
|
await fetchDashboardSections();
|
||||||
}
|
}
|
||||||
async function handleTestGroupLatency(tag) {
|
async function handleTestGroupLatency(tag) {
|
||||||
@@ -1595,7 +1568,7 @@ async function handleTestGroupLatency(tag) {
|
|||||||
latencyFetching: true
|
latencyFetching: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await ClashMethods.getGroupLatency(tag);
|
await PodkopShellMethods.getClashApiGroupLatency(tag);
|
||||||
await fetchDashboardSections();
|
await fetchDashboardSections();
|
||||||
store.set({
|
store.set({
|
||||||
sectionsWidget: {
|
sectionsWidget: {
|
||||||
@@ -1611,7 +1584,7 @@ async function handleTestProxyLatency(tag) {
|
|||||||
latencyFetching: true
|
latencyFetching: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await ClashMethods.getProxyLatency(tag);
|
await PodkopShellMethods.getClashApiProxyLatency(tag);
|
||||||
await fetchDashboardSections();
|
await fetchDashboardSections();
|
||||||
store.set({
|
store.set({
|
||||||
sectionsWidget: {
|
sectionsWidget: {
|
||||||
@@ -3141,10 +3114,6 @@ async function onMount(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// src/helpers/getClashApiUrl.ts
|
// src/helpers/getClashApiUrl.ts
|
||||||
function getClashApiUrl() {
|
|
||||||
const { hostname } = window.location;
|
|
||||||
return `http://${hostname}:9090`;
|
|
||||||
}
|
|
||||||
function getClashWsUrl() {
|
function getClashWsUrl() {
|
||||||
const { hostname } = window.location;
|
const { hostname } = window.location;
|
||||||
return `ws://${hostname}:9090`;
|
return `ws://${hostname}:9090`;
|
||||||
@@ -3193,7 +3162,6 @@ return baseclass.extend({
|
|||||||
CACHE_TIMEOUT,
|
CACHE_TIMEOUT,
|
||||||
COMMAND_SCHEDULING,
|
COMMAND_SCHEDULING,
|
||||||
COMMAND_TIMEOUT,
|
COMMAND_TIMEOUT,
|
||||||
ClashMethods,
|
|
||||||
CustomPodkopMethods,
|
CustomPodkopMethods,
|
||||||
DIAGNOSTICS_INITIAL_DELAY,
|
DIAGNOSTICS_INITIAL_DELAY,
|
||||||
DIAGNOSTICS_UPDATE_INTERVAL,
|
DIAGNOSTICS_UPDATE_INTERVAL,
|
||||||
@@ -3216,8 +3184,6 @@ return baseclass.extend({
|
|||||||
bulkValidate,
|
bulkValidate,
|
||||||
coreService,
|
coreService,
|
||||||
executeShellCommand,
|
executeShellCommand,
|
||||||
getBaseUrl,
|
|
||||||
getClashApiUrl,
|
|
||||||
getClashUIUrl,
|
getClashUIUrl,
|
||||||
getClashWsUrl,
|
getClashWsUrl,
|
||||||
getProxyUrlName,
|
getProxyUrlName,
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ function createSettingsContent(section) {
|
|||||||
form.Flag,
|
form.Flag,
|
||||||
'enable_yacd',
|
'enable_yacd',
|
||||||
_('Enable YACD'),
|
_('Enable YACD'),
|
||||||
`<a href="${main.getClashApiUrl()}/ui" target="_blank">${main.getClashApiUrl()}/ui</a>`,
|
`<a href="${main.getClashUIUrl()}" target="_blank">${main.getClashUIUrl()}</a>`,
|
||||||
);
|
);
|
||||||
o.default = '0';
|
o.default = '0';
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user