Move everything in-tree (WIP)
This commit is contained in:
parent
96c4f9d800
commit
68178cee60
10
0.ts
Normal file
10
0.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { copy } from "https://deno.land/std@0.156.0/streams/conversion.ts";
|
||||||
|
|
||||||
|
const PORT = 5588;
|
||||||
|
|
||||||
|
console.log(`Listening on port ${PORT}`);
|
||||||
|
|
||||||
|
for await (const conn of Deno.listen({ port: PORT })) {
|
||||||
|
await copy(conn, conn);
|
||||||
|
conn.close();
|
||||||
|
}
|
69
1.ts
Normal file
69
1.ts
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import { JsonParseStream } from "https://deno.land/std@0.157.0/encoding/json/stream.ts";
|
||||||
|
import { TextLineStream } from "https://deno.land/std@0.156.0/streams/delimiter.ts";
|
||||||
|
|
||||||
|
const PORT = 5588;
|
||||||
|
const tEnc = new TextEncoder();
|
||||||
|
|
||||||
|
console.log(`Listening on port ${PORT}`);
|
||||||
|
for await (const conn of Deno.listen({ port: PORT })) {
|
||||||
|
console.log("Connection established:", conn.remoteAddr);
|
||||||
|
try {
|
||||||
|
for await (const request of requests(conn)) {
|
||||||
|
console.debug("Request:", request);
|
||||||
|
if (
|
||||||
|
request == null || typeof request != "object" ||
|
||||||
|
!("method" in request) || !("number" in request)
|
||||||
|
) {
|
||||||
|
throw "Invalid request";
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
request.method == "isPrime" &&
|
||||||
|
typeof request.number == "number"
|
||||||
|
) {
|
||||||
|
const response = {
|
||||||
|
method: "isPrime",
|
||||||
|
prime: isPrime(request.number),
|
||||||
|
};
|
||||||
|
console.debug("Response:", response);
|
||||||
|
await conn.write(tEnc.encode(JSON.stringify(response) + "\n"));
|
||||||
|
} else {
|
||||||
|
console.debug("Request malformed");
|
||||||
|
await conn.write(tEnc.encode("Malformed!\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(conn.remoteAddr, e);
|
||||||
|
} finally {
|
||||||
|
console.log("Connection closed:", conn.remoteAddr);
|
||||||
|
try {
|
||||||
|
conn.close();
|
||||||
|
} catch (_err) {
|
||||||
|
// connection already closed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPrime(n: number) {
|
||||||
|
if (!Number.isInteger(n)) return false;
|
||||||
|
for (let i = 2, s = Math.sqrt(n); i <= s; i++) if (n % i === 0) return false;
|
||||||
|
return n > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function requests(conn: Deno.Conn) {
|
||||||
|
try {
|
||||||
|
const readable = conn.readable
|
||||||
|
.pipeThrough(new TextDecoderStream())
|
||||||
|
.pipeThrough(new TextLineStream())
|
||||||
|
.pipeThrough(new JsonParseStream());
|
||||||
|
|
||||||
|
return {
|
||||||
|
async *[Symbol.asyncIterator]() {
|
||||||
|
for await (const data of readable) {
|
||||||
|
yield data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
108
2.ts
Normal file
108
2.ts
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
import { readLines } from "https://deno.land/std@0.157.0/io/buffer.ts";
|
||||||
|
|
||||||
|
const PORT = 5588;
|
||||||
|
console.log(`Starting TCP listener on on 0.0.0.0:${PORT}`);
|
||||||
|
|
||||||
|
const clients = new Map<Deno.Conn, string>();
|
||||||
|
|
||||||
|
const tEnc = new TextEncoder();
|
||||||
|
|
||||||
|
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<Deno.Conn>,
|
||||||
|
text: string,
|
||||||
|
) {
|
||||||
|
const conns = !Array.isArray(connsArg) ? [connsArg] : connsArg;
|
||||||
|
const messages: Promise<number>[] = [];
|
||||||
|
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 })) {
|
||||||
|
console.log("Connection established:", conn.remoteAddr);
|
||||||
|
try {
|
||||||
|
chatSession(conn);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(
|
||||||
|
"Exception occurred during chat session:",
|
||||||
|
conn.remoteAddr,
|
||||||
|
e,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
console.log("Connection closed:", conn.remoteAddr);
|
||||||
|
}
|
25
3.ts
Normal file
25
3.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
const PORT = 5588;
|
||||||
|
console.log(`Starting UDP listener on port ${PORT}`);
|
||||||
|
|
||||||
|
const tDec = new TextDecoder();
|
||||||
|
const tEnc = new TextEncoder();
|
||||||
|
|
||||||
|
const reservedData: Record<string, string> = { version: "KeyVal 1.0" };
|
||||||
|
const data = new Map<string, string>();
|
||||||
|
|
||||||
|
const listener = Deno.listenDatagram({ port: PORT, transport: "udp" });
|
||||||
|
|
||||||
|
for await (const [bytes, addr] of listener) {
|
||||||
|
const message = tDec.decode(bytes).trim();
|
||||||
|
console.debug("Datagram Received from:", addr, message);
|
||||||
|
if (message.includes("=")) {
|
||||||
|
const [key, val] = message.split("=", 1);
|
||||||
|
console.debug(`Setting ${key} to ${val}`);
|
||||||
|
if (!(key in reservedData)) data.set(key, val);
|
||||||
|
} else {
|
||||||
|
const value = reservedData[message] || data.get(message) || "";
|
||||||
|
const bytes = tEnc.encode(`${message}=${value}`);
|
||||||
|
console.debug(`Sending ${message}=${value}`);
|
||||||
|
await listener.send(bytes, addr);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue