mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-07 16:16:37 +08:00
迁移配置表
This commit is contained in:
@@ -1,47 +1,47 @@
|
||||
import type {OptionItem} from "@/lib/services/openflare"
|
||||
|
||||
export type OpenFlareOpsFields = {
|
||||
AgentHeartbeatInterval: string
|
||||
AgentWebsocketUpgradeEnabled: boolean
|
||||
NodeOfflineThreshold: string
|
||||
AgentUpdateRepo: string
|
||||
GeoIPProvider: string
|
||||
ServerAddress: string
|
||||
UptimeKumaEnabled: boolean
|
||||
UptimeKumaUrl: string
|
||||
UptimeKumaUsername: string
|
||||
UptimeKumaPassword: string
|
||||
UptimeKumaMonitorScope: string
|
||||
UptimeKumaSelectedSites: string
|
||||
UptimeKumaSyncInterval: string
|
||||
UptimeKumaInterval: string
|
||||
UptimeKumaRetry: string
|
||||
UptimeKumaRetryInterval: string
|
||||
UptimeKumaTimeout: string
|
||||
DatabaseAutoCleanupEnabled: boolean
|
||||
DatabaseAutoCleanupRetentionDays: string
|
||||
agent_heartbeat_interval: string
|
||||
agent_websocket_upgrade_enabled: boolean
|
||||
node_offline_threshold: string
|
||||
agent_update_repo: string
|
||||
geoip_provider: string
|
||||
server_address: string
|
||||
uptime_kuma_enabled: boolean
|
||||
uptime_kuma_url: string
|
||||
uptime_kuma_username: string
|
||||
uptime_kuma_password: string
|
||||
uptime_kuma_monitor_scope: string
|
||||
uptime_kuma_selected_sites: string
|
||||
uptime_kuma_sync_interval: string
|
||||
uptime_kuma_interval: string
|
||||
uptime_kuma_retry: string
|
||||
uptime_kuma_retry_interval: string
|
||||
uptime_kuma_timeout: string
|
||||
database_auto_cleanup_enabled: boolean
|
||||
database_auto_cleanup_retention_days: string
|
||||
}
|
||||
|
||||
export const defaultOpenFlareOpsFields: OpenFlareOpsFields = {
|
||||
AgentHeartbeatInterval: "10000",
|
||||
AgentWebsocketUpgradeEnabled: true,
|
||||
NodeOfflineThreshold: "120000",
|
||||
AgentUpdateRepo: "Rain-kl/OpenFlare",
|
||||
GeoIPProvider: "ipinfo",
|
||||
ServerAddress: "",
|
||||
UptimeKumaEnabled: false,
|
||||
UptimeKumaUrl: "",
|
||||
UptimeKumaUsername: "",
|
||||
UptimeKumaPassword: "",
|
||||
UptimeKumaMonitorScope: "all",
|
||||
UptimeKumaSelectedSites: "",
|
||||
UptimeKumaSyncInterval: "5",
|
||||
UptimeKumaInterval: "60",
|
||||
UptimeKumaRetry: "0",
|
||||
UptimeKumaRetryInterval: "60",
|
||||
UptimeKumaTimeout: "48",
|
||||
DatabaseAutoCleanupEnabled: false,
|
||||
DatabaseAutoCleanupRetentionDays: "30",
|
||||
agent_heartbeat_interval: "10000",
|
||||
agent_websocket_upgrade_enabled: true,
|
||||
node_offline_threshold: "120000",
|
||||
agent_update_repo: "Rain-kl/OpenFlare",
|
||||
geoip_provider: "ipinfo",
|
||||
server_address: "",
|
||||
uptime_kuma_enabled: false,
|
||||
uptime_kuma_url: "",
|
||||
uptime_kuma_username: "",
|
||||
uptime_kuma_password: "",
|
||||
uptime_kuma_monitor_scope: "all",
|
||||
uptime_kuma_selected_sites: "",
|
||||
uptime_kuma_sync_interval: "5",
|
||||
uptime_kuma_interval: "60",
|
||||
uptime_kuma_retry: "0",
|
||||
uptime_kuma_retry_interval: "60",
|
||||
uptime_kuma_timeout: "48",
|
||||
database_auto_cleanup_enabled: false,
|
||||
database_auto_cleanup_retention_days: "30",
|
||||
}
|
||||
|
||||
export const INSTALLER_SCRIPT_URL =
|
||||
@@ -64,25 +64,25 @@ export function mapOptionsToOpsFields(
|
||||
serverAddress = "",
|
||||
): OpenFlareOpsFields {
|
||||
return {
|
||||
AgentHeartbeatInterval: optionMap.AgentHeartbeatInterval ?? "10000",
|
||||
AgentWebsocketUpgradeEnabled: toBoolean(optionMap.AgentWebsocketUpgradeEnabled, true),
|
||||
NodeOfflineThreshold: optionMap.NodeOfflineThreshold ?? "120000",
|
||||
AgentUpdateRepo: optionMap.AgentUpdateRepo ?? "Rain-kl/OpenFlare",
|
||||
GeoIPProvider: optionMap.GeoIPProvider ?? "ipinfo",
|
||||
ServerAddress: optionMap.ServerAddress || serverAddress,
|
||||
UptimeKumaEnabled: toBoolean(optionMap.UptimeKumaEnabled, false),
|
||||
UptimeKumaUrl: optionMap.UptimeKumaUrl ?? "",
|
||||
UptimeKumaUsername: optionMap.UptimeKumaUsername ?? "",
|
||||
UptimeKumaPassword: "",
|
||||
UptimeKumaMonitorScope: optionMap.UptimeKumaMonitorScope ?? "all",
|
||||
UptimeKumaSelectedSites: optionMap.UptimeKumaSelectedSites ?? "",
|
||||
UptimeKumaSyncInterval: optionMap.UptimeKumaSyncInterval ?? "5",
|
||||
UptimeKumaInterval: optionMap.UptimeKumaInterval ?? "60",
|
||||
UptimeKumaRetry: optionMap.UptimeKumaRetry ?? "0",
|
||||
UptimeKumaRetryInterval: optionMap.UptimeKumaRetryInterval ?? "60",
|
||||
UptimeKumaTimeout: optionMap.UptimeKumaTimeout ?? "48",
|
||||
DatabaseAutoCleanupEnabled: toBoolean(optionMap.DatabaseAutoCleanupEnabled, false),
|
||||
DatabaseAutoCleanupRetentionDays: optionMap.DatabaseAutoCleanupRetentionDays ?? "30",
|
||||
agent_heartbeat_interval: optionMap.agent_heartbeat_interval ?? "10000",
|
||||
agent_websocket_upgrade_enabled: toBoolean(optionMap.agent_websocket_upgrade_enabled, true),
|
||||
node_offline_threshold: optionMap.node_offline_threshold ?? "120000",
|
||||
agent_update_repo: optionMap.agent_update_repo ?? "Rain-kl/OpenFlare",
|
||||
geoip_provider: optionMap.geoip_provider ?? "ipinfo",
|
||||
server_address: optionMap.server_address || serverAddress,
|
||||
uptime_kuma_enabled: toBoolean(optionMap.uptime_kuma_enabled, false),
|
||||
uptime_kuma_url: optionMap.uptime_kuma_url ?? "",
|
||||
uptime_kuma_username: optionMap.uptime_kuma_username ?? "",
|
||||
uptime_kuma_password: "",
|
||||
uptime_kuma_monitor_scope: optionMap.uptime_kuma_monitor_scope ?? "all",
|
||||
uptime_kuma_selected_sites: optionMap.uptime_kuma_selected_sites ?? "",
|
||||
uptime_kuma_sync_interval: optionMap.uptime_kuma_sync_interval ?? "5",
|
||||
uptime_kuma_interval: optionMap.uptime_kuma_interval ?? "60",
|
||||
uptime_kuma_retry: optionMap.uptime_kuma_retry ?? "0",
|
||||
uptime_kuma_retry_interval: optionMap.uptime_kuma_retry_interval ?? "60",
|
||||
uptime_kuma_timeout: optionMap.uptime_kuma_timeout ?? "48",
|
||||
database_auto_cleanup_enabled: toBoolean(optionMap.database_auto_cleanup_enabled, false),
|
||||
database_auto_cleanup_retention_days: optionMap.database_auto_cleanup_retention_days ?? "30",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,8 +111,8 @@ export function buildDiscoveryCommand(serverUrl: string, discoveryToken: string)
|
||||
}
|
||||
|
||||
export function validateAgentFields(fields: OpenFlareOpsFields) {
|
||||
const heartbeat = Number.parseInt(fields.AgentHeartbeatInterval, 10)
|
||||
const offline = Number.parseInt(fields.NodeOfflineThreshold, 10)
|
||||
const heartbeat = Number.parseInt(fields.agent_heartbeat_interval, 10)
|
||||
const offline = Number.parseInt(fields.node_offline_threshold, 10)
|
||||
if (Number.isNaN(heartbeat) || heartbeat < 5000) {
|
||||
throw new Error("心跳间隔不能小于 5000 毫秒。")
|
||||
}
|
||||
@@ -122,15 +122,15 @@ export function validateAgentFields(fields: OpenFlareOpsFields) {
|
||||
}
|
||||
|
||||
export function validateUptimeKumaFields(fields: OpenFlareOpsFields) {
|
||||
const syncInt = Number.parseInt(fields.UptimeKumaSyncInterval, 10)
|
||||
const interval = Number.parseInt(fields.UptimeKumaInterval, 10)
|
||||
const retry = Number.parseInt(fields.UptimeKumaRetry, 10)
|
||||
const retryInt = Number.parseInt(fields.UptimeKumaRetryInterval, 10)
|
||||
const timeout = Number.parseInt(fields.UptimeKumaTimeout, 10)
|
||||
const syncInt = Number.parseInt(fields.uptime_kuma_sync_interval, 10)
|
||||
const interval = Number.parseInt(fields.uptime_kuma_interval, 10)
|
||||
const retry = Number.parseInt(fields.uptime_kuma_retry, 10)
|
||||
const retryInt = Number.parseInt(fields.uptime_kuma_retry_interval, 10)
|
||||
const timeout = Number.parseInt(fields.uptime_kuma_timeout, 10)
|
||||
|
||||
if (fields.UptimeKumaEnabled) {
|
||||
if (!fields.UptimeKumaUrl.trim()) throw new Error("请输入 Uptime Kuma 地址。")
|
||||
if (!fields.UptimeKumaUsername.trim()) throw new Error("请输入 Uptime Kuma 用户名。")
|
||||
if (fields.uptime_kuma_enabled) {
|
||||
if (!fields.uptime_kuma_url.trim()) throw new Error("请输入 Uptime Kuma 地址。")
|
||||
if (!fields.uptime_kuma_username.trim()) throw new Error("请输入 Uptime Kuma 用户名。")
|
||||
}
|
||||
if (Number.isNaN(syncInt) || syncInt <= 0) throw new Error("同步间隔必须为正整数。")
|
||||
if (Number.isNaN(interval) || interval <= 0) throw new Error("心跳间隔必须为正整数。")
|
||||
@@ -140,7 +140,7 @@ export function validateUptimeKumaFields(fields: OpenFlareOpsFields) {
|
||||
}
|
||||
|
||||
export function validateDatabaseAutoCleanup(fields: OpenFlareOpsFields) {
|
||||
const retentionDays = Number.parseInt(fields.DatabaseAutoCleanupRetentionDays, 10)
|
||||
const retentionDays = Number.parseInt(fields.database_auto_cleanup_retention_days, 10)
|
||||
if (Number.isNaN(retentionDays) || retentionDays < 1) {
|
||||
throw new Error("自动清理保留天数至少为 1 天。")
|
||||
}
|
||||
@@ -149,35 +149,35 @@ export function validateDatabaseAutoCleanup(fields: OpenFlareOpsFields) {
|
||||
export function agentOptionEntries(fields: OpenFlareOpsFields): OptionItem[] {
|
||||
validateAgentFields(fields)
|
||||
return [
|
||||
{ key: "AgentHeartbeatInterval", value: fields.AgentHeartbeatInterval },
|
||||
{ key: "AgentWebsocketUpgradeEnabled", value: String(fields.AgentWebsocketUpgradeEnabled) },
|
||||
{ key: "NodeOfflineThreshold", value: fields.NodeOfflineThreshold },
|
||||
{ key: "AgentUpdateRepo", value: fields.AgentUpdateRepo.trim() },
|
||||
{ key: "GeoIPProvider", value: fields.GeoIPProvider },
|
||||
{ key: "agent_heartbeat_interval", value: fields.agent_heartbeat_interval },
|
||||
{ key: "agent_websocket_upgrade_enabled", value: String(fields.agent_websocket_upgrade_enabled) },
|
||||
{ key: "node_offline_threshold", value: fields.node_offline_threshold },
|
||||
{ key: "agent_update_repo", value: fields.agent_update_repo.trim() },
|
||||
{ key: "geoip_provider", value: fields.geoip_provider },
|
||||
]
|
||||
}
|
||||
|
||||
export function uptimeKumaOptionEntries(fields: OpenFlareOpsFields): OptionItem[] {
|
||||
validateUptimeKumaFields(fields)
|
||||
return [
|
||||
{ key: "UptimeKumaEnabled", value: String(fields.UptimeKumaEnabled) },
|
||||
{ key: "UptimeKumaUrl", value: fields.UptimeKumaUrl.trim() },
|
||||
{ key: "UptimeKumaUsername", value: fields.UptimeKumaUsername.trim() },
|
||||
{ key: "UptimeKumaPassword", value: fields.UptimeKumaPassword },
|
||||
{ key: "UptimeKumaMonitorScope", value: fields.UptimeKumaMonitorScope },
|
||||
{ key: "UptimeKumaSelectedSites", value: fields.UptimeKumaSelectedSites },
|
||||
{ key: "UptimeKumaSyncInterval", value: fields.UptimeKumaSyncInterval },
|
||||
{ key: "UptimeKumaInterval", value: fields.UptimeKumaInterval },
|
||||
{ key: "UptimeKumaRetry", value: fields.UptimeKumaRetry },
|
||||
{ key: "UptimeKumaRetryInterval", value: fields.UptimeKumaRetryInterval },
|
||||
{ key: "UptimeKumaTimeout", value: fields.UptimeKumaTimeout },
|
||||
{ key: "uptime_kuma_enabled", value: String(fields.uptime_kuma_enabled) },
|
||||
{ key: "uptime_kuma_url", value: fields.uptime_kuma_url.trim() },
|
||||
{ key: "uptime_kuma_username", value: fields.uptime_kuma_username.trim() },
|
||||
{ key: "uptime_kuma_password", value: fields.uptime_kuma_password },
|
||||
{ key: "uptime_kuma_monitor_scope", value: fields.uptime_kuma_monitor_scope },
|
||||
{ key: "uptime_kuma_selected_sites", value: fields.uptime_kuma_selected_sites },
|
||||
{ key: "uptime_kuma_sync_interval", value: fields.uptime_kuma_sync_interval },
|
||||
{ key: "uptime_kuma_interval", value: fields.uptime_kuma_interval },
|
||||
{ key: "uptime_kuma_retry", value: fields.uptime_kuma_retry },
|
||||
{ key: "uptime_kuma_retry_interval", value: fields.uptime_kuma_retry_interval },
|
||||
{ key: "uptime_kuma_timeout", value: fields.uptime_kuma_timeout },
|
||||
]
|
||||
}
|
||||
|
||||
export function databaseAutoCleanupEntries(fields: OpenFlareOpsFields): OptionItem[] {
|
||||
validateDatabaseAutoCleanup(fields)
|
||||
return [
|
||||
{ key: "DatabaseAutoCleanupEnabled", value: String(fields.DatabaseAutoCleanupEnabled) },
|
||||
{ key: "DatabaseAutoCleanupRetentionDays", value: fields.DatabaseAutoCleanupRetentionDays },
|
||||
{ key: "database_auto_cleanup_enabled", value: String(fields.database_auto_cleanup_enabled) },
|
||||
{ key: "database_auto_cleanup_retention_days", value: fields.database_auto_cleanup_retention_days },
|
||||
]
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ import {Textarea} from "@/components/ui/textarea"
|
||||
import {ErrorInline} from "@/components/layout/error"
|
||||
import {LoadingStateWithBorder} from "@/components/layout/loading"
|
||||
import type {DatabaseCleanupTarget} from "@/lib/services/openflare"
|
||||
import {AdminStatusService} from "@/lib/services/admin"
|
||||
import {NodeService, OptionService, StatusService, UptimeKumaService,} from "@/lib/services/openflare"
|
||||
import {AdminStatusService} from "@/lib/services/admin"
|
||||
import {VersionUpgradeDialog} from "@/app/(main)/components/version-upgrade-dialog"
|
||||
import {adminUpdateStatusQueryKey, openflarePublicStatusQueryKey,} from "@/lib/hooks/use-openflare-server-upgrade"
|
||||
|
||||
@@ -111,14 +111,14 @@ export function OpenFlareOpsSettings() {
|
||||
if (!optionsQuery.data) return
|
||||
const optionMap = optionsToMap(optionsQuery.data)
|
||||
const serverAddress =
|
||||
optionMap.ServerAddress ||
|
||||
optionMap.server_address ||
|
||||
statusQuery.data?.server_address ||
|
||||
getBrowserOrigin()
|
||||
setFields(mapOptionsToOpsFields(optionMap, serverAddress))
|
||||
}, [optionsQuery.data, statusQuery.data?.server_address])
|
||||
|
||||
const geoIPMutation = useMutation({
|
||||
mutationFn: () => OptionService.lookupGeoIP(fields.GeoIPProvider, geoIPTestIP.trim()),
|
||||
mutationFn: () => OptionService.lookupGeoIP(fields.geoip_provider, geoIPTestIP.trim()),
|
||||
})
|
||||
|
||||
const saveMutation = useMutation({
|
||||
@@ -186,9 +186,9 @@ export function OpenFlareOpsSettings() {
|
||||
|
||||
const discoveryToken = bootstrapQuery.data?.discovery_token ?? ""
|
||||
const discoveryCommand = useMemo(() => {
|
||||
if (!fields.ServerAddress || !discoveryToken) return ""
|
||||
return buildDiscoveryCommand(fields.ServerAddress, discoveryToken)
|
||||
}, [discoveryToken, fields.ServerAddress])
|
||||
if (!fields.server_address || !discoveryToken) return ""
|
||||
return buildDiscoveryCommand(fields.server_address, discoveryToken)
|
||||
}, [discoveryToken, fields.server_address])
|
||||
|
||||
const updateField = <K extends keyof OpenFlareOpsFields>(
|
||||
key: K,
|
||||
@@ -266,29 +266,29 @@ export function OpenFlareOpsSettings() {
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<FieldInput
|
||||
label={`心跳间隔 (${formatDurationLabel(fields.AgentHeartbeatInterval)})`}
|
||||
value={fields.AgentHeartbeatInterval}
|
||||
label={`心跳间隔 (${formatDurationLabel(fields.agent_heartbeat_interval)})`}
|
||||
value={fields.agent_heartbeat_interval}
|
||||
type="number"
|
||||
onChange={(value) => updateField("AgentHeartbeatInterval", value)}
|
||||
onChange={(value) => updateField("agent_heartbeat_interval", value)}
|
||||
/>
|
||||
<FieldInput
|
||||
label={`离线阈值 (${formatDurationLabel(fields.NodeOfflineThreshold)})`}
|
||||
value={fields.NodeOfflineThreshold}
|
||||
label={`离线阈值 (${formatDurationLabel(fields.node_offline_threshold)})`}
|
||||
value={fields.node_offline_threshold}
|
||||
type="number"
|
||||
onChange={(value) => updateField("NodeOfflineThreshold", value)}
|
||||
onChange={(value) => updateField("node_offline_threshold", value)}
|
||||
/>
|
||||
</div>
|
||||
<ToggleRow
|
||||
label="开启 WS 连接升级"
|
||||
description="HTTP 心跳成功后尝试升级为 WebSocket,配置发布可即时通知。"
|
||||
checked={fields.AgentWebsocketUpgradeEnabled}
|
||||
onChange={(value) => updateField("AgentWebsocketUpgradeEnabled", value)}
|
||||
checked={fields.agent_websocket_upgrade_enabled}
|
||||
onChange={(value) => updateField("agent_websocket_upgrade_enabled", value)}
|
||||
/>
|
||||
<FieldInput
|
||||
label="Agent 更新仓库"
|
||||
value={fields.AgentUpdateRepo}
|
||||
value={fields.agent_update_repo}
|
||||
placeholder="Rain-kl/OpenFlare"
|
||||
onChange={(value) => updateField("AgentUpdateRepo", value)}
|
||||
onChange={(value) => updateField("agent_update_repo", value)}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -314,8 +314,8 @@ export function OpenFlareOpsSettings() {
|
||||
<div className="space-y-1.5">
|
||||
<Label>归属方式</Label>
|
||||
<Select
|
||||
value={fields.GeoIPProvider}
|
||||
onValueChange={(value) => updateField("GeoIPProvider", value)}
|
||||
value={fields.geoip_provider}
|
||||
onValueChange={(value) => updateField("geoip_provider", value)}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
@@ -384,8 +384,8 @@ export function OpenFlareOpsSettings() {
|
||||
<CardContent className="space-y-4">
|
||||
<FieldInput
|
||||
label="Server URL"
|
||||
value={fields.ServerAddress}
|
||||
onChange={(value) => updateField("ServerAddress", value)}
|
||||
value={fields.server_address}
|
||||
onChange={(value) => updateField("server_address", value)}
|
||||
placeholder="https://yourdomain.com"
|
||||
/>
|
||||
<div className="rounded-lg border border-dashed p-3">
|
||||
@@ -428,7 +428,7 @@ export function OpenFlareOpsSettings() {
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={!fields.UptimeKumaEnabled || syncUptimeKumaMutation.isPending}
|
||||
disabled={!fields.uptime_kuma_enabled || syncUptimeKumaMutation.isPending}
|
||||
onClick={() => syncUptimeKumaMutation.mutate()}
|
||||
>
|
||||
<RefreshCw className="size-3.5 mr-1" />
|
||||
@@ -446,41 +446,41 @@ export function OpenFlareOpsSettings() {
|
||||
<CardContent className="space-y-4">
|
||||
<ToggleRow
|
||||
label="开启 Uptime Kuma"
|
||||
checked={fields.UptimeKumaEnabled}
|
||||
onChange={(value) => updateField("UptimeKumaEnabled", value)}
|
||||
checked={fields.uptime_kuma_enabled}
|
||||
onChange={(value) => updateField("uptime_kuma_enabled", value)}
|
||||
/>
|
||||
{fields.UptimeKumaEnabled ? (
|
||||
{fields.uptime_kuma_enabled ? (
|
||||
<>
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<FieldInput
|
||||
label="Uptime Kuma 地址"
|
||||
value={fields.UptimeKumaUrl}
|
||||
onChange={(value) => updateField("UptimeKumaUrl", value)}
|
||||
value={fields.uptime_kuma_url}
|
||||
onChange={(value) => updateField("uptime_kuma_url", value)}
|
||||
placeholder="http://localhost:3001"
|
||||
/>
|
||||
<FieldInput
|
||||
label="用户名"
|
||||
value={fields.UptimeKumaUsername}
|
||||
onChange={(value) => updateField("UptimeKumaUsername", value)}
|
||||
value={fields.uptime_kuma_username}
|
||||
onChange={(value) => updateField("uptime_kuma_username", value)}
|
||||
/>
|
||||
<FieldInput
|
||||
label="密码"
|
||||
value={fields.UptimeKumaPassword}
|
||||
value={fields.uptime_kuma_password}
|
||||
type="password"
|
||||
onChange={(value) => updateField("UptimeKumaPassword", value)}
|
||||
onChange={(value) => updateField("uptime_kuma_password", value)}
|
||||
placeholder="留空表示不更新"
|
||||
/>
|
||||
<FieldInput
|
||||
label="同步间隔 (分钟)"
|
||||
value={fields.UptimeKumaSyncInterval}
|
||||
value={fields.uptime_kuma_sync_interval}
|
||||
type="number"
|
||||
onChange={(value) => updateField("UptimeKumaSyncInterval", value)}
|
||||
onChange={(value) => updateField("uptime_kuma_sync_interval", value)}
|
||||
/>
|
||||
<div className="space-y-1.5">
|
||||
<Label>监控范围</Label>
|
||||
<Select
|
||||
value={fields.UptimeKumaMonitorScope}
|
||||
onValueChange={(value) => updateField("UptimeKumaMonitorScope", value)}
|
||||
value={fields.uptime_kuma_monitor_scope}
|
||||
onValueChange={(value) => updateField("uptime_kuma_monitor_scope", value)}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
@@ -492,7 +492,7 @@ export function OpenFlareOpsSettings() {
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
{fields.UptimeKumaMonitorScope === "selected" ? (
|
||||
{fields.uptime_kuma_monitor_scope === "selected" ? (
|
||||
<div className="rounded-lg border border-dashed p-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<p className="text-sm font-medium">已选站点</p>
|
||||
@@ -506,8 +506,8 @@ export function OpenFlareOpsSettings() {
|
||||
</Button>
|
||||
</div>
|
||||
<p className="mt-2 break-all text-xs text-muted-foreground">
|
||||
{fields.UptimeKumaSelectedSites
|
||||
? fields.UptimeKumaSelectedSites.split(",").join(", ")
|
||||
{fields.uptime_kuma_selected_sites
|
||||
? fields.uptime_kuma_selected_sites.split(",").join(", ")
|
||||
: "未选择任何站点"}
|
||||
</p>
|
||||
</div>
|
||||
@@ -515,27 +515,27 @@ export function OpenFlareOpsSettings() {
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<FieldInput
|
||||
label="检测频率 (秒)"
|
||||
value={fields.UptimeKumaInterval}
|
||||
value={fields.uptime_kuma_interval}
|
||||
type="number"
|
||||
onChange={(value) => updateField("UptimeKumaInterval", value)}
|
||||
onChange={(value) => updateField("uptime_kuma_interval", value)}
|
||||
/>
|
||||
<FieldInput
|
||||
label="重试次数"
|
||||
value={fields.UptimeKumaRetry}
|
||||
value={fields.uptime_kuma_retry}
|
||||
type="number"
|
||||
onChange={(value) => updateField("UptimeKumaRetry", value)}
|
||||
onChange={(value) => updateField("uptime_kuma_retry", value)}
|
||||
/>
|
||||
<FieldInput
|
||||
label="重试间隔 (秒)"
|
||||
value={fields.UptimeKumaRetryInterval}
|
||||
value={fields.uptime_kuma_retry_interval}
|
||||
type="number"
|
||||
onChange={(value) => updateField("UptimeKumaRetryInterval", value)}
|
||||
onChange={(value) => updateField("uptime_kuma_retry_interval", value)}
|
||||
/>
|
||||
<FieldInput
|
||||
label="请求超时 (秒)"
|
||||
value={fields.UptimeKumaTimeout}
|
||||
value={fields.uptime_kuma_timeout}
|
||||
type="number"
|
||||
onChange={(value) => updateField("UptimeKumaTimeout", value)}
|
||||
onChange={(value) => updateField("uptime_kuma_timeout", value)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
@@ -561,14 +561,14 @@ export function OpenFlareOpsSettings() {
|
||||
<CardContent className="space-y-4">
|
||||
<ToggleRow
|
||||
label="启用每日自动清理"
|
||||
checked={fields.DatabaseAutoCleanupEnabled}
|
||||
onChange={(value) => updateField("DatabaseAutoCleanupEnabled", value)}
|
||||
checked={fields.database_auto_cleanup_enabled}
|
||||
onChange={(value) => updateField("database_auto_cleanup_enabled", value)}
|
||||
/>
|
||||
<FieldInput
|
||||
label="保留天数"
|
||||
value={fields.DatabaseAutoCleanupRetentionDays}
|
||||
value={fields.database_auto_cleanup_retention_days}
|
||||
type="number"
|
||||
onChange={(value) => updateField("DatabaseAutoCleanupRetentionDays", value)}
|
||||
onChange={(value) => updateField("database_auto_cleanup_retention_days", value)}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -653,12 +653,12 @@ export function OpenFlareOpsSettings() {
|
||||
<UptimeKumaSiteSelectModal
|
||||
open={uptimeKumaModalOpen}
|
||||
selectedSites={
|
||||
fields.UptimeKumaSelectedSites
|
||||
? fields.UptimeKumaSelectedSites.split(",")
|
||||
fields.uptime_kuma_selected_sites
|
||||
? fields.uptime_kuma_selected_sites.split(",")
|
||||
: []
|
||||
}
|
||||
onOpenChange={setUptimeKumaModalOpen}
|
||||
onSave={(sites) => updateField("UptimeKumaSelectedSites", sites.join(","))}
|
||||
onSave={(sites) => updateField("uptime_kuma_selected_sites", sites.join(","))}
|
||||
/>
|
||||
|
||||
<AlertDialog
|
||||
|
||||
@@ -94,11 +94,6 @@ export function VersionSnapshotSheet({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs font-semibold">快照 JSON</p>
|
||||
<CodeBlock code={detail.snapshot_json} language="json" className="my-0 text-xs" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs font-semibold">主配置</p>
|
||||
<CodeBlock code={detail.main_config} language="nginx" className="my-0 text-xs" />
|
||||
|
||||
@@ -1,80 +1,80 @@
|
||||
export type PerformanceFields = {
|
||||
OpenRestyDefaultServerReturnStatus: string
|
||||
OpenRestyWorkerProcesses: string
|
||||
OpenRestyWorkerConnections: string
|
||||
OpenRestyWorkerRlimitNofile: string
|
||||
OpenRestyEventsUse: string
|
||||
OpenRestyEventsMultiAcceptEnabled: boolean
|
||||
OpenRestyKeepaliveTimeout: string
|
||||
OpenRestyKeepaliveRequests: string
|
||||
OpenRestyClientHeaderTimeout: string
|
||||
OpenRestyClientBodyTimeout: string
|
||||
OpenRestyClientMaxBodySize: string
|
||||
OpenRestyLargeClientHeaderBuffers: string
|
||||
OpenRestySendTimeout: string
|
||||
OpenRestyProxyConnectTimeout: string
|
||||
OpenRestyProxySendTimeout: string
|
||||
OpenRestyProxyReadTimeout: string
|
||||
OpenRestyWebsocketEnabled: boolean
|
||||
OpenRestyHTTP3Enabled: boolean
|
||||
OpenRestyProxyRequestBufferingEnabled: boolean
|
||||
OpenRestyProxyBufferingEnabled: boolean
|
||||
OpenRestyProxyBuffers: string
|
||||
OpenRestyProxyBufferSize: string
|
||||
OpenRestyProxyBusyBuffersSize: string
|
||||
OpenRestyGzipEnabled: boolean
|
||||
OpenRestyGzipMinLength: string
|
||||
OpenRestyGzipCompLevel: string
|
||||
OpenRestyCacheEnabled: boolean
|
||||
OpenRestyCachePath: string
|
||||
OpenRestyCacheLevels: string
|
||||
OpenRestyCacheInactive: string
|
||||
OpenRestyCacheMaxSize: string
|
||||
OpenRestyCacheKeyTemplate: string
|
||||
OpenRestyCacheLockEnabled: boolean
|
||||
OpenRestyCacheLockTimeout: string
|
||||
OpenRestyCacheUseStale: string
|
||||
OpenRestyResolvers: string
|
||||
openresty_default_server_return_status: string
|
||||
openresty_worker_processes: string
|
||||
openresty_worker_connections: string
|
||||
openresty_worker_rlimit_nofile: string
|
||||
openresty_events_use: string
|
||||
openresty_events_multi_accept_enabled: boolean
|
||||
openresty_keepalive_timeout: string
|
||||
openresty_keepalive_requests: string
|
||||
openresty_client_header_timeout: string
|
||||
openresty_client_body_timeout: string
|
||||
openresty_client_max_body_size: string
|
||||
openresty_large_client_header_buffers: string
|
||||
openresty_send_timeout: string
|
||||
openresty_proxy_connect_timeout: string
|
||||
openresty_proxy_send_timeout: string
|
||||
openresty_proxy_read_timeout: string
|
||||
openresty_websocket_enabled: boolean
|
||||
openresty_http3_enabled: boolean
|
||||
openresty_proxy_request_buffering_enabled: boolean
|
||||
openresty_proxy_buffering_enabled: boolean
|
||||
openresty_proxy_buffers: string
|
||||
openresty_proxy_buffer_size: string
|
||||
openresty_proxy_busy_buffers_size: string
|
||||
openresty_gzip_enabled: boolean
|
||||
openresty_gzip_min_length: string
|
||||
openresty_gzip_comp_level: string
|
||||
openresty_cache_enabled: boolean
|
||||
openresty_cache_path: string
|
||||
openresty_cache_levels: string
|
||||
openresty_cache_inactive: string
|
||||
openresty_cache_max_size: string
|
||||
openresty_cache_key_template: string
|
||||
openresty_cache_lock_enabled: boolean
|
||||
openresty_cache_lock_timeout: string
|
||||
openresty_cache_use_stale: string
|
||||
openresty_resolvers: string
|
||||
}
|
||||
|
||||
export const defaultPerformanceFields: PerformanceFields = {
|
||||
OpenRestyDefaultServerReturnStatus: "421",
|
||||
OpenRestyWorkerProcesses: "auto",
|
||||
OpenRestyWorkerConnections: "4096",
|
||||
OpenRestyWorkerRlimitNofile: "65535",
|
||||
OpenRestyEventsUse: "epoll",
|
||||
OpenRestyEventsMultiAcceptEnabled: true,
|
||||
OpenRestyKeepaliveTimeout: "20",
|
||||
OpenRestyKeepaliveRequests: "1000",
|
||||
OpenRestyClientHeaderTimeout: "15",
|
||||
OpenRestyClientBodyTimeout: "15",
|
||||
OpenRestyClientMaxBodySize: "64m",
|
||||
OpenRestyLargeClientHeaderBuffers: "4 16k",
|
||||
OpenRestySendTimeout: "30",
|
||||
OpenRestyProxyConnectTimeout: "3",
|
||||
OpenRestyProxySendTimeout: "60",
|
||||
OpenRestyProxyReadTimeout: "60",
|
||||
OpenRestyWebsocketEnabled: true,
|
||||
OpenRestyHTTP3Enabled: true,
|
||||
OpenRestyProxyRequestBufferingEnabled: false,
|
||||
OpenRestyProxyBufferingEnabled: true,
|
||||
OpenRestyProxyBuffers: "16 16k",
|
||||
OpenRestyProxyBufferSize: "8k",
|
||||
OpenRestyProxyBusyBuffersSize: "64k",
|
||||
OpenRestyGzipEnabled: true,
|
||||
OpenRestyGzipMinLength: "1024",
|
||||
OpenRestyGzipCompLevel: "5",
|
||||
OpenRestyCacheEnabled: false,
|
||||
OpenRestyCachePath: "",
|
||||
OpenRestyCacheLevels: "1:2",
|
||||
OpenRestyCacheInactive: "30m",
|
||||
OpenRestyCacheMaxSize: "1g",
|
||||
OpenRestyCacheKeyTemplate: "$scheme$host$request_uri",
|
||||
OpenRestyCacheLockEnabled: true,
|
||||
OpenRestyCacheLockTimeout: "5s",
|
||||
OpenRestyCacheUseStale:
|
||||
openresty_default_server_return_status: "421",
|
||||
openresty_worker_processes: "auto",
|
||||
openresty_worker_connections: "4096",
|
||||
openresty_worker_rlimit_nofile: "65535",
|
||||
openresty_events_use: "epoll",
|
||||
openresty_events_multi_accept_enabled: true,
|
||||
openresty_keepalive_timeout: "20",
|
||||
openresty_keepalive_requests: "1000",
|
||||
openresty_client_header_timeout: "15",
|
||||
openresty_client_body_timeout: "15",
|
||||
openresty_client_max_body_size: "64m",
|
||||
openresty_large_client_header_buffers: "4 16k",
|
||||
openresty_send_timeout: "30",
|
||||
openresty_proxy_connect_timeout: "3",
|
||||
openresty_proxy_send_timeout: "60",
|
||||
openresty_proxy_read_timeout: "60",
|
||||
openresty_websocket_enabled: true,
|
||||
openresty_http3_enabled: true,
|
||||
openresty_proxy_request_buffering_enabled: false,
|
||||
openresty_proxy_buffering_enabled: true,
|
||||
openresty_proxy_buffers: "16 16k",
|
||||
openresty_proxy_buffer_size: "8k",
|
||||
openresty_proxy_busy_buffers_size: "64k",
|
||||
openresty_gzip_enabled: true,
|
||||
openresty_gzip_min_length: "1024",
|
||||
openresty_gzip_comp_level: "5",
|
||||
openresty_cache_enabled: false,
|
||||
openresty_cache_path: "",
|
||||
openresty_cache_levels: "1:2",
|
||||
openresty_cache_inactive: "30m",
|
||||
openresty_cache_max_size: "1g",
|
||||
openresty_cache_key_template: "$scheme$host$request_uri",
|
||||
openresty_cache_lock_enabled: true,
|
||||
openresty_cache_lock_timeout: "5s",
|
||||
openresty_cache_use_stale:
|
||||
"error timeout updating http_500 http_502 http_503 http_504",
|
||||
OpenRestyResolvers: "",
|
||||
openresty_resolvers: "",
|
||||
}
|
||||
|
||||
export function optionsToMap(options: Array<{ key: string; value: string }>) {
|
||||
@@ -93,65 +93,65 @@ export function mapOptionsToFields(
|
||||
optionMap: Record<string, string>,
|
||||
): PerformanceFields {
|
||||
return {
|
||||
OpenRestyDefaultServerReturnStatus:
|
||||
optionMap.OpenRestyDefaultServerReturnStatus ?? "421",
|
||||
OpenRestyWorkerProcesses: optionMap.OpenRestyWorkerProcesses ?? "auto",
|
||||
OpenRestyWorkerConnections: optionMap.OpenRestyWorkerConnections ?? "4096",
|
||||
OpenRestyWorkerRlimitNofile:
|
||||
optionMap.OpenRestyWorkerRlimitNofile ?? "65535",
|
||||
OpenRestyEventsUse: optionMap.OpenRestyEventsUse ?? "epoll",
|
||||
OpenRestyEventsMultiAcceptEnabled: toBoolean(
|
||||
optionMap.OpenRestyEventsMultiAcceptEnabled,
|
||||
openresty_default_server_return_status:
|
||||
optionMap.openresty_default_server_return_status ?? "421",
|
||||
openresty_worker_processes: optionMap.openresty_worker_processes ?? "auto",
|
||||
openresty_worker_connections: optionMap.openresty_worker_connections ?? "4096",
|
||||
openresty_worker_rlimit_nofile:
|
||||
optionMap.openresty_worker_rlimit_nofile ?? "65535",
|
||||
openresty_events_use: optionMap.openresty_events_use ?? "epoll",
|
||||
openresty_events_multi_accept_enabled: toBoolean(
|
||||
optionMap.openresty_events_multi_accept_enabled,
|
||||
true,
|
||||
),
|
||||
OpenRestyKeepaliveTimeout: optionMap.OpenRestyKeepaliveTimeout ?? "20",
|
||||
OpenRestyKeepaliveRequests: optionMap.OpenRestyKeepaliveRequests ?? "1000",
|
||||
OpenRestyClientHeaderTimeout:
|
||||
optionMap.OpenRestyClientHeaderTimeout ?? "15",
|
||||
OpenRestyClientBodyTimeout: optionMap.OpenRestyClientBodyTimeout ?? "15",
|
||||
OpenRestyClientMaxBodySize: optionMap.OpenRestyClientMaxBodySize ?? "64m",
|
||||
OpenRestyLargeClientHeaderBuffers:
|
||||
optionMap.OpenRestyLargeClientHeaderBuffers ?? "4 16k",
|
||||
OpenRestySendTimeout: optionMap.OpenRestySendTimeout ?? "30",
|
||||
OpenRestyProxyConnectTimeout: optionMap.OpenRestyProxyConnectTimeout ?? "3",
|
||||
OpenRestyProxySendTimeout: optionMap.OpenRestyProxySendTimeout ?? "60",
|
||||
OpenRestyProxyReadTimeout: optionMap.OpenRestyProxyReadTimeout ?? "60",
|
||||
OpenRestyWebsocketEnabled: toBoolean(
|
||||
optionMap.OpenRestyWebsocketEnabled,
|
||||
openresty_keepalive_timeout: optionMap.openresty_keepalive_timeout ?? "20",
|
||||
openresty_keepalive_requests: optionMap.openresty_keepalive_requests ?? "1000",
|
||||
openresty_client_header_timeout:
|
||||
optionMap.openresty_client_header_timeout ?? "15",
|
||||
openresty_client_body_timeout: optionMap.openresty_client_body_timeout ?? "15",
|
||||
openresty_client_max_body_size: optionMap.openresty_client_max_body_size ?? "64m",
|
||||
openresty_large_client_header_buffers:
|
||||
optionMap.openresty_large_client_header_buffers ?? "4 16k",
|
||||
openresty_send_timeout: optionMap.openresty_send_timeout ?? "30",
|
||||
openresty_proxy_connect_timeout: optionMap.openresty_proxy_connect_timeout ?? "3",
|
||||
openresty_proxy_send_timeout: optionMap.openresty_proxy_send_timeout ?? "60",
|
||||
openresty_proxy_read_timeout: optionMap.openresty_proxy_read_timeout ?? "60",
|
||||
openresty_websocket_enabled: toBoolean(
|
||||
optionMap.openresty_websocket_enabled,
|
||||
true,
|
||||
),
|
||||
OpenRestyHTTP3Enabled: toBoolean(optionMap.OpenRestyHTTP3Enabled, false),
|
||||
OpenRestyProxyRequestBufferingEnabled: toBoolean(
|
||||
optionMap.OpenRestyProxyRequestBufferingEnabled,
|
||||
openresty_http3_enabled: toBoolean(optionMap.openresty_http3_enabled, false),
|
||||
openresty_proxy_request_buffering_enabled: toBoolean(
|
||||
optionMap.openresty_proxy_request_buffering_enabled,
|
||||
false,
|
||||
),
|
||||
OpenRestyProxyBufferingEnabled: toBoolean(
|
||||
optionMap.OpenRestyProxyBufferingEnabled,
|
||||
openresty_proxy_buffering_enabled: toBoolean(
|
||||
optionMap.openresty_proxy_buffering_enabled,
|
||||
true,
|
||||
),
|
||||
OpenRestyProxyBuffers: optionMap.OpenRestyProxyBuffers ?? "16 16k",
|
||||
OpenRestyProxyBufferSize: optionMap.OpenRestyProxyBufferSize ?? "8k",
|
||||
OpenRestyProxyBusyBuffersSize:
|
||||
optionMap.OpenRestyProxyBusyBuffersSize ?? "64k",
|
||||
OpenRestyGzipEnabled: toBoolean(optionMap.OpenRestyGzipEnabled, true),
|
||||
OpenRestyGzipMinLength: optionMap.OpenRestyGzipMinLength ?? "1024",
|
||||
OpenRestyGzipCompLevel: optionMap.OpenRestyGzipCompLevel ?? "5",
|
||||
OpenRestyCacheEnabled: toBoolean(optionMap.OpenRestyCacheEnabled, false),
|
||||
OpenRestyCachePath: optionMap.OpenRestyCachePath ?? "",
|
||||
OpenRestyCacheLevels: optionMap.OpenRestyCacheLevels ?? "1:2",
|
||||
OpenRestyCacheInactive: optionMap.OpenRestyCacheInactive ?? "30m",
|
||||
OpenRestyCacheMaxSize: optionMap.OpenRestyCacheMaxSize ?? "1g",
|
||||
OpenRestyCacheKeyTemplate:
|
||||
optionMap.OpenRestyCacheKeyTemplate ?? "$scheme$host$request_uri",
|
||||
OpenRestyCacheLockEnabled: toBoolean(
|
||||
optionMap.OpenRestyCacheLockEnabled,
|
||||
openresty_proxy_buffers: optionMap.openresty_proxy_buffers ?? "16 16k",
|
||||
openresty_proxy_buffer_size: optionMap.openresty_proxy_buffer_size ?? "8k",
|
||||
openresty_proxy_busy_buffers_size:
|
||||
optionMap.openresty_proxy_busy_buffers_size ?? "64k",
|
||||
openresty_gzip_enabled: toBoolean(optionMap.openresty_gzip_enabled, true),
|
||||
openresty_gzip_min_length: optionMap.openresty_gzip_min_length ?? "1024",
|
||||
openresty_gzip_comp_level: optionMap.openresty_gzip_comp_level ?? "5",
|
||||
openresty_cache_enabled: toBoolean(optionMap.openresty_cache_enabled, false),
|
||||
openresty_cache_path: optionMap.openresty_cache_path ?? "",
|
||||
openresty_cache_levels: optionMap.openresty_cache_levels ?? "1:2",
|
||||
openresty_cache_inactive: optionMap.openresty_cache_inactive ?? "30m",
|
||||
openresty_cache_max_size: optionMap.openresty_cache_max_size ?? "1g",
|
||||
openresty_cache_key_template:
|
||||
optionMap.openresty_cache_key_template ?? "$scheme$host$request_uri",
|
||||
openresty_cache_lock_enabled: toBoolean(
|
||||
optionMap.openresty_cache_lock_enabled,
|
||||
true,
|
||||
),
|
||||
OpenRestyCacheLockTimeout: optionMap.OpenRestyCacheLockTimeout ?? "5s",
|
||||
OpenRestyCacheUseStale:
|
||||
optionMap.OpenRestyCacheUseStale ??
|
||||
openresty_cache_lock_timeout: optionMap.openresty_cache_lock_timeout ?? "5s",
|
||||
openresty_cache_use_stale:
|
||||
optionMap.openresty_cache_use_stale ??
|
||||
"error timeout updating http_500 http_502 http_503 http_504",
|
||||
OpenRestyResolvers: optionMap.OpenRestyResolvers ?? "",
|
||||
openresty_resolvers: optionMap.openresty_resolvers ?? "",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,79 +178,79 @@ function isCacheLevelsValue(value: string) {
|
||||
|
||||
export function validateRuntimeFields(fields: PerformanceFields) {
|
||||
if (
|
||||
fields.OpenRestyWorkerProcesses !== "auto" &&
|
||||
!isPositiveInteger(fields.OpenRestyWorkerProcesses)
|
||||
fields.openresty_worker_processes !== "auto" &&
|
||||
!isPositiveInteger(fields.openresty_worker_processes)
|
||||
) {
|
||||
throw new Error("worker_processes 必须为 auto 或大于 0 的整数")
|
||||
}
|
||||
const integers = [
|
||||
fields.OpenRestyWorkerConnections,
|
||||
fields.OpenRestyWorkerRlimitNofile,
|
||||
fields.OpenRestyKeepaliveTimeout,
|
||||
fields.OpenRestyKeepaliveRequests,
|
||||
fields.OpenRestyClientHeaderTimeout,
|
||||
fields.OpenRestyClientBodyTimeout,
|
||||
fields.OpenRestySendTimeout,
|
||||
fields.openresty_worker_connections,
|
||||
fields.openresty_worker_rlimit_nofile,
|
||||
fields.openresty_keepalive_timeout,
|
||||
fields.openresty_keepalive_requests,
|
||||
fields.openresty_client_header_timeout,
|
||||
fields.openresty_client_body_timeout,
|
||||
fields.openresty_send_timeout,
|
||||
]
|
||||
if (integers.some((value) => !isPositiveInteger(value))) {
|
||||
throw new Error("超时与连接参数必须为大于 0 的整数")
|
||||
}
|
||||
const status = Number.parseInt(fields.OpenRestyDefaultServerReturnStatus, 10)
|
||||
const status = Number.parseInt(fields.openresty_default_server_return_status, 10)
|
||||
if (Number.isNaN(status) || status < 100 || status > 999) {
|
||||
throw new Error("空白页面返回状态码必须在 100 到 999 之间")
|
||||
}
|
||||
if (!isSizeValue(fields.OpenRestyClientMaxBodySize)) {
|
||||
if (!isSizeValue(fields.openresty_client_max_body_size)) {
|
||||
throw new Error("client_max_body_size 格式不合法")
|
||||
}
|
||||
if (!isProxyBuffersValue(fields.OpenRestyLargeClientHeaderBuffers)) {
|
||||
if (!isProxyBuffersValue(fields.openresty_large_client_header_buffers)) {
|
||||
throw new Error('large_client_header_buffers 格式必须类似 "4 16k"')
|
||||
}
|
||||
}
|
||||
|
||||
export function validateProxyFields(fields: PerformanceFields) {
|
||||
const timeouts = [
|
||||
fields.OpenRestyProxyConnectTimeout,
|
||||
fields.OpenRestyProxySendTimeout,
|
||||
fields.OpenRestyProxyReadTimeout,
|
||||
fields.openresty_proxy_connect_timeout,
|
||||
fields.openresty_proxy_send_timeout,
|
||||
fields.openresty_proxy_read_timeout,
|
||||
]
|
||||
if (timeouts.some((value) => !isPositiveInteger(value))) {
|
||||
throw new Error("代理超时参数必须为大于 0 的整数秒")
|
||||
}
|
||||
if (!isProxyBuffersValue(fields.OpenRestyProxyBuffers)) {
|
||||
if (!isProxyBuffersValue(fields.openresty_proxy_buffers)) {
|
||||
throw new Error('proxy_buffers 格式必须类似 "16 16k"')
|
||||
}
|
||||
if (
|
||||
!isSizeValue(fields.OpenRestyProxyBufferSize) ||
|
||||
!isSizeValue(fields.OpenRestyProxyBusyBuffersSize)
|
||||
!isSizeValue(fields.openresty_proxy_buffer_size) ||
|
||||
!isSizeValue(fields.openresty_proxy_busy_buffers_size)
|
||||
) {
|
||||
throw new Error("缓冲大小必须为整数或带 k/m/g 单位的值")
|
||||
}
|
||||
}
|
||||
|
||||
export function validateGzipFields(fields: PerformanceFields) {
|
||||
if (!isPositiveInteger(fields.OpenRestyGzipMinLength)) {
|
||||
if (!isPositiveInteger(fields.openresty_gzip_min_length)) {
|
||||
throw new Error("gzip_min_length 必须为大于 0 的整数")
|
||||
}
|
||||
const level = Number.parseInt(fields.OpenRestyGzipCompLevel, 10)
|
||||
const level = Number.parseInt(fields.openresty_gzip_comp_level, 10)
|
||||
if (Number.isNaN(level) || level < 1 || level > 9) {
|
||||
throw new Error("gzip_comp_level 必须在 1 到 9 之间")
|
||||
}
|
||||
}
|
||||
|
||||
export function validateCacheFields(fields: PerformanceFields) {
|
||||
if (!fields.OpenRestyCacheEnabled) return
|
||||
if (!fields.OpenRestyCachePath.trim()) {
|
||||
if (!fields.openresty_cache_enabled) return
|
||||
if (!fields.openresty_cache_path.trim()) {
|
||||
throw new Error("启用缓存时必须填写 proxy_cache_path 目录")
|
||||
}
|
||||
if (
|
||||
!isCacheLevelsValue(fields.OpenRestyCacheLevels) ||
|
||||
!isDurationToken(fields.OpenRestyCacheInactive) ||
|
||||
!isSizeValue(fields.OpenRestyCacheMaxSize) ||
|
||||
!isDurationToken(fields.OpenRestyCacheLockTimeout)
|
||||
!isCacheLevelsValue(fields.openresty_cache_levels) ||
|
||||
!isDurationToken(fields.openresty_cache_inactive) ||
|
||||
!isSizeValue(fields.openresty_cache_max_size) ||
|
||||
!isDurationToken(fields.openresty_cache_lock_timeout)
|
||||
) {
|
||||
throw new Error("缓存 levels、inactive、max_size 或 lock_timeout 格式不合法")
|
||||
}
|
||||
if (!fields.OpenRestyCacheKeyTemplate.trim()) {
|
||||
if (!fields.openresty_cache_key_template.trim()) {
|
||||
throw new Error("启用缓存时必须填写缓存 Key 模板")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,20 +162,20 @@ export default function PerformancePage() {
|
||||
section: "runtime",
|
||||
validator: validateRuntimeFields,
|
||||
entries: entriesFromKeys(fields, [
|
||||
"OpenRestyDefaultServerReturnStatus",
|
||||
"OpenRestyWorkerProcesses",
|
||||
"OpenRestyResolvers",
|
||||
"OpenRestyWorkerConnections",
|
||||
"OpenRestyWorkerRlimitNofile",
|
||||
"OpenRestyEventsUse",
|
||||
"OpenRestyEventsMultiAcceptEnabled",
|
||||
"OpenRestyKeepaliveTimeout",
|
||||
"OpenRestyKeepaliveRequests",
|
||||
"OpenRestyClientHeaderTimeout",
|
||||
"OpenRestyClientBodyTimeout",
|
||||
"OpenRestyClientMaxBodySize",
|
||||
"OpenRestyLargeClientHeaderBuffers",
|
||||
"OpenRestySendTimeout",
|
||||
"openresty_default_server_return_status",
|
||||
"openresty_worker_processes",
|
||||
"openresty_resolvers",
|
||||
"openresty_worker_connections",
|
||||
"openresty_worker_rlimit_nofile",
|
||||
"openresty_events_use",
|
||||
"openresty_events_multi_accept_enabled",
|
||||
"openresty_keepalive_timeout",
|
||||
"openresty_keepalive_requests",
|
||||
"openresty_client_header_timeout",
|
||||
"openresty_client_body_timeout",
|
||||
"openresty_client_max_body_size",
|
||||
"openresty_large_client_header_buffers",
|
||||
"openresty_send_timeout",
|
||||
]),
|
||||
})
|
||||
}
|
||||
@@ -189,12 +189,12 @@ export default function PerformancePage() {
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
<FieldInput label="worker_processes" value={fields.OpenRestyWorkerProcesses} onChange={(v) => updateField("OpenRestyWorkerProcesses", v)} />
|
||||
<FieldInput label="worker_connections" value={fields.OpenRestyWorkerConnections} onChange={(v) => updateField("OpenRestyWorkerConnections", v)} type="number" />
|
||||
<FieldInput label="worker_rlimit_nofile" value={fields.OpenRestyWorkerRlimitNofile} onChange={(v) => updateField("OpenRestyWorkerRlimitNofile", v)} type="number" />
|
||||
<FieldInput label="worker_processes" value={fields.openresty_worker_processes} onChange={(v) => updateField("openresty_worker_processes", v)} />
|
||||
<FieldInput label="worker_connections" value={fields.openresty_worker_connections} onChange={(v) => updateField("openresty_worker_connections", v)} type="number" />
|
||||
<FieldInput label="worker_rlimit_nofile" value={fields.openresty_worker_rlimit_nofile} onChange={(v) => updateField("openresty_worker_rlimit_nofile", v)} type="number" />
|
||||
<div className="space-y-1.5">
|
||||
<Label>events use</Label>
|
||||
<Select value={fields.OpenRestyEventsUse} onValueChange={(v) => updateField("OpenRestyEventsUse", v)}>
|
||||
<Select value={fields.openresty_events_use} onValueChange={(v) => updateField("openresty_events_use", v)}>
|
||||
<SelectTrigger><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="epoll">epoll</SelectItem>
|
||||
@@ -204,11 +204,11 @@ export default function PerformancePage() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<ToggleRow label="multi_accept" checked={fields.OpenRestyEventsMultiAcceptEnabled} onChange={(v) => updateField("OpenRestyEventsMultiAcceptEnabled", v)} />
|
||||
<FieldInput label="keepalive_timeout" value={fields.OpenRestyKeepaliveTimeout} onChange={(v) => updateField("OpenRestyKeepaliveTimeout", v)} type="number" />
|
||||
<FieldInput label="client_max_body_size" value={fields.OpenRestyClientMaxBodySize} onChange={(v) => updateField("OpenRestyClientMaxBodySize", v)} />
|
||||
<FieldInput label="resolvers" value={fields.OpenRestyResolvers} onChange={(v) => updateField("OpenRestyResolvers", v)} placeholder="1.1.1.1 8.8.8.8" />
|
||||
<FieldInput label="default_server_return_status" value={fields.OpenRestyDefaultServerReturnStatus} onChange={(v) => updateField("OpenRestyDefaultServerReturnStatus", v)} type="number" />
|
||||
<ToggleRow label="multi_accept" checked={fields.openresty_events_multi_accept_enabled} onChange={(v) => updateField("openresty_events_multi_accept_enabled", v)} />
|
||||
<FieldInput label="keepalive_timeout" value={fields.openresty_keepalive_timeout} onChange={(v) => updateField("openresty_keepalive_timeout", v)} type="number" />
|
||||
<FieldInput label="client_max_body_size" value={fields.openresty_client_max_body_size} onChange={(v) => updateField("openresty_client_max_body_size", v)} />
|
||||
<FieldInput label="resolvers" value={fields.openresty_resolvers} onChange={(v) => updateField("openresty_resolvers", v)} placeholder="1.1.1.1 8.8.8.8" />
|
||||
<FieldInput label="default_server_return_status" value={fields.openresty_default_server_return_status} onChange={(v) => updateField("openresty_default_server_return_status", v)} type="number" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -226,16 +226,16 @@ export default function PerformancePage() {
|
||||
section: "proxy",
|
||||
validator: validateProxyFields,
|
||||
entries: entriesFromKeys(fields, [
|
||||
"OpenRestyProxyConnectTimeout",
|
||||
"OpenRestyProxySendTimeout",
|
||||
"OpenRestyProxyReadTimeout",
|
||||
"OpenRestyWebsocketEnabled",
|
||||
"OpenRestyHTTP3Enabled",
|
||||
"OpenRestyProxyRequestBufferingEnabled",
|
||||
"OpenRestyProxyBufferingEnabled",
|
||||
"OpenRestyProxyBuffers",
|
||||
"OpenRestyProxyBufferSize",
|
||||
"OpenRestyProxyBusyBuffersSize",
|
||||
"openresty_proxy_connect_timeout",
|
||||
"openresty_proxy_send_timeout",
|
||||
"openresty_proxy_read_timeout",
|
||||
"openresty_websocket_enabled",
|
||||
"openresty_http3_enabled",
|
||||
"openresty_proxy_request_buffering_enabled",
|
||||
"openresty_proxy_buffering_enabled",
|
||||
"openresty_proxy_buffers",
|
||||
"openresty_proxy_buffer_size",
|
||||
"openresty_proxy_busy_buffers_size",
|
||||
]),
|
||||
})
|
||||
}
|
||||
@@ -245,12 +245,12 @@ export default function PerformancePage() {
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent className="grid gap-4 md:grid-cols-2">
|
||||
<FieldInput label="proxy_connect_timeout" value={fields.OpenRestyProxyConnectTimeout} onChange={(v) => updateField("OpenRestyProxyConnectTimeout", v)} type="number" />
|
||||
<FieldInput label="proxy_read_timeout" value={fields.OpenRestyProxyReadTimeout} onChange={(v) => updateField("OpenRestyProxyReadTimeout", v)} type="number" />
|
||||
<ToggleRow label="websocket" checked={fields.OpenRestyWebsocketEnabled} onChange={(v) => updateField("OpenRestyWebsocketEnabled", v)} />
|
||||
<ToggleRow label="http3" checked={fields.OpenRestyHTTP3Enabled} onChange={(v) => updateField("OpenRestyHTTP3Enabled", v)} />
|
||||
<ToggleRow label="proxy_buffering" checked={fields.OpenRestyProxyBufferingEnabled} onChange={(v) => updateField("OpenRestyProxyBufferingEnabled", v)} />
|
||||
<FieldInput label="proxy_buffers" value={fields.OpenRestyProxyBuffers} onChange={(v) => updateField("OpenRestyProxyBuffers", v)} />
|
||||
<FieldInput label="proxy_connect_timeout" value={fields.openresty_proxy_connect_timeout} onChange={(v) => updateField("openresty_proxy_connect_timeout", v)} type="number" />
|
||||
<FieldInput label="proxy_read_timeout" value={fields.openresty_proxy_read_timeout} onChange={(v) => updateField("openresty_proxy_read_timeout", v)} type="number" />
|
||||
<ToggleRow label="websocket" checked={fields.openresty_websocket_enabled} onChange={(v) => updateField("openresty_websocket_enabled", v)} />
|
||||
<ToggleRow label="http3" checked={fields.openresty_http3_enabled} onChange={(v) => updateField("openresty_http3_enabled", v)} />
|
||||
<ToggleRow label="proxy_buffering" checked={fields.openresty_proxy_buffering_enabled} onChange={(v) => updateField("openresty_proxy_buffering_enabled", v)} />
|
||||
<FieldInput label="proxy_buffers" value={fields.openresty_proxy_buffers} onChange={(v) => updateField("openresty_proxy_buffers", v)} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -266,9 +266,9 @@ export default function PerformancePage() {
|
||||
section: "gzip",
|
||||
validator: validateGzipFields,
|
||||
entries: entriesFromKeys(fields, [
|
||||
"OpenRestyGzipEnabled",
|
||||
"OpenRestyGzipMinLength",
|
||||
"OpenRestyGzipCompLevel",
|
||||
"openresty_gzip_enabled",
|
||||
"openresty_gzip_min_length",
|
||||
"openresty_gzip_comp_level",
|
||||
]),
|
||||
})
|
||||
}
|
||||
@@ -277,9 +277,9 @@ export default function PerformancePage() {
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<ToggleRow label="gzip" checked={fields.OpenRestyGzipEnabled} onChange={(v) => updateField("OpenRestyGzipEnabled", v)} />
|
||||
<FieldInput label="gzip_min_length" value={fields.OpenRestyGzipMinLength} onChange={(v) => updateField("OpenRestyGzipMinLength", v)} type="number" />
|
||||
<FieldInput label="gzip_comp_level" value={fields.OpenRestyGzipCompLevel} onChange={(v) => updateField("OpenRestyGzipCompLevel", v)} type="number" />
|
||||
<ToggleRow label="gzip" checked={fields.openresty_gzip_enabled} onChange={(v) => updateField("openresty_gzip_enabled", v)} />
|
||||
<FieldInput label="gzip_min_length" value={fields.openresty_gzip_min_length} onChange={(v) => updateField("openresty_gzip_min_length", v)} type="number" />
|
||||
<FieldInput label="gzip_comp_level" value={fields.openresty_gzip_comp_level} onChange={(v) => updateField("openresty_gzip_comp_level", v)} type="number" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -297,15 +297,15 @@ export default function PerformancePage() {
|
||||
section: "cache",
|
||||
validator: validateCacheFields,
|
||||
entries: entriesFromKeys(fields, [
|
||||
"OpenRestyCacheEnabled",
|
||||
"OpenRestyCachePath",
|
||||
"OpenRestyCacheLevels",
|
||||
"OpenRestyCacheInactive",
|
||||
"OpenRestyCacheMaxSize",
|
||||
"OpenRestyCacheKeyTemplate",
|
||||
"OpenRestyCacheLockEnabled",
|
||||
"OpenRestyCacheLockTimeout",
|
||||
"OpenRestyCacheUseStale",
|
||||
"openresty_cache_enabled",
|
||||
"openresty_cache_path",
|
||||
"openresty_cache_levels",
|
||||
"openresty_cache_inactive",
|
||||
"openresty_cache_max_size",
|
||||
"openresty_cache_key_template",
|
||||
"openresty_cache_lock_enabled",
|
||||
"openresty_cache_lock_timeout",
|
||||
"openresty_cache_use_stale",
|
||||
]),
|
||||
})
|
||||
}
|
||||
@@ -314,10 +314,10 @@ export default function PerformancePage() {
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<ToggleRow label="cache_enabled" checked={fields.OpenRestyCacheEnabled} onChange={(v) => updateField("OpenRestyCacheEnabled", v)} />
|
||||
<FieldInput label="proxy_cache_path" value={fields.OpenRestyCachePath} onChange={(v) => updateField("OpenRestyCachePath", v)} disabled={!fields.OpenRestyCacheEnabled} />
|
||||
<FieldInput label="levels" value={fields.OpenRestyCacheLevels} onChange={(v) => updateField("OpenRestyCacheLevels", v)} disabled={!fields.OpenRestyCacheEnabled} />
|
||||
<FieldInput label="max_size" value={fields.OpenRestyCacheMaxSize} onChange={(v) => updateField("OpenRestyCacheMaxSize", v)} disabled={!fields.OpenRestyCacheEnabled} />
|
||||
<ToggleRow label="cache_enabled" checked={fields.openresty_cache_enabled} onChange={(v) => updateField("openresty_cache_enabled", v)} />
|
||||
<FieldInput label="proxy_cache_path" value={fields.openresty_cache_path} onChange={(v) => updateField("openresty_cache_path", v)} disabled={!fields.openresty_cache_enabled} />
|
||||
<FieldInput label="levels" value={fields.openresty_cache_levels} onChange={(v) => updateField("openresty_cache_levels", v)} disabled={!fields.openresty_cache_enabled} />
|
||||
<FieldInput label="max_size" value={fields.openresty_cache_max_size} onChange={(v) => updateField("openresty_cache_max_size", v)} disabled={!fields.openresty_cache_enabled} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user