import { BufReader, writeAll } from "./deps.ts";
export type Command = (string | number)[];export type Reply = string | number | null | Reply[];
const CRLF = "\r\n";const encoder = new TextEncoder();const decoder = new TextDecoder();
function removePrefix(line: string): string { return line.slice(1);}
async function readLine(bufReader: BufReader): Promise<string | null> { const result = await bufReader.readLine(); return decoder.decode(result?.line) ?? null;}
function createRequest(command: Command): string { let request = "*" + command.length + CRLF; for (const arg of command) { request += "$" + arg.toString().length + CRLF; request += arg + CRLF; } return request;}
async function writeRequest( redisConn: Deno.Conn, request: string,): Promise<void> { await writeAll(redisConn, encoder.encode(request));}
export async function writeCommand( redisConn: Deno.Conn, command: Command,): Promise<void> { await writeRequest(redisConn, createRequest(command));}
async function readReply(bufReader: BufReader): Promise<Reply> { const line = await readLine(bufReader); if (line === null) { return await Promise.reject("No response received from Redis server"); } switch (line.charAt(0)) { case "+": return removePrefix(line); case "-": return await Promise.reject(removePrefix(line)); case ":": return Number(removePrefix(line)); case "$": return Number(removePrefix(line)) === -1 ? null : await readReply(bufReader); case "*": { const length = Number(removePrefix(line)); if (length === -1) { return null; } const array: Reply[] = []; for (let i = 0; i < length; i++) { array.push(await readReply(bufReader)); } return array; } default: return line; }}
export async function sendCommand( redisConn: Deno.Conn, command: Command,): Promise<Reply> { await writeCommand(redisConn, command); return await readReply(new BufReader(redisConn));}
export async function pipelineCommands( redisConn: Deno.Conn, commands: Command[],): Promise<Reply[]> { const request = commands.map(createRequest).join(""); await writeRequest(redisConn, request); const bufReader = new BufReader(redisConn); const replies: Reply[] = []; for (let i = 0; i < commands.length; i++) { replies.push(await readReply(bufReader)); } return replies;}
export async function* listenReplies( redisConn: Deno.Conn,): AsyncIterable<Reply> { const bufReader = new BufReader(redisConn); while (true) { yield await readReply(bufReader); }}