danceinterpreter-rs 0.6.1

Danceinterpreter in Rust
const MAX_QUEUE = 20;
const DEBUG_LOGGING = false;

let sessionId = Bun.randomUUIDv7();
let baseTime = 0;
let state = null;
let queue = [];

let requiredImages = [];
let loadedImages = [];
let sentImages = [];

const resetConnection = () => {
    state = null;
    queue = [];

    requiredImages = [];
    loadedImages = [];
    sentImages = [];

    sessionId = Bun.randomUUIDv7();
};

const getNeededImages = () => requiredImages.filter(i => !loadedImages.includes(i));

const onUpdateState = () => {
    requiredImages = [
        state.deck0content.filePath,
        state.deck1content.filePath,
        state.deck2content.filePath,
        state.deck3content.filePath,
    ].filter(i => i);
    loadedImages = loadedImages.filter(i => requiredImages.includes(i));
    onChangeNeededImages();

    console.log(state);
};

const onChangeNeededImages = () => {
    const neededImages = getNeededImages();
    const newImages = neededImages.filter(i => !sentImages.includes(i));

    if (newImages.length > 0)
        console.log("needed images changed");

    for (const img of newImages)
        server.publish("cover", img);

    sentImages = neededImages;
};

const server = Bun.serve({
    port: 8080,
    routes: {
        "/connect": () => new Response(JSON.stringify({
            sessionId,
            debugLogging: DEBUG_LOGGING,
        })),
        "/init": {
            POST: async req => {
                const data = await req.json();

                if (data.sessionId === sessionId) {
                    baseTime = data.timestamp;
                    state = data.state;

                    for (const update in queue)
                        Object.apply(state, update);
                    queue = [];

                    onUpdateState();
                }

                return new Response(sessionId);
            },
        },
        "/update/:id": {
            POST: async req => {
                const data = await req.json();

                if (data.sessionId === sessionId) {
                    if (!state) {
                        queue.push(data.state);

                        if (queue.length > MAX_QUEUE)
                            resetConnection();
                    } else {
                        state[req.params.id] = data.state;
                        onUpdateState();
                    }
                }

                return new Response(sessionId);
            },
        },
        "/cover": {
            GET: async req => {
                if (server.upgrade(req))
                    return;

                return new Response("expected websocket connection", { status: 400 });
            },
            POST: async req => {
                const { searchParams } = URL.parse(req.url);
                const path = searchParams.get("path");
                if (!path)
                    return new Response("'path' query param missing", { status: 400 });

                const data = await req.blob();
                loadedImages.push(path);

                console.log(`image "${path}" received`);

                const file = Bun.file(`./${Bun.randomUUIDv7()}.bin`);
                await Bun.write(file, data);
                return new Response("OK");
            },
        },
        "/log": {
            POST: async req => {
                if (req.body) console.log(`[log] ${await req.text()}`);
                return new Response("OK");
            }
        },
        "/*": async req => {
            console.log(`${req.method}\t${req.url}`);
            if (req.body) console.log(await req.text());

            return new Response("OK");
        },
    },

    async fetch(req) {
        console.log(`${req.method}\t${req.url}`);
        if (req.body) console.log(await req.text());

        return new Response("Not Found", { status: 404 });
    },

    websocket: {
        open(ws) {
            console.log("web socket connected");

            for (const img of sentImages)
                ws.send(img);

            ws.subscribe("cover");
        },
        close() {
            console.log("web socket disconnected");
        },
    },
});

console.log(`Listening on ${server.url}`);