Release 3X-UI for Docker / build (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
112 lines
3.7 KiB
TypeScript
112 lines
3.7 KiB
TypeScript
import { keepPreviousData, useMutation, useQuery } from '@tanstack/react-query';
|
|
import { z } from 'zod';
|
|
|
|
import { keys } from '@/api/queryKeys';
|
|
import {
|
|
GeoCategoryPageSchema,
|
|
GeoEntryPageSchema,
|
|
GeoFileSchema,
|
|
GeodataTokenIssueSchema,
|
|
} from '@/generated/zod';
|
|
import type { GeoCategoryPage, GeoEntryPage, GeoFile, GeodataTokenIssue } from '@/generated/types';
|
|
import { HttpUtil } from '@/utils';
|
|
import { parseMsg } from '@/utils/zodValidate';
|
|
|
|
const GeoFileListSchema = z.array(GeoFileSchema);
|
|
const GeodataTokenIssueListSchema = z.array(GeodataTokenIssueSchema);
|
|
|
|
const EMPTY_CATEGORY_PAGE: GeoCategoryPage = { total: 0, items: [] };
|
|
const EMPTY_ENTRY_PAGE: GeoEntryPage = { total: 0, items: [] };
|
|
|
|
export type GeoTokenKind = 'ip' | 'domain';
|
|
|
|
export interface ValidateGeoTokensInput {
|
|
tokens: string[];
|
|
kind: GeoTokenKind;
|
|
}
|
|
|
|
async function fetchGeodataFiles(): Promise<GeoFile[]> {
|
|
const msg = await HttpUtil.get('/panel/api/xray/geodata/files', undefined, { silent: true });
|
|
if (!msg?.success) throw new Error(msg?.msg || 'Failed to fetch geodata files');
|
|
const validated = parseMsg(msg, GeoFileListSchema, 'xray/geodata/files');
|
|
return Array.isArray(validated.obj) ? validated.obj : [];
|
|
}
|
|
|
|
async function fetchGeodataCategories(file: string, query: string): Promise<GeoCategoryPage> {
|
|
const msg = await HttpUtil.get(
|
|
'/panel/api/xray/geodata/categories',
|
|
{ file, q: query },
|
|
{ silent: true },
|
|
);
|
|
if (!msg?.success) throw new Error(msg?.msg || 'Failed to fetch geodata categories');
|
|
const validated = parseMsg(msg, GeoCategoryPageSchema, 'xray/geodata/categories');
|
|
return validated.obj ?? EMPTY_CATEGORY_PAGE;
|
|
}
|
|
|
|
async function fetchGeodataEntries(
|
|
file: string,
|
|
code: string,
|
|
query: string,
|
|
offset: number,
|
|
limit: number,
|
|
): Promise<GeoEntryPage> {
|
|
const msg = await HttpUtil.get(
|
|
'/panel/api/xray/geodata/entries',
|
|
{ file, code, q: query, offset, limit },
|
|
{ silent: true },
|
|
);
|
|
if (!msg?.success) throw new Error(msg?.msg || 'Failed to fetch geodata entries');
|
|
const validated = parseMsg(msg, GeoEntryPageSchema, 'xray/geodata/entries');
|
|
return validated.obj ?? EMPTY_ENTRY_PAGE;
|
|
}
|
|
|
|
export function useGeodataFiles(enabled: boolean) {
|
|
return useQuery({
|
|
queryKey: keys.xray.geodata.files(),
|
|
queryFn: fetchGeodataFiles,
|
|
enabled,
|
|
staleTime: 5 * 60 * 1000,
|
|
});
|
|
}
|
|
|
|
export function useGeodataCategories(file: string | undefined, query: string, enabled: boolean) {
|
|
return useQuery({
|
|
queryKey: keys.xray.geodata.categories(file ?? '', query),
|
|
queryFn: () => fetchGeodataCategories(file ?? '', query),
|
|
enabled: enabled && !!file,
|
|
staleTime: 5 * 60 * 1000,
|
|
placeholderData: keepPreviousData,
|
|
});
|
|
}
|
|
|
|
export function useGeodataEntries(
|
|
file: string | undefined,
|
|
code: string | undefined,
|
|
query: string,
|
|
offset: number,
|
|
limit: number,
|
|
enabled: boolean,
|
|
) {
|
|
return useQuery({
|
|
queryKey: keys.xray.geodata.entries(file ?? '', code ?? '', query, offset, limit),
|
|
queryFn: () => fetchGeodataEntries(file ?? '', code ?? '', query, offset, limit),
|
|
enabled: enabled && !!file && !!code,
|
|
placeholderData: keepPreviousData,
|
|
});
|
|
}
|
|
|
|
export function useValidateGeoTokens() {
|
|
return useMutation<GeodataTokenIssue[], Error, ValidateGeoTokensInput>({
|
|
mutationFn: async ({ tokens, kind }) => {
|
|
const msg = await HttpUtil.post(
|
|
'/panel/api/xray/geodata/validate',
|
|
{ tokens: tokens.join(','), kind },
|
|
{ silent: true },
|
|
);
|
|
if (!msg?.success) throw new Error(msg?.msg || 'Failed to validate geodata tokens');
|
|
const validated = parseMsg(msg, GeodataTokenIssueListSchema, 'xray/geodata/validate');
|
|
return Array.isArray(validated.obj) ? validated.obj : [];
|
|
},
|
|
});
|
|
}
|