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/src/river_python_test/client.py b/impls/python/src/river_python_test/client.py index 08793ee..1920ccb 100644 --- a/impls/python/src/river_python_test/client.py +++ b/impls/python/src/river_python_test/client.py @@ -72,7 +72,16 @@ async def process_commands() -> None: 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)