import { BufReader } from "https://deno.land/std@0.157.0/io/buffer.ts"; import { copy } from "https://deno.land/std@0.156.0/streams/conversion.ts"; const PORT = 5588; const PROXY_CHAT_SERVER = "chat.protohackers.com"; const PROXY_CHAT_PORT = 16963; const TONYS_ADDRESS = "7YWHMfk9JZe0LM0g1ZauHuiSxhI"; const tEnc = new TextEncoder(); console.log(`Starting TCP listener on on 0.0.0.0:${PORT}`); async function chatSession(conn: Deno.Conn) { const proxy = await Deno.connect({ hostname: PROXY_CHAT_SERVER, port: PROXY_CHAT_PORT, }); const closeOnDisconnect = () => { console.warn("Disconnected client"); try { proxy.close(); } catch (err) { console.error("Error closing proxy connection:", err); } try { conn.close(); } catch (err) { console.error("Error closing client connection:", err); } }; rewriteMessages(conn, proxy).catch((e) => e).finally(closeOnDisconnect); rewriteMessages(proxy, conn).catch((e) => e).finally(closeOnDisconnect); } const chatCommands = (reader: Deno.Conn) => ({ async *[Symbol.asyncIterator]() { let s = await BufReader.create(reader).readString("\n"); if (!s) return; while (s) { console.log(s); yield s; s = await BufReader.create(reader).readString("\n"); } }, }); async function rewriteMessages(reader: Deno.Conn, writer: Deno.Conn) { try { for await (const rawLine of chatCommands(reader)) { if (!rawLine || !rawLine.endsWith("\n")) throw "incomplete chat command"; const line = rawLine.trim(); console.debug("Line:", line); await writer.write(tEnc.encode(replaceAddresses(line) + "\n")); } } catch (err) { console.error("Error reading line:", err, { ...err }); throw err; } } function replaceAddresses(text: string): string { const result = text.split(" ").map((word) => replaceAddress(word)).join(" "); if (result != text) console.debug("replaced text:", result); return result; } function replaceAddress(word: string): string { const result = word.replace( /^7\w{25,34}$/i, TONYS_ADDRESS, ); if (word != result) console.debug("word:", word, "replaced:", result); return result; } for await (const conn of Deno.listen({ port: PORT })) { console.log("Connection established:", conn.remoteAddr); chatSession(conn); console.log("Connection closed:", conn.remoteAddr); }