Files
hy2-panel/app/admin/nodes/actions.ts
T

139 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use server";
import {
CustomProxyValidationError,
parseCustomProxyYaml,
} from "@/lib/custom-proxy";
import { revalidatePath } from "next/cache";
import { ensureDb } from "@/lib/db";
import { requireAdminAccess } from "@/lib/session";
import {
createNode,
deleteNode,
normalizeNodeType,
updateNode,
} from "@/lib/store";
function boolFromForm(value: FormDataEntryValue | null) {
return value === "on";
}
function validateCustomYaml(nodeType: string, formData: FormData) {
if (nodeType !== "custom") return;
try {
parseCustomProxyYaml(String(formData.get("custom_config_yaml") ?? ""));
} catch (error) {
if (error instanceof CustomProxyValidationError)
return { error: error.message };
throw error;
}
}
export async function createNodeAction(formData: FormData) {
await requireAdminAccess();
const nodeType = normalizeNodeType(
String(formData.get("node_type") ?? "hy2"),
);
const validation = validateCustomYaml(nodeType, formData);
if (validation) return validation;
const name = String(formData.get("name") ?? "").trim();
const clientName = String(formData.get("client_name") ?? "").trim();
await createNode({
nodeType,
slug: String(formData.get("slug") ?? "").trim(),
name,
authToken: String(formData.get("auth_token") ?? "").trim() || null,
hy2Listen: String(formData.get("hy2_listen") ?? "").trim() || "",
serverHost: String(formData.get("server_host") ?? "").trim(),
serverPort: Number(formData.get("server_port") ?? 443),
clientName: clientName || (nodeType === "hy2" ? name : ""),
bandwidthUpMbps: Number(formData.get("bandwidth_up_mbps") ?? 30),
bandwidthDownMbps: Number(formData.get("bandwidth_down_mbps") ?? 30),
skipCertVerify: boolFromForm(formData.get("skip_cert_verify")),
sni: String(formData.get("sni") ?? "").trim() || null,
customConfigYaml: String(formData.get("custom_config_yaml") ?? ""),
trafficStatsUrl: String(formData.get("traffic_stats_url") ?? "").trim(),
trafficStatsListen:
String(formData.get("traffic_stats_listen") ?? "").trim() || ":9999",
trafficStatsSecret: String(
formData.get("traffic_stats_secret") ?? "",
).trim(),
enabled: boolFromForm(formData.get("enabled")),
pollIntervalSeconds: Number(formData.get("poll_interval_seconds") ?? 15),
});
revalidatePath("/admin/nodes");
revalidatePath("/admin/subscriptions");
revalidatePath("/admin/dashboard");
}
export async function updateNodeAction(formData: FormData) {
await requireAdminAccess();
const nodeType = normalizeNodeType(
String(formData.get("node_type") ?? "hy2"),
);
const validation = validateCustomYaml(nodeType, formData);
if (validation) return validation;
const name = String(formData.get("name") ?? "").trim();
const clientName = String(formData.get("client_name") ?? "").trim();
await updateNode({
id: Number(formData.get("id")),
nodeType,
slug: String(formData.get("slug") ?? "").trim(),
name,
authToken: String(formData.get("auth_token") ?? "").trim(),
hy2Listen: String(formData.get("hy2_listen") ?? "").trim() || "",
serverHost: String(formData.get("server_host") ?? "").trim(),
serverPort: Number(formData.get("server_port") ?? 443),
clientName: clientName || (nodeType === "hy2" ? name : ""),
bandwidthUpMbps: Number(formData.get("bandwidth_up_mbps") ?? 30),
bandwidthDownMbps: Number(formData.get("bandwidth_down_mbps") ?? 30),
skipCertVerify: boolFromForm(formData.get("skip_cert_verify")),
sni: String(formData.get("sni") ?? "").trim() || null,
customConfigYaml: String(formData.get("custom_config_yaml") ?? ""),
trafficStatsUrl: String(formData.get("traffic_stats_url") ?? "").trim(),
trafficStatsListen:
String(formData.get("traffic_stats_listen") ?? "").trim() || ":9999",
trafficStatsSecret: String(
formData.get("traffic_stats_secret") ?? "",
).trim(),
enabled: boolFromForm(formData.get("enabled")),
pollIntervalSeconds: Number(formData.get("poll_interval_seconds") ?? 15),
});
revalidatePath("/admin/nodes");
revalidatePath("/admin/subscriptions");
revalidatePath("/admin/dashboard");
}
export async function deleteNodeAction(formData: FormData) {
await requireAdminAccess();
await deleteNode(Number(formData.get("id")));
revalidatePath("/admin/nodes");
revalidatePath("/admin/subscriptions");
revalidatePath("/admin/dashboard");
}
export async function updateAnyTLSNodeAction(data: FormData) {
await requireAdminAccess();
const name = String(data.get("name") || "").trim();
if (!name || name.length > 100)
return { error: "请填写 1–100 字的节点名称。" };
const db = await ensureDb();
db.prepare(
"UPDATE hy2_nodes SET name=?,client_name=?,enabled=?,updated_at=? WHERE id=? AND node_type='anytls'",
).run(
name,
name,
data.get("enabled") === "on" ? 1 : 0,
new Date().toISOString(),
Number(data.get("id")),
);
revalidatePath("/admin/nodes");
revalidatePath("/admin/subscriptions");
revalidatePath("/admin/dashboard");
}