mirror of
https://github.com/itdoginfo/podkop.git
synced 2025-12-07 20:16:53 +03:00
feat: add test latency & select tag functionality
This commit is contained in:
@@ -4,3 +4,4 @@ export * from './getGroupDelay';
|
|||||||
export * from './getProxies';
|
export * from './getProxies';
|
||||||
export * from './getVersion';
|
export * from './getVersion';
|
||||||
export * from './triggerProxySelector';
|
export * from './triggerProxySelector';
|
||||||
|
export * from './triggerLatencyTest';
|
||||||
|
|||||||
35
fe-app-podkop/src/clash/methods/triggerLatencyTest.ts
Normal file
35
fe-app-podkop/src/clash/methods/triggerLatencyTest.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { IBaseApiResponse } from '../types';
|
||||||
|
import { createBaseApiRequest } from './createBaseApiRequest';
|
||||||
|
import { getClashApiUrl } from '../../helpers';
|
||||||
|
|
||||||
|
export async function triggerLatencyGroupTest(
|
||||||
|
tag: string,
|
||||||
|
timeout: number = 2000,
|
||||||
|
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' },
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function triggerLatencyProxyTest(
|
||||||
|
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' },
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -9,6 +9,11 @@ import { store } from '../store';
|
|||||||
import { socket } from '../socket';
|
import { socket } from '../socket';
|
||||||
import { renderDashboardWidget } from './renderer/renderWidget';
|
import { renderDashboardWidget } from './renderer/renderWidget';
|
||||||
import { prettyBytes } from '../helpers/prettyBytes';
|
import { prettyBytes } from '../helpers/prettyBytes';
|
||||||
|
import {
|
||||||
|
triggerLatencyGroupTest,
|
||||||
|
triggerLatencyProxyTest,
|
||||||
|
triggerProxySelector,
|
||||||
|
} from '../clash';
|
||||||
|
|
||||||
// Fetchers
|
// Fetchers
|
||||||
|
|
||||||
@@ -63,11 +68,40 @@ async function connectToClashSockets() {
|
|||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
|
|
||||||
|
async function handleChooseOutbound(selector: string, tag: string) {
|
||||||
|
await triggerProxySelector(selector, tag);
|
||||||
|
await fetchDashboardSections();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleTestGroupLatency(tag: string) {
|
||||||
|
await triggerLatencyGroupTest(tag);
|
||||||
|
await fetchDashboardSections();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleTestProxyLatency(tag: string) {
|
||||||
|
await triggerLatencyProxyTest(tag);
|
||||||
|
await fetchDashboardSections();
|
||||||
|
}
|
||||||
|
|
||||||
async function renderDashboardSections() {
|
async function renderDashboardSections() {
|
||||||
const sections = store.get().sections;
|
const sections = store.get().sections;
|
||||||
console.log('render dashboard sections group');
|
console.log('render dashboard sections group');
|
||||||
const container = document.getElementById('dashboard-sections-grid');
|
const container = document.getElementById('dashboard-sections-grid');
|
||||||
const renderedOutboundGroups = sections.map(renderOutboundGroup);
|
const renderedOutboundGroups = sections.map((section) =>
|
||||||
|
renderOutboundGroup({
|
||||||
|
section,
|
||||||
|
onTestLatency: (tag) => {
|
||||||
|
if (section.withTagSelect) {
|
||||||
|
return handleTestGroupLatency(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return handleTestProxyLatency(tag);
|
||||||
|
},
|
||||||
|
onChooseOutbound: (selector, tag) => {
|
||||||
|
handleChooseOutbound(selector, tag);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
container!.replaceChildren(...renderedOutboundGroups);
|
container!.replaceChildren(...renderedOutboundGroups);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,28 @@
|
|||||||
import { Podkop } from '../../podkop/types';
|
import { Podkop } from '../../podkop/types';
|
||||||
|
|
||||||
|
interface IRenderOutboundGroupProps {
|
||||||
|
section: Podkop.OutboundGroup;
|
||||||
|
onTestLatency: (tag: string) => void;
|
||||||
|
onChooseOutbound: (selector: string, tag: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
export function renderOutboundGroup({
|
export function renderOutboundGroup({
|
||||||
outbounds,
|
section,
|
||||||
displayName,
|
onTestLatency,
|
||||||
}: Podkop.OutboundGroup) {
|
onChooseOutbound,
|
||||||
|
}: IRenderOutboundGroupProps) {
|
||||||
|
function testLatency() {
|
||||||
|
if (section.withTagSelect) {
|
||||||
|
return onTestLatency(section.code);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section.outbounds.length) {
|
||||||
|
return onTestLatency(section.outbounds[0].code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function renderOutbound(outbound: Podkop.Outbound) {
|
function renderOutbound(outbound: Podkop.Outbound) {
|
||||||
function getLatencyClass() {
|
function getLatencyClass() {
|
||||||
|
|
||||||
if (!outbound.latency) {
|
if (!outbound.latency) {
|
||||||
return 'pdk_dashboard-page__outbound-grid__item__latency--empty';
|
return 'pdk_dashboard-page__outbound-grid__item__latency--empty';
|
||||||
}
|
}
|
||||||
@@ -25,7 +41,10 @@ export function renderOutboundGroup({
|
|||||||
return E(
|
return E(
|
||||||
'div',
|
'div',
|
||||||
{
|
{
|
||||||
class: `pdk_dashboard-page__outbound-grid__item ${outbound.selected ? 'pdk_dashboard-page__outbound-grid__item--active' : ''}`,
|
class: `pdk_dashboard-page__outbound-grid__item ${outbound.selected ? 'pdk_dashboard-page__outbound-grid__item--active' : ''} ${section.withTagSelect ? 'pdk_dashboard-page__outbound-grid__item--selectable' : ''}`,
|
||||||
|
click: () =>
|
||||||
|
section.withTagSelect &&
|
||||||
|
onChooseOutbound(section.code, outbound.code),
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
E('b', {}, outbound.displayName),
|
E('b', {}, outbound.displayName),
|
||||||
@@ -53,14 +72,14 @@ export function renderOutboundGroup({
|
|||||||
{
|
{
|
||||||
class: 'pdk_dashboard-page__outbound-section__title-section__title',
|
class: 'pdk_dashboard-page__outbound-section__title-section__title',
|
||||||
},
|
},
|
||||||
displayName,
|
section.displayName,
|
||||||
),
|
),
|
||||||
E('button', { class: 'btn' }, 'Test latency'),
|
E('button', { class: 'btn', click: () => testLatency() }, 'Test latency'),
|
||||||
]),
|
]),
|
||||||
E(
|
E(
|
||||||
'div',
|
'div',
|
||||||
{ class: 'pdk_dashboard-page__outbound-grid' },
|
{ class: 'pdk_dashboard-page__outbound-grid' },
|
||||||
outbounds.map((outbound) => renderOutbound(outbound)),
|
section.outbounds.map((outbound) => renderOutbound(outbound)),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ export async function getDashboardSections(): Promise<Podkop.OutboundGroup[]> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: section['.name'],
|
withTagSelect: false,
|
||||||
|
code: outbound?.code || section['.name'],
|
||||||
displayName: section['.name'],
|
displayName: section['.name'],
|
||||||
outbounds: [
|
outbounds: [
|
||||||
{
|
{
|
||||||
@@ -51,7 +52,8 @@ export async function getDashboardSections(): Promise<Podkop.OutboundGroup[]> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: section['.name'],
|
withTagSelect: false,
|
||||||
|
code: outbound?.code || section['.name'],
|
||||||
displayName: section['.name'],
|
displayName: section['.name'],
|
||||||
outbounds: [
|
outbounds: [
|
||||||
{
|
{
|
||||||
@@ -90,7 +92,8 @@ export async function getDashboardSections(): Promise<Podkop.OutboundGroup[]> {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: section['.name'],
|
withTagSelect: true,
|
||||||
|
code: selector?.code || section['.name'],
|
||||||
displayName: section['.name'],
|
displayName: section['.name'],
|
||||||
outbounds: [
|
outbounds: [
|
||||||
{
|
{
|
||||||
@@ -112,7 +115,8 @@ export async function getDashboardSections(): Promise<Podkop.OutboundGroup[]> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: section['.name'],
|
withTagSelect: false,
|
||||||
|
code: outbound?.code || section['.name'],
|
||||||
displayName: section['.name'],
|
displayName: section['.name'],
|
||||||
outbounds: [
|
outbounds: [
|
||||||
{
|
{
|
||||||
@@ -127,6 +131,7 @@ export async function getDashboardSections(): Promise<Podkop.OutboundGroup[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
withTagSelect: false,
|
||||||
code: section['.name'],
|
code: section['.name'],
|
||||||
displayName: section['.name'],
|
displayName: section['.name'],
|
||||||
outbounds: [],
|
outbounds: [],
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export namespace Podkop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface OutboundGroup {
|
export interface OutboundGroup {
|
||||||
|
withTagSelect: boolean;
|
||||||
code: string;
|
code: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
outbounds: Outbound[];
|
outbounds: Outbound[];
|
||||||
|
|||||||
@@ -122,13 +122,17 @@ export const GlobalStyles = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pdk_dashboard-page__outbound-grid__item {
|
.pdk_dashboard-page__outbound-grid__item {
|
||||||
cursor: pointer;
|
|
||||||
border: 2px var(--background-color-low) solid;
|
border: 2px var(--background-color-low) solid;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
transition: border 0.2s ease;
|
transition: border 0.2s ease;
|
||||||
}
|
}
|
||||||
.pdk_dashboard-page__outbound-grid__item:hover {
|
|
||||||
|
.pdk_dashboard-page__outbound-grid__item--selectable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_dashboard-page__outbound-grid__item--selectable:hover {
|
||||||
border-color: var(--primary-color-high);
|
border-color: var(--primary-color-high);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -470,13 +470,17 @@ var GlobalStyles = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pdk_dashboard-page__outbound-grid__item {
|
.pdk_dashboard-page__outbound-grid__item {
|
||||||
cursor: pointer;
|
|
||||||
border: 2px var(--background-color-low) solid;
|
border: 2px var(--background-color-low) solid;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
transition: border 0.2s ease;
|
transition: border 0.2s ease;
|
||||||
}
|
}
|
||||||
.pdk_dashboard-page__outbound-grid__item:hover {
|
|
||||||
|
.pdk_dashboard-page__outbound-grid__item--selectable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_dashboard-page__outbound-grid__item--selectable:hover {
|
||||||
border-color: var(--primary-color-high);
|
border-color: var(--primary-color-high);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -855,6 +859,30 @@ async function triggerProxySelector(selector, outbound) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// src/clash/methods/triggerLatencyTest.ts
|
||||||
|
async function triggerLatencyGroupTest(tag, timeout = 2e3, 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" }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
async function triggerLatencyProxyTest(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/dashboard/renderDashboard.ts
|
// src/dashboard/renderDashboard.ts
|
||||||
function renderDashboard() {
|
function renderDashboard() {
|
||||||
return E(
|
return E(
|
||||||
@@ -958,7 +986,8 @@ async function getDashboardSections() {
|
|||||||
(proxy) => proxy.code === `${section[".name"]}-out`
|
(proxy) => proxy.code === `${section[".name"]}-out`
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
code: section[".name"],
|
withTagSelect: false,
|
||||||
|
code: outbound?.code || section[".name"],
|
||||||
displayName: section[".name"],
|
displayName: section[".name"],
|
||||||
outbounds: [
|
outbounds: [
|
||||||
{
|
{
|
||||||
@@ -976,7 +1005,8 @@ async function getDashboardSections() {
|
|||||||
(proxy) => proxy.code === `${section[".name"]}-out`
|
(proxy) => proxy.code === `${section[".name"]}-out`
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
code: section[".name"],
|
withTagSelect: false,
|
||||||
|
code: outbound?.code || section[".name"],
|
||||||
displayName: section[".name"],
|
displayName: section[".name"],
|
||||||
outbounds: [
|
outbounds: [
|
||||||
{
|
{
|
||||||
@@ -1004,7 +1034,8 @@ async function getDashboardSections() {
|
|||||||
selected: selector?.value?.now === item?.code
|
selected: selector?.value?.now === item?.code
|
||||||
}));
|
}));
|
||||||
return {
|
return {
|
||||||
code: section[".name"],
|
withTagSelect: true,
|
||||||
|
code: selector?.code || section[".name"],
|
||||||
displayName: section[".name"],
|
displayName: section[".name"],
|
||||||
outbounds: [
|
outbounds: [
|
||||||
{
|
{
|
||||||
@@ -1024,7 +1055,8 @@ async function getDashboardSections() {
|
|||||||
(proxy) => proxy.code === `${section[".name"]}-out`
|
(proxy) => proxy.code === `${section[".name"]}-out`
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
code: section[".name"],
|
withTagSelect: false,
|
||||||
|
code: outbound?.code || section[".name"],
|
||||||
displayName: section[".name"],
|
displayName: section[".name"],
|
||||||
outbounds: [
|
outbounds: [
|
||||||
{
|
{
|
||||||
@@ -1038,6 +1070,7 @@ async function getDashboardSections() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
withTagSelect: false,
|
||||||
code: section[".name"],
|
code: section[".name"],
|
||||||
displayName: section[".name"],
|
displayName: section[".name"],
|
||||||
outbounds: []
|
outbounds: []
|
||||||
@@ -1073,9 +1106,18 @@ async function getSingboxStatus() {
|
|||||||
|
|
||||||
// src/dashboard/renderer/renderOutboundGroup.ts
|
// src/dashboard/renderer/renderOutboundGroup.ts
|
||||||
function renderOutboundGroup({
|
function renderOutboundGroup({
|
||||||
outbounds,
|
section,
|
||||||
displayName
|
onTestLatency,
|
||||||
|
onChooseOutbound
|
||||||
}) {
|
}) {
|
||||||
|
function testLatency() {
|
||||||
|
if (section.withTagSelect) {
|
||||||
|
return onTestLatency(section.code);
|
||||||
|
}
|
||||||
|
if (section.outbounds.length) {
|
||||||
|
return onTestLatency(section.outbounds[0].code);
|
||||||
|
}
|
||||||
|
}
|
||||||
function renderOutbound(outbound) {
|
function renderOutbound(outbound) {
|
||||||
function getLatencyClass() {
|
function getLatencyClass() {
|
||||||
if (!outbound.latency) {
|
if (!outbound.latency) {
|
||||||
@@ -1092,7 +1134,8 @@ function renderOutboundGroup({
|
|||||||
return E(
|
return E(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
class: `pdk_dashboard-page__outbound-grid__item ${outbound.selected ? "pdk_dashboard-page__outbound-grid__item--active" : ""}`
|
class: `pdk_dashboard-page__outbound-grid__item ${outbound.selected ? "pdk_dashboard-page__outbound-grid__item--active" : ""} ${section.withTagSelect ? "pdk_dashboard-page__outbound-grid__item--selectable" : ""}`,
|
||||||
|
click: () => section.withTagSelect && onChooseOutbound(section.code, outbound.code)
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
E("b", {}, outbound.displayName),
|
E("b", {}, outbound.displayName),
|
||||||
@@ -1119,14 +1162,14 @@ function renderOutboundGroup({
|
|||||||
{
|
{
|
||||||
class: "pdk_dashboard-page__outbound-section__title-section__title"
|
class: "pdk_dashboard-page__outbound-section__title-section__title"
|
||||||
},
|
},
|
||||||
displayName
|
section.displayName
|
||||||
),
|
),
|
||||||
E("button", { class: "btn" }, "Test latency")
|
E("button", { class: "btn", click: () => testLatency() }, "Test latency")
|
||||||
]),
|
]),
|
||||||
E(
|
E(
|
||||||
"div",
|
"div",
|
||||||
{ class: "pdk_dashboard-page__outbound-grid" },
|
{ class: "pdk_dashboard-page__outbound-grid" },
|
||||||
outbounds.map((outbound) => renderOutbound(outbound))
|
section.outbounds.map((outbound) => renderOutbound(outbound))
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -1343,11 +1386,36 @@ async function connectToClashSockets() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
async function handleChooseOutbound(selector, tag) {
|
||||||
|
await triggerProxySelector(selector, tag);
|
||||||
|
await fetchDashboardSections();
|
||||||
|
}
|
||||||
|
async function handleTestGroupLatency(tag) {
|
||||||
|
await triggerLatencyGroupTest(tag);
|
||||||
|
await fetchDashboardSections();
|
||||||
|
}
|
||||||
|
async function handleTestProxyLatency(tag) {
|
||||||
|
await triggerLatencyProxyTest(tag);
|
||||||
|
await fetchDashboardSections();
|
||||||
|
}
|
||||||
async function renderDashboardSections() {
|
async function renderDashboardSections() {
|
||||||
const sections = store.get().sections;
|
const sections = store.get().sections;
|
||||||
console.log("render dashboard sections group");
|
console.log("render dashboard sections group");
|
||||||
const container = document.getElementById("dashboard-sections-grid");
|
const container = document.getElementById("dashboard-sections-grid");
|
||||||
const renderedOutboundGroups = sections.map(renderOutboundGroup);
|
const renderedOutboundGroups = sections.map(
|
||||||
|
(section) => renderOutboundGroup({
|
||||||
|
section,
|
||||||
|
onTestLatency: (tag) => {
|
||||||
|
if (section.withTagSelect) {
|
||||||
|
return handleTestGroupLatency(tag);
|
||||||
|
}
|
||||||
|
return handleTestProxyLatency(tag);
|
||||||
|
},
|
||||||
|
onChooseOutbound: (selector, tag) => {
|
||||||
|
handleChooseOutbound(selector, tag);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
container.replaceChildren(...renderedOutboundGroups);
|
container.replaceChildren(...renderedOutboundGroups);
|
||||||
}
|
}
|
||||||
async function renderTrafficWidget() {
|
async function renderTrafficWidget() {
|
||||||
@@ -1480,6 +1548,8 @@ return baseclass.extend({
|
|||||||
onMount,
|
onMount,
|
||||||
parseValueList,
|
parseValueList,
|
||||||
renderDashboard,
|
renderDashboard,
|
||||||
|
triggerLatencyGroupTest,
|
||||||
|
triggerLatencyProxyTest,
|
||||||
triggerProxySelector,
|
triggerProxySelector,
|
||||||
validateDNS,
|
validateDNS,
|
||||||
validateDomain,
|
validateDomain,
|
||||||
|
|||||||
Reference in New Issue
Block a user