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"}⏎
|