From adea0ab070d76bbb4c2107c10e7e126984ad6e11 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Wed, 26 Aug 2026 16:30:47 +0700 Subject: [PATCH] =?UTF-8?q?fix(launcher):=20=D1=81=D0=BE=D0=B1=D0=B8=D1=80?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20ingest=20JSON=20MikroTik=20=D0=B2=D1=80?= =?UTF-8?q?=D1=83=D1=87=D0=BD=D1=83=D1=8E=20(ros-7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RouterOS serialize ломал тело POST. ros-7 пишет JSON строкой и печатает префикс при ошибке ingest. Co-authored-by: Cursor --- apps/api/scripts/censorcheck/launcher.rsc | 35 ++++++++++++----------- apps/api/scripts/ipregion/launcher.rsc | 35 ++++++++++++----------- apps/api/src/lib/ros-ingest.ts | 3 ++ apps/api/src/routes/launcher.test.ts | 8 +++--- 4 files changed, 45 insertions(+), 36 deletions(-) diff --git a/apps/api/scripts/censorcheck/launcher.rsc b/apps/api/scripts/censorcheck/launcher.rsc index f411d3e..7cd1c0d 100644 --- a/apps/api/scripts/censorcheck/launcher.rsc +++ b/apps/api/scripts/censorcheck/launcher.rsc @@ -6,7 +6,7 @@ :local vtToken "__VT_INGEST_TOKEN__" :local vtDaily "__VT_DAILY__" :local vtRemove "__VT_REMOVE_DAILY__" -:local launcherVer "ros-6" +:local launcherVer "ros-7" :local schedName "vt-cc" :local dstFile "vt-cc.rsc" @@ -112,7 +112,6 @@ :local sp2 :local codeStr :local n -:local item :foreach host in=$hosts do={ :set code 0 :do { @@ -142,25 +141,27 @@ :set code 0 } :put ($host . " " . $code) - :set item { service=$host; raw={ https={ ipv4={ status=$code } } } } - :set itemJson [:serialize to=json value=$item] + :set itemJson ("{\"service\":\"" . $host . "\",\"raw\":{\"https\":{\"ipv4\":{\"status\":" . $code . "}}}}") :if ([:len $resultJson] > 0) do={ :set resultJson ($resultJson . ",") } :set resultJson ($resultJson . $itemJson) } -:local probe { publicIp=$publicIp } -:if ([:len $hoster] > 0) do={ :set ($probe->"hoster") $hoster } - -:local meta {\ - schemaVersion=1;\ - runId=$runId;\ - probe=$probe;\ - launcherVersion=$launcherVer;\ - censorcheck={ version="ros"; mode="https" }\ +:local hosterJson "" +:if ([:len $hoster] > 0) do={ + :local esc "" + :local hi 0 + :while ($hi < [:len $hoster]) do={ + :local ch [:pick $hoster $hi ($hi + 1)] + :if ($ch = "\\") do={ :set esc ($esc . "\\\\") } else={ + :if ($ch = "\"") do={ :set esc ($esc . "\\\"") } else={ :set esc ($esc . $ch) } + } + :set hi ($hi + 1) + } + :set hosterJson (",\"hoster\":\"" . $esc . "\"") } -:local metaJson [:serialize to=json value=$meta] -:local json ([:pick $metaJson 0 ([:len $metaJson] - 1)] . ",\"results\":[" . $resultJson . "]}") -:local hdrs {"Content-Type: application/json"; ("Authorization: Bearer " . $vtToken)} +:if ([:len $resultJson] = 0) do={ :error "ingest: results пустой" } +:local json ("{\"schemaVersion\":1,\"runId\":\"" . $runId . "\",\"probe\":{\"publicIp\":\"" . $publicIp . "\"" . $hosterJson . "},\"launcherVersion\":\"" . $launcherVer . "\",\"censorcheck\":{\"version\":\"ros\",\"mode\":\"https\"},\"results\":[" . $resultJson . "]}") +:local hdrs ("Content-Type: application/json,Authorization: Bearer " . $vtToken) :put ("Отправляю ingest (" . [:len $json] . " B)...") :set ingestOk false :onerror err,attr in={ @@ -175,6 +176,7 @@ :if (([:typeof $attr] = "array") and ([:typeof ($attr->"data")] = "str") and ([:len ($attr->"data")] > 0)) do={ :put ($attr->"data") } + :if ([:len $json] > 120) do={ :put ([:pick $json 0 120] . "...") } else={ :put $json } } :if ($ingestOk = false) do={ :put "повтор ingest без src-address..." @@ -186,6 +188,7 @@ :if (([:typeof $attr2] = "array") and ([:typeof ($attr2->"data")] = "str") and ([:len ($attr2->"data")] > 0)) do={ :put ($attr2->"data") } + :if ([:len $json] > 120) do={ :put ([:pick $json 0 120] . "...") } else={ :put $json } } } diff --git a/apps/api/scripts/ipregion/launcher.rsc b/apps/api/scripts/ipregion/launcher.rsc index 5bc2ea9..582ee82 100644 --- a/apps/api/scripts/ipregion/launcher.rsc +++ b/apps/api/scripts/ipregion/launcher.rsc @@ -6,7 +6,7 @@ :local vtToken "__VT_INGEST_TOKEN__" :local vtDaily "__VT_DAILY__" :local vtRemove "__VT_REMOVE_DAILY__" -:local launcherVer "ros-6" +:local launcherVer "ros-7" :local schedName "vt-ic" :local dstFile "vt-ic.rsc" @@ -128,7 +128,6 @@ :local colo :local iata :local ci -:local item :foreach name in=$names do={ :set url "" :set method "get" @@ -259,25 +258,27 @@ } :put ($name . " " . $iso) - :set item { service=$name; ipv4=$iso } - :set itemJson [:serialize to=json value=$item] + :set itemJson ("{\"service\":\"" . $name . "\",\"ipv4\":\"" . $iso . "\"}") :if ([:len $resultJson] > 0) do={ :set resultJson ($resultJson . ",") } :set resultJson ($resultJson . $itemJson) } -:local probe { publicIp=$publicIp } -:if ([:len $hoster] > 0) do={ :set ($probe->"hoster") $hoster } - -:local meta {\ - schemaVersion=1;\ - runId=$runId;\ - probe=$probe;\ - launcherVersion=$launcherVer;\ - ipregion={ version="ros" }\ +:local hosterJson "" +:if ([:len $hoster] > 0) do={ + :local esc "" + :local hi 0 + :while ($hi < [:len $hoster]) do={ + :local ch [:pick $hoster $hi ($hi + 1)] + :if ($ch = "\\") do={ :set esc ($esc . "\\\\") } else={ + :if ($ch = "\"") do={ :set esc ($esc . "\\\"") } else={ :set esc ($esc . $ch) } + } + :set hi ($hi + 1) + } + :set hosterJson (",\"hoster\":\"" . $esc . "\"") } -:local metaJson [:serialize to=json value=$meta] -:local json ([:pick $metaJson 0 ([:len $metaJson] - 1)] . ",\"results\":[" . $resultJson . "]}") -:local hdrs {"Content-Type: application/json"; ("Authorization: Bearer " . $vtToken)} +:if ([:len $resultJson] = 0) do={ :error "ingest: results пустой" } +:local json ("{\"schemaVersion\":1,\"runId\":\"" . $runId . "\",\"probe\":{\"publicIp\":\"" . $publicIp . "\"" . $hosterJson . "},\"launcherVersion\":\"" . $launcherVer . "\",\"ipregion\":{\"version\":\"ros\"},\"results\":[" . $resultJson . "]}") +:local hdrs ("Content-Type: application/json,Authorization: Bearer " . $vtToken) :put ("Отправляю ingest (" . [:len $json] . " B)...") :set ingestOk false :onerror err,attr in={ @@ -292,6 +293,7 @@ :if (([:typeof $attr] = "array") and ([:typeof ($attr->"data")] = "str") and ([:len ($attr->"data")] > 0)) do={ :put ($attr->"data") } + :if ([:len $json] > 120) do={ :put ([:pick $json 0 120] . "...") } else={ :put $json } } :if ($ingestOk = false) do={ :put "повтор ingest без src-address..." @@ -303,6 +305,7 @@ :if (([:typeof $attr2] = "array") and ([:typeof ($attr2->"data")] = "str") and ([:len ($attr2->"data")] > 0)) do={ :put ($attr2->"data") } + :if ([:len $json] > 120) do={ :put ([:pick $json 0 120] . "...") } else={ :put $json } } } diff --git a/apps/api/src/lib/ros-ingest.ts b/apps/api/src/lib/ros-ingest.ts index 4e6223e..6ff1f18 100644 --- a/apps/api/src/lib/ros-ingest.ts +++ b/apps/api/src/lib/ros-ingest.ts @@ -5,6 +5,9 @@ */ export function coerceRouterosIngestBody(body: unknown): unknown { let value: unknown = body + if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { + value = value.toString('utf8') + } if (typeof value === 'string') { try { value = JSON.parse(value) diff --git a/apps/api/src/routes/launcher.test.ts b/apps/api/src/routes/launcher.test.ts index 96a311c..ffe58c1 100644 --- a/apps/api/src/routes/launcher.test.ts +++ b/apps/api/src/routes/launcher.test.ts @@ -128,7 +128,7 @@ describe('GET /cc.rsc RouterOS launcher', () => { expect(res.body).toContain('https://vt.shnt.top') expect(res.body).toContain('/tool fetch') expect(res.body).toContain('/api/integrations/censorcheck/runs') - expect(res.body).toContain('ros-6') + expect(res.body).toContain('ros-7') expect(res.body).toContain(':local vtDaily "no"') expect(res.body).toContain(':local vtRemove "no"') expect(res.body).toContain('/system scheduler') @@ -138,7 +138,7 @@ describe('GET /cc.rsc RouterOS launcher', () => { expect(res.body).toContain('src-address=$srcIp') expect(res.body).toContain(':onerror') expect(res.body).toContain('повтор ingest без src-address') - expect(res.body).toContain('\\"results\\":[') + expect(res.body).toContain('schemaVersion\\":1') expect(res.body).not.toContain('mark-routing') expect(res.body).not.toContain('vtIface') expect(res.body).not.toContain('\r') @@ -189,7 +189,7 @@ describe('GET /ic.rsc RouterOS launcher', () => { expect(res.body).toContain('https://vt.shnt.top') expect(res.body).toContain('/tool fetch') expect(res.body).toContain('/api/integrations/ipregion/runs') - expect(res.body).toContain('ros-6') + expect(res.body).toContain('ros-7') expect(res.body).toContain(':local vtDaily "no"') expect(res.body).toContain('ipinfo.io') expect(res.body).toContain('cloudflare cdn') @@ -198,7 +198,7 @@ describe('GET /ic.rsc RouterOS launcher', () => { expect(res.body).toContain('src-address=$srcIp') expect(res.body).toContain(':onerror') expect(res.body).toContain('повтор ingest без src-address') - expect(res.body).toContain('\\"results\\":[') + expect(res.body).toContain('schemaVersion\\":1') expect(res.body).not.toContain('mark-routing') expect(res.body).not.toContain('vtIface') expect(res.body).not.toContain('\r')