diff --git a/2.ts b/2.ts index 9fa8c7a..48e8bab 100644 --- a/2.ts +++ b/2.ts @@ -1,108 +1,71 @@ -import { readLines } from "https://deno.land/std@0.157.0/io/buffer.ts"; +import { BufReader } from "https://deno.land/std@0.157.0/io/buffer.ts"; +import { ByteSet } from "https://deno.land/x/bytes@1.0.3/mod.ts"; +const QUERY_SIZE = 9; const PORT = 5588; -console.log(`Starting TCP listener on on 0.0.0.0:${PORT}`); -const clients = new Map(); +const listener = Deno.listen({ port: 5588 }); -const tEnc = new TextEncoder(); +console.log(`Listening on port ${PORT}`); -async function chatSession(conn: Deno.Conn) { - try { - let myNick: string | null = null; - await sendPrompt(conn); - for await (const line of readLines(conn)) { - console.debug("Received line:", line); - const message = line.trim(); - if (myNick == null) { - if (isLegalNick(message)) { - myNick = message; - await join(myNick, conn); - } else { - console.error("Illegal nick:", message); - break; - } - } else { - const conns: Deno.Conn[] = []; - for (const themConn of clients.keys()) { - if (themConn != conn) conns.push(themConn); - } - await send(conns, `[${myNick}] ${message}`); - } - } - } finally { - if (clients.has(conn)) { - try { - await disconnect(conn); - } catch (err) { - console.error("Failed to disconnect:", err); - } - } - try { - if (conn.writable) { - send(conn, "You are being disconnected..."); - } - } catch (err) { - console.error("Failed to send disconnect notice:", err); - } - } - try { - conn.close(); - } catch (err) { - console.error("Failed to close connection:", err); - } -} - -async function send( - connsArg: Deno.Conn | Array, - text: string, -) { - const conns = !Array.isArray(connsArg) ? [connsArg] : connsArg; - const messages: Promise[] = []; - const bytes = tEnc.encode(text + "\n"); - conns.forEach((conn) => messages.push(conn.write(bytes))); - return await Promise.all(messages); -} - -const broadcast = async (text: string) => await send([...clients.keys()], text); - -const LEGAL_NICK_REGEXP = /^[a-z0-9]+$/i; -const isLegalNick = (nick: string) => { - console.debug( - `Checking nick: ${nick} (Bytes: ${tEnc.encode(nick)})`, - ); - return LEGAL_NICK_REGEXP.exec(nick) != null; -}; - -const sendPrompt = async (conn: Deno.Conn) => { - console.debug("Sending prompt..."); - return await send(conn, "Who you be?"); -}; - -async function join(myNick: string, conn: Deno.Conn) { - const userList: string[] = []; - clients.forEach((nick, _) => userList.push(nick)); - await broadcast(`* ${myNick} joined`); - clients.set(conn, myNick); - await send(conn, `* users: ${userList.join(", ")}`); -} - -async function disconnect(conn: Deno.Conn) { - const myNick = clients.get(conn); - clients.delete(conn); - await broadcast(`* ${myNick} left`); -} - -for await (const conn of Deno.listen({ port: PORT })) { +for await (const conn of listener) { console.log("Connection established:", conn.remoteAddr); try { - chatSession(conn); + meansToAnEnd(conn); } catch (e) { - console.error( - "Exception occurred during chat session:", - conn.remoteAddr, - e, - ); + console.error(conn.remoteAddr, e); } console.log("Connection closed:", conn.remoteAddr); } + +async function meansToAnEnd(conn: Deno.Conn) { + try { + const prices = []; + for await (const query of queries(conn)) { + if (query == null) break; + const bs = ByteSet.from(query, "big"); + const queryChar = String.fromCharCode(bs.read.uint8()); + const a1 = bs.read.int32(); + const a2 = bs.read.int32(); + if (queryChar == "I") { + prices.push([a1, a2]); + } else if (queryChar == "Q") { + let numMatches = 0; + let sum = 0; + for (const [ts, price] of prices) { + if (ts < a1 || ts > a2) continue; + numMatches++; + sum += price; + } + let result = Math.floor(sum / numMatches); + if (isNaN(result)) result = 0; + console.log( + conn.remoteAddr, + `Result for ${prices.length} prices: ${sum} / ${numMatches} = ${result}`, + ); + const response = new ByteSet(4, "big"); + response.write.int32(result); + conn.write(response.buffer); + } + } + console.log("Done!"); + } catch (err) { + console.error("Error processing query:", err); + } +} + +function queries(conn: Deno.Conn) { + return { + async *[Symbol.asyncIterator]() { + const b = new Uint8Array(9); + const reader = new BufReader(conn, QUERY_SIZE); + try { + while (await reader.readFull(b) != null) { + yield b; + } + } catch (err) { + console.error("Error receiving query:", err); + } + }, + }; +}