diff --git a/plans/002-ny-import-tunnel-selection-compat.md b/plans/002-ny-import-tunnel-selection-compat.md new file mode 100644 index 0000000..e0efebf --- /dev/null +++ b/plans/002-ny-import-tunnel-selection-compat.md @@ -0,0 +1,7 @@ +- [x] Review current forward import flow and confirm ny import uses tunnel selection +- [x] Define ny compatibility update with tunnel-first behavior and auto port assignment fallback +- [x] Update ny parser to accept alias fields and optional `listen_port` +- [x] Keep import execution bound to selected tunnel and remove entry-selection dependency from ux copy +- [x] Update ny import help text to document optional port auto assignment +- [x] Add parser tests for alias-field compatibility and missing-port auto assignment +- [x] Validate updated import parser tests locally diff --git a/vite-frontend/src/pages/forward.tsx b/vite-frontend/src/pages/forward.tsx index 37002c0..714369a 100644 --- a/vite-frontend/src/pages/forward.tsx +++ b/vite-frontend/src/pages/forward.tsx @@ -4620,10 +4620,10 @@ export default function ForwardPage() { ) : ( <>
- ny格式:JSON对象,支持多个目标地址(负载均衡) + ny格式:JSON对象,支持多个目标地址(负载均衡),按所选隧道导入
- 格式:{"dest":["地址:端口"],"listen_port":端口,"name":"名称"} + 格式:{"dest":["地址:端口"],"listen_port":端口,"name":"名称"}(listen_port可省略,自动分配端口)
> )} @@ -4696,7 +4696,7 @@ export default function ForwardPage() { placeholder={ importFormat === "flvx" ? "请输入要导入的转发数据,格式:目标地址|转发名称|入口端口" - : '请输入ny格式数据,每行一个JSON对象,如:{"dest":["1.2.3.4:80"],"listen_port":8080,"name":"转发1"}' + : '请输入ny格式数据,每行一个JSON对象,如:{"dest":["1.2.3.4:80"],"listen_port":8080,"name":"转发1"};listen_port可省略自动分配' } value={importData} variant="flat" diff --git a/vite-frontend/src/pages/forward/import-format.test.ts b/vite-frontend/src/pages/forward/import-format.test.ts index ce656c6..4a9bb54 100644 --- a/vite-frontend/src/pages/forward/import-format.test.ts +++ b/vite-frontend/src/pages/forward/import-format.test.ts @@ -46,6 +46,33 @@ test("parseNyFormatData returns validation errors for invalid fields", () => { assert.match(result[1].error || "", /目标地址格式错误/); }); +test("parseNyFormatData allows missing listen_port for auto assignment", () => { + const input = '{"dest":["1.1.1.1:1000"],"name":"No Port"}'; + + const result = parseNyFormatData(input); + + assert.equal(result.length, 1); + assert.equal(result[0].error, undefined); + assert.equal(result[0].parsed?.listen_port, null); +}); + +test("parseNyFormatData supports ny alias fields", () => { + const input = + '{"dst":["2.2.2.2:2000"],"listenPort":"3000","forward_name":"Alias A"}\n{"target":"3.3.3.3:4000,4.4.4.4:5000","port":6000,"forwardName":"Alias B"}'; + + const result = parseNyFormatData(input); + + assert.equal(result.length, 2); + assert.equal(result[0].error, undefined); + assert.equal(result[1].error, undefined); + assert.deepEqual(result[0].parsed?.dest, ["2.2.2.2:2000"]); + assert.equal(result[0].parsed?.listen_port, 3000); + assert.equal(result[0].parsed?.name, "Alias A"); + assert.deepEqual(result[1].parsed?.dest, ["3.3.3.3:4000", "4.4.4.4:5000"]); + assert.equal(result[1].parsed?.listen_port, 6000); + assert.equal(result[1].parsed?.name, "Alias B"); +}); + test("convertNyItemToForwardInput maps ny fields correctly", () => { const mapped = convertNyItemToForwardInput({ dest: ["1.1.1.1:1111", "2.2.2.2:2222"], @@ -60,3 +87,18 @@ test("convertNyItemToForwardInput maps ny fields correctly", () => { strategy: "fifo", }); }); + +test("convertNyItemToForwardInput keeps null inPort for auto assignment", () => { + const mapped = convertNyItemToForwardInput({ + dest: ["1.1.1.1:1111"], + listen_port: null, + name: "No Port", + }); + + assert.deepEqual(mapped, { + name: "No Port", + inPort: null, + remoteAddr: "1.1.1.1:1111", + strategy: "fifo", + }); +}); diff --git a/vite-frontend/src/pages/forward/import-format.ts b/vite-frontend/src/pages/forward/import-format.ts index dff602a..8fadd6e 100644 --- a/vite-frontend/src/pages/forward/import-format.ts +++ b/vite-frontend/src/pages/forward/import-format.ts @@ -1,6 +1,6 @@ export interface NyImportItem { dest: string[]; - listen_port: number; + listen_port: number | null; name: string; } @@ -12,6 +12,70 @@ export interface ParsedNyImportLine { const ADDRESS_PATTERN = /^[^:]+:\d+$/; +const getAliasField = ( + item: Record