From 4e57c85f628c62094d805a604772ca7eb48a8cc1 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Thu, 14 Nov 2024 11:36:03 -0800 Subject: [PATCH] Do a dance to handle the docker "hijack" message --- impls/node-protocolv2/client.ts | 19 ++++++++++++++++++- impls/node/client.ts | 19 ++++++++++++++++++- impls/python/client.py | 11 ++++++++++- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/impls/node-protocolv2/client.ts b/impls/node-protocolv2/client.ts index fcba135..94137b5 100644 --- a/impls/node-protocolv2/client.ts +++ b/impls/node-protocolv2/client.ts @@ -71,7 +71,24 @@ const handles = new Map< >(); for await (const line of rl) { - const { id, init, payload, proc } = JSON.parse(line); + const { id, init, payload, proc } = (() => { + try { + return JSON.parse(line); + } catch (e) { + // Sometimes docker injects this into the stream: + // {"hijack":true,"stream":true,"stdin":true,"stdout":true,"stderr":true}{"type": "invoke", ... + const match = e.message.match(/line (\d*) column (\d*)/); + if (!!match) { + const offset = parseInt(match['2'], 10); + const first = JSON.parse(line.substring(0, offset)); + assert( + 'hijack' in first, + 'The only syntax errors that we expect are that Docker jams stuff into the stream', + ); + return JSON.parse(line.substring(offset)); + } + } + })(); switch (proc) { case 'kv.set': { diff --git a/impls/node/client.ts b/impls/node/client.ts index 08da044..d97225c 100644 --- a/impls/node/client.ts +++ b/impls/node/client.ts @@ -61,7 +61,24 @@ const rl = readline.createInterface({ const handles = new Map>(); for await (const line of rl) { - const { id, init, payload, proc } = JSON.parse(line); + const { id, init, payload, proc } = (() => { + try { + return JSON.parse(line); + } catch (e) { + // Sometimes docker injects this into the stream: + // {"hijack":true,"stream":true,"stdin":true,"stdout":true,"stderr":true}{"type": "invoke", ... + const match = e.message.match(/line (\d*) column (\d*)/); + if (!!match) { + const offset = parseInt(match['2'], 10); + const first = JSON.parse(line.substring(0, offset)); + assert( + 'hijack' in first, + 'The only syntax errors that we expect are that Docker jams stuff into the stream', + ); + return JSON.parse(line.substring(offset)); + } + } + })(); switch (proc) { case 'kv.set': { diff --git a/impls/python/client.py b/impls/python/client.py index 116aa7c..289c185 100644 --- a/impls/python/client.py +++ b/impls/python/client.py @@ -71,7 +71,16 @@ async def process_commands(): if not line: break - action = json.loads(line) + try: + action = json.loads(line) + except json.JSONDecodeError as e: + # Sometimes docker injects this into the stream: + # {"hijack":true,"stream":true,"stdin":true,"stdout":true,"stderr":true}{"type": "invoke", ... + offset = e.colno - 1 + first = json.loads(line[0:offset]) + assert "hijack" in first + action = json.loads(line[offset:]) + if not action: print("FATAL: invalid command", line) sys.exit(1)