fix: 自定义规则置顶生效,写入前校验策略名存在
规则首条匹配即生效,自定义规则此前插在模板规则之后、FINAL 之前,被 download.conf 等宽泛规则集抢先命中(brew.sh 配了代理仍直连)。现在新建 规则插到 seq 0,重新播种时也把自定义规则整体排在模板规则之前。 同时把 BUILTIN_POLICIES 提到 shared 共用,规则新建/编辑时校验策略必须是 内置策略或已有策略组,避免引用不存在的策略被 IR 静默剔除;前端表单默认 策略由不存在的「Proxy」改为 DIRECT。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import { Hono } from 'hono';
|
||||
import { zValidator } from '@hono/zod-validator';
|
||||
import { asc, eq } from 'drizzle-orm';
|
||||
import { asc, eq, sql } from 'drizzle-orm';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { z } from 'zod';
|
||||
import { ruleInputSchema, type RuleDto } from '@proxy-station/shared';
|
||||
import { BUILTIN_POLICIES, ruleInputSchema, type RuleDto } from '@proxy-station/shared';
|
||||
import { db } from '../db/index.js';
|
||||
import { rules, rulesets } from '../db/schema.js';
|
||||
import { policyGroups, rules, rulesets } from '../db/schema.js';
|
||||
import { seedRulesFromTemplate } from '../db/seed.js';
|
||||
|
||||
function loadRules(): RuleDto[] {
|
||||
@@ -22,29 +22,26 @@ function loadRules(): RuleDto[] {
|
||||
});
|
||||
}
|
||||
|
||||
function nextSeq(): number {
|
||||
const rows = db.select({ seq: rules.seq }).from(rules).all();
|
||||
return rows.length ? Math.max(...rows.map((r) => r.seq)) + 1 : 0;
|
||||
/** 引用不存在的策略组会被 IR 静默剔除,必须在写入前拦下 */
|
||||
function policyError(policy: string): string | null {
|
||||
if ((BUILTIN_POLICIES as readonly string[]).includes(policy)) return null;
|
||||
const exists = db.select({ id: policyGroups.id }).from(policyGroups).where(eq(policyGroups.name, policy)).get();
|
||||
return exists ? null : `策略「${policy}」不存在:请选择内置策略或已有策略组`;
|
||||
}
|
||||
|
||||
export const rulesRoute = new Hono()
|
||||
.get('/', (c) => c.json(loadRules()))
|
||||
.post('/', zValidator('json', ruleInputSchema), (c) => {
|
||||
const input = c.req.valid('json');
|
||||
// 新自定义规则插到 FINAL 之前
|
||||
const finalRow = db.select().from(rules).where(eq(rules.type, 'FINAL')).get();
|
||||
let seq: number;
|
||||
if (finalRow) {
|
||||
seq = finalRow.seq;
|
||||
db.update(rules).set({ seq: finalRow.seq + 1 }).where(eq(rules.id, finalRow.id)).run();
|
||||
} else {
|
||||
seq = nextSeq();
|
||||
}
|
||||
const err = policyError(input.policy);
|
||||
if (err) return c.json({ error: err }, 400);
|
||||
// 规则首条匹配即生效,自定义规则必须压过模板里的宽泛规则集(如 download.conf),插到最前
|
||||
db.update(rules).set({ seq: sql`${rules.seq} + 1` }).run();
|
||||
const id = nanoid(10);
|
||||
db.insert(rules)
|
||||
.values({
|
||||
id,
|
||||
seq,
|
||||
seq: 0,
|
||||
type: input.type,
|
||||
value: input.value ?? null,
|
||||
policy: input.policy,
|
||||
@@ -69,6 +66,8 @@ export const rulesRoute = new Hono()
|
||||
const existing = db.select().from(rules).where(eq(rules.id, id)).get();
|
||||
if (!existing) return c.json({ error: '规则不存在' }, 404);
|
||||
const input = c.req.valid('json');
|
||||
const err = policyError(input.policy);
|
||||
if (err) return c.json({ error: err }, 400);
|
||||
db.update(rules)
|
||||
.set({
|
||||
type: input.type,
|
||||
|
||||
Reference in New Issue
Block a user