fix(launcher): собирать ingest JSON MikroTik вручную (ros-7)
Docker / build (push) Failing after 23s

RouterOS serialize ломал тело POST. ros-7 пишет JSON строкой и печатает префикс при ошибке ingest.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-08-26 16:30:47 +07:00
co-authored by Cursor
parent f53ca1ed7d
commit adea0ab070
4 changed files with 45 additions and 36 deletions
+19 -16
View File
@@ -6,7 +6,7 @@
:local vtToken "__VT_INGEST_TOKEN__" :local vtToken "__VT_INGEST_TOKEN__"
:local vtDaily "__VT_DAILY__" :local vtDaily "__VT_DAILY__"
:local vtRemove "__VT_REMOVE_DAILY__" :local vtRemove "__VT_REMOVE_DAILY__"
:local launcherVer "ros-6" :local launcherVer "ros-7"
:local schedName "vt-cc" :local schedName "vt-cc"
:local dstFile "vt-cc.rsc" :local dstFile "vt-cc.rsc"
@@ -112,7 +112,6 @@
:local sp2 :local sp2
:local codeStr :local codeStr
:local n :local n
:local item
:foreach host in=$hosts do={ :foreach host in=$hosts do={
:set code 0 :set code 0
:do { :do {
@@ -142,25 +141,27 @@
:set code 0 :set code 0
} }
:put ($host . " " . $code) :put ($host . " " . $code)
:set item { service=$host; raw={ https={ ipv4={ status=$code } } } } :set itemJson ("{\"service\":\"" . $host . "\",\"raw\":{\"https\":{\"ipv4\":{\"status\":" . $code . "}}}}")
:set itemJson [:serialize to=json value=$item]
:if ([:len $resultJson] > 0) do={ :set resultJson ($resultJson . ",") } :if ([:len $resultJson] > 0) do={ :set resultJson ($resultJson . ",") }
:set resultJson ($resultJson . $itemJson) :set resultJson ($resultJson . $itemJson)
} }
:local probe { publicIp=$publicIp } :local hosterJson ""
:if ([:len $hoster] > 0) do={ :set ($probe->"hoster") $hoster } :if ([:len $hoster] > 0) do={
:local esc ""
:local meta {\ :local hi 0
schemaVersion=1;\ :while ($hi < [:len $hoster]) do={
runId=$runId;\ :local ch [:pick $hoster $hi ($hi + 1)]
probe=$probe;\ :if ($ch = "\\") do={ :set esc ($esc . "\\\\") } else={
launcherVersion=$launcherVer;\ :if ($ch = "\"") do={ :set esc ($esc . "\\\"") } else={ :set esc ($esc . $ch) }
censorcheck={ version="ros"; mode="https" }\ }
:set hi ($hi + 1)
}
:set hosterJson (",\"hoster\":\"" . $esc . "\"")
} }
:local metaJson [:serialize to=json value=$meta] :if ([:len $resultJson] = 0) do={ :error "ingest: results пустой" }
:local json ([:pick $metaJson 0 ([:len $metaJson] - 1)] . ",\"results\":[" . $resultJson . "]}") :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)} :local hdrs ("Content-Type: application/json,Authorization: Bearer " . $vtToken)
:put ("Отправляю ingest (" . [:len $json] . " B)...") :put ("Отправляю ingest (" . [:len $json] . " B)...")
:set ingestOk false :set ingestOk false
:onerror err,attr in={ :onerror err,attr in={
@@ -175,6 +176,7 @@
:if (([:typeof $attr] = "array") and ([:typeof ($attr->"data")] = "str") and ([:len ($attr->"data")] > 0)) do={ :if (([:typeof $attr] = "array") and ([:typeof ($attr->"data")] = "str") and ([:len ($attr->"data")] > 0)) do={
:put ($attr->"data") :put ($attr->"data")
} }
:if ([:len $json] > 120) do={ :put ([:pick $json 0 120] . "...") } else={ :put $json }
} }
:if ($ingestOk = false) do={ :if ($ingestOk = false) do={
:put "повтор ingest без src-address..." :put "повтор ingest без src-address..."
@@ -186,6 +188,7 @@
:if (([:typeof $attr2] = "array") and ([:typeof ($attr2->"data")] = "str") and ([:len ($attr2->"data")] > 0)) do={ :if (([:typeof $attr2] = "array") and ([:typeof ($attr2->"data")] = "str") and ([:len ($attr2->"data")] > 0)) do={
:put ($attr2->"data") :put ($attr2->"data")
} }
:if ([:len $json] > 120) do={ :put ([:pick $json 0 120] . "...") } else={ :put $json }
} }
} }
+19 -16
View File
@@ -6,7 +6,7 @@
:local vtToken "__VT_INGEST_TOKEN__" :local vtToken "__VT_INGEST_TOKEN__"
:local vtDaily "__VT_DAILY__" :local vtDaily "__VT_DAILY__"
:local vtRemove "__VT_REMOVE_DAILY__" :local vtRemove "__VT_REMOVE_DAILY__"
:local launcherVer "ros-6" :local launcherVer "ros-7"
:local schedName "vt-ic" :local schedName "vt-ic"
:local dstFile "vt-ic.rsc" :local dstFile "vt-ic.rsc"
@@ -128,7 +128,6 @@
:local colo :local colo
:local iata :local iata
:local ci :local ci
:local item
:foreach name in=$names do={ :foreach name in=$names do={
:set url "" :set url ""
:set method "get" :set method "get"
@@ -259,25 +258,27 @@
} }
:put ($name . " " . $iso) :put ($name . " " . $iso)
:set item { service=$name; ipv4=$iso } :set itemJson ("{\"service\":\"" . $name . "\",\"ipv4\":\"" . $iso . "\"}")
:set itemJson [:serialize to=json value=$item]
:if ([:len $resultJson] > 0) do={ :set resultJson ($resultJson . ",") } :if ([:len $resultJson] > 0) do={ :set resultJson ($resultJson . ",") }
:set resultJson ($resultJson . $itemJson) :set resultJson ($resultJson . $itemJson)
} }
:local probe { publicIp=$publicIp } :local hosterJson ""
:if ([:len $hoster] > 0) do={ :set ($probe->"hoster") $hoster } :if ([:len $hoster] > 0) do={
:local esc ""
:local meta {\ :local hi 0
schemaVersion=1;\ :while ($hi < [:len $hoster]) do={
runId=$runId;\ :local ch [:pick $hoster $hi ($hi + 1)]
probe=$probe;\ :if ($ch = "\\") do={ :set esc ($esc . "\\\\") } else={
launcherVersion=$launcherVer;\ :if ($ch = "\"") do={ :set esc ($esc . "\\\"") } else={ :set esc ($esc . $ch) }
ipregion={ version="ros" }\ }
:set hi ($hi + 1)
}
:set hosterJson (",\"hoster\":\"" . $esc . "\"")
} }
:local metaJson [:serialize to=json value=$meta] :if ([:len $resultJson] = 0) do={ :error "ingest: results пустой" }
:local json ([:pick $metaJson 0 ([:len $metaJson] - 1)] . ",\"results\":[" . $resultJson . "]}") :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)} :local hdrs ("Content-Type: application/json,Authorization: Bearer " . $vtToken)
:put ("Отправляю ingest (" . [:len $json] . " B)...") :put ("Отправляю ingest (" . [:len $json] . " B)...")
:set ingestOk false :set ingestOk false
:onerror err,attr in={ :onerror err,attr in={
@@ -292,6 +293,7 @@
:if (([:typeof $attr] = "array") and ([:typeof ($attr->"data")] = "str") and ([:len ($attr->"data")] > 0)) do={ :if (([:typeof $attr] = "array") and ([:typeof ($attr->"data")] = "str") and ([:len ($attr->"data")] > 0)) do={
:put ($attr->"data") :put ($attr->"data")
} }
:if ([:len $json] > 120) do={ :put ([:pick $json 0 120] . "...") } else={ :put $json }
} }
:if ($ingestOk = false) do={ :if ($ingestOk = false) do={
:put "повтор ingest без src-address..." :put "повтор ingest без src-address..."
@@ -303,6 +305,7 @@
:if (([:typeof $attr2] = "array") and ([:typeof ($attr2->"data")] = "str") and ([:len ($attr2->"data")] > 0)) do={ :if (([:typeof $attr2] = "array") and ([:typeof ($attr2->"data")] = "str") and ([:len ($attr2->"data")] > 0)) do={
:put ($attr2->"data") :put ($attr2->"data")
} }
:if ([:len $json] > 120) do={ :put ([:pick $json 0 120] . "...") } else={ :put $json }
} }
} }
+3
View File
@@ -5,6 +5,9 @@
*/ */
export function coerceRouterosIngestBody(body: unknown): unknown { export function coerceRouterosIngestBody(body: unknown): unknown {
let value: unknown = body let value: unknown = body
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
value = value.toString('utf8')
}
if (typeof value === 'string') { if (typeof value === 'string') {
try { try {
value = JSON.parse(value) value = JSON.parse(value)
+4 -4
View File
@@ -128,7 +128,7 @@ describe('GET /cc.rsc RouterOS launcher', () => {
expect(res.body).toContain('https://vt.shnt.top') expect(res.body).toContain('https://vt.shnt.top')
expect(res.body).toContain('/tool fetch') expect(res.body).toContain('/tool fetch')
expect(res.body).toContain('/api/integrations/censorcheck/runs') 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 vtDaily "no"')
expect(res.body).toContain(':local vtRemove "no"') expect(res.body).toContain(':local vtRemove "no"')
expect(res.body).toContain('/system scheduler') 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('src-address=$srcIp')
expect(res.body).toContain(':onerror') expect(res.body).toContain(':onerror')
expect(res.body).toContain('повтор ingest без src-address') 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('mark-routing')
expect(res.body).not.toContain('vtIface') expect(res.body).not.toContain('vtIface')
expect(res.body).not.toContain('\r') 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('https://vt.shnt.top')
expect(res.body).toContain('/tool fetch') expect(res.body).toContain('/tool fetch')
expect(res.body).toContain('/api/integrations/ipregion/runs') 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(':local vtDaily "no"')
expect(res.body).toContain('ipinfo.io') expect(res.body).toContain('ipinfo.io')
expect(res.body).toContain('cloudflare cdn') 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('src-address=$srcIp')
expect(res.body).toContain(':onerror') expect(res.body).toContain(':onerror')
expect(res.body).toContain('повтор ingest без src-address') 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('mark-routing')
expect(res.body).not.toContain('vtIface') expect(res.body).not.toContain('vtIface')
expect(res.body).not.toContain('\r') expect(res.body).not.toContain('\r')