150 lines
4.9 KiB
TypeScript
150 lines
4.9 KiB
TypeScript
|
import { catcher, catcher_async, squish_option } from "utils";
|
|||
|
import { Conversation, Database, Message, Preset } from "types";
|
|||
|
import { Option } from "optionals";
|
|||
|
import { URL } from "utils";
|
|||
|
|
|||
|
const DB_PATH = "./db.json";
|
|||
|
|
|||
|
export async function get_db_obj(): Promise<Option<Database>> {
|
|||
|
const text = await catcher_async(() => Deno.readTextFile(DB_PATH));
|
|||
|
const db = text.map(db_text =>
|
|||
|
catcher(() => JSON.parse(db_text) as Database)
|
|||
|
);
|
|||
|
return squish_option(db);
|
|||
|
}
|
|||
|
|
|||
|
export async function get_message(id: string): Promise<Option<Message>> {
|
|||
|
return (await get_db_obj()).map(db => db.messages[id]);
|
|||
|
}
|
|||
|
|
|||
|
export async function get_conversation(
|
|||
|
id: string
|
|||
|
): Promise<Option<Conversation>> {
|
|||
|
return (await get_db_obj()).map(db => db.conversations[id]);
|
|||
|
}
|
|||
|
|
|||
|
async function save_db(db: Database) {
|
|||
|
await Deno.writeTextFile(DB_PATH, JSON.stringify(db));
|
|||
|
}
|
|||
|
|
|||
|
export function new_conversation(
|
|||
|
name: string,
|
|||
|
description: string
|
|||
|
): Promise<Option<string>> {
|
|||
|
return catcher_async(async () => {
|
|||
|
const db = (await get_db_obj()).unwrap();
|
|||
|
|
|||
|
const id = abc_number(db.conversation_id);
|
|||
|
db.conversation_id++;
|
|||
|
db.conversations[id] = { name, description, messages: [], presets: {} };
|
|||
|
db.conversations[id].presets.default = { fg: "black" };
|
|||
|
db.conversations[id].presets.page = { fg: "black", bg: "white" };
|
|||
|
db.conversations[id].presets.box = { fg: "black", bg: "white" };
|
|||
|
|
|||
|
await save_db(db);
|
|||
|
return id;
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
export function add_preset(
|
|||
|
name: string,
|
|||
|
{ fg, bg, font }: Preset,
|
|||
|
conv_id: string
|
|||
|
) {
|
|||
|
return catcher_async(async () => {
|
|||
|
const db = (await get_db_obj()).unwrap();
|
|||
|
const conv = db.conversations[conv_id];
|
|||
|
if (!conv.presets) {
|
|||
|
conv.presets = {};
|
|||
|
}
|
|||
|
conv.presets[name] = { fg, bg, font };
|
|||
|
|
|||
|
await save_db(db);
|
|||
|
return name;
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
export function orphan_message(message: Message): Promise<Option<string>> {
|
|||
|
return catcher_async(async () => {
|
|||
|
const db = (await get_db_obj()).unwrap();
|
|||
|
|
|||
|
const id = abc_number(db.message_id);
|
|||
|
db.message_id++;
|
|||
|
db.messages[id] = message;
|
|||
|
|
|||
|
await save_db(db);
|
|||
|
return id;
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
export function message_under(
|
|||
|
message: Message,
|
|||
|
conv_id: string
|
|||
|
): Promise<Option<string>> {
|
|||
|
return catcher_async(async () => {
|
|||
|
const new_msg_id = (await orphan_message(message)).unwrap();
|
|||
|
const db = (await get_db_obj()).unwrap();
|
|||
|
if (!db.conversations[conv_id]) {
|
|||
|
throw {};
|
|||
|
}
|
|||
|
db.conversations[conv_id].messages.push(new_msg_id);
|
|||
|
|
|||
|
await save_db(db);
|
|||
|
return new_msg_id;
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
function abc_number(n: number): string {
|
|||
|
let x = n.toString(26);
|
|||
|
for (let i = 25; i >= 0; i--) {
|
|||
|
const from = i.toString(26);
|
|||
|
const to = (i + 10).toString(36);
|
|||
|
x = x.replaceAll(from, to);
|
|||
|
}
|
|||
|
return x;
|
|||
|
}
|
|||
|
|
|||
|
export async function fetch_db(): Promise<Option<Database>> {
|
|||
|
const db_response = await catcher_async(
|
|||
|
async () => await fetch(`${URL}/api/db`).then(r => r.json())
|
|||
|
);
|
|||
|
return db_response.map(db => db.val);
|
|||
|
}
|
|||
|
|
|||
|
// export type Preset = {
|
|||
|
// fg: string;
|
|||
|
// bg: string;
|
|||
|
// font?: string;
|
|||
|
// };
|
|||
|
|
|||
|
//TODO: AS TEMPTING AS IT MIGHT BE, DO NOT JUST HAVE A save_db FUNCTION THAT STORES A SERIALIZED OBJECT
|
|||
|
//TODO: THAT IS JUST *BEGGING* FOR CONCURRENCY ERRORS
|
|||
|
//TODO: INSTEAD HAVE A SMALL SET OF FUNCTIONS THAT DO SPECIFIC THINGS
|
|||
|
|
|||
|
//TODO: it might actually be easier to use an actual db
|
|||
|
|
|||
|
// toy-network on main [✘!?] via v17.4.0 took 1m10s
|
|||
|
// ❯ curl --request PUT localhost:8000/api/conv -d '{"name": "test", "description": "curl test", "fg": "red", "bg": "blue"}'
|
|||
|
// "a"⏎
|
|||
|
// toy-network on main [✘!?] via v17.4.0
|
|||
|
// ❯ curl --request PUT localhost:8000/api/conv/a -d '{"content": "hello", "font": "Comic Sans MS"}'
|
|||
|
// {}⏎
|
|||
|
// toy-network on main [✘!?] via v17.4.0
|
|||
|
// ❯ curl --request PUT localhost:8000/api/conv/a -d '{"content": "hello", "font": "Comic Sans MS"}'
|
|||
|
// {"val":"c"}⏎
|
|||
|
// toy-network on main [✘!?] via v17.4.0
|
|||
|
// ❯ curl --request PUT localhost:8000/api/conv/a -d '{"content": "hello", "font": "Comic Sans MS"}'
|
|||
|
// {"val":"c"}⏎
|
|||
|
// toy-network on main [✘!?] via v17.4.0
|
|||
|
// ❯ curl --request PUT localhost:8000/api/conv/a -d '{"content": "yay", "font": "cursive", "fg": "rebeccapurple"}'
|
|||
|
// {"val":"d"}⏎
|
|||
|
// toy-network on main [✘!?] via v17.4.0
|
|||
|
// ❯ curl --request PUT localhost:8000/api/conv/a -d '{"content": "serif", "font": "serif", "fg": "rebeccapurple"}'
|
|||
|
// {"val":"e"}⏎
|
|||
|
// toy-network on main [✘!?] via v17.4.0
|
|||
|
// ❯ curl --request PUT localhost:8000/api/conv/a -d '{"content": "\\"normal\\"", "fg": "rebeccapurple"}'
|
|||
|
// {"val":"f"}⏎
|
|||
|
// toy-network on main [✘!?] via v17.4.0
|
|||
|
// ❯ curl --request PUT localhost:8000/api/conv/a -d '{"content": "contrast", "bg": "black", "fg": "white"}'
|
|||
|
// {"val":"g"}⏎
|