feat: Implemented launching and downloading of roms

This is just an initial implementation lots of kings to iron out
This commit is contained in:
Simeon Radivoev 2026-02-19 16:10:29 +02:00
parent ef08fa6114
commit f15bf9a1e0
Signed by: simeonradivoev
GPG key ID: 7611A451D2A5D37A
117 changed files with 37776 additions and 1073 deletions

View file

@ -1,97 +1,12 @@
import z from "zod";
import { config } from "./settings";
import Elysia, { status } from "elysia";
import keytar from '@hackolade/keytar';
import { loginApiLoginPost } from "../../clients/romm";
import { CookieJar } from 'tough-cookie';
import FileCookieStore from 'tough-cookie-file-store';
import path from 'node:path';
import Elysia from "elysia";
import { config, jar } from "./app";
import games from "./games/games";
import platforms from "./games/platforms";
import auth from "./auth";
const fileCookieStore = new FileCookieStore(path.join(path.dirname(config.path), 'cookies.json'));
console.log("Cookie Jar Path Located At: ", fileCookieStore.filePath);
const jar = new CookieJar(fileCookieStore);
await login();
export async function logout ()
{
if (!config.has('rommAddress'))
{
return;
}
const rommAddress = config.get('rommAddress');
if (rommAddress)
{
console.log("Logging Out of ROMM");
try
{
await loginApiLoginPost({
baseUrl: rommAddress, headers: {
'cookie': await jar.getCookieString(rommAddress)
}
});
} catch (error)
{
console.error("Failed to logout of ROMM ", error);
}
}
}
async function login ()
{
if (!config.has('rommAddress') || !config.has('rommUser'))
{
return;
}
const rommAddress = config.get('rommAddress');
const rommUser = config.get('rommUser');
if (rommAddress && rommUser)
{
console.log("Logging In to ROMM");
const password = await keytar.getPassword('romm', 'gameflow');
const loginResponse = await loginApiLoginPost({ baseUrl: rommAddress, auth: `${rommUser}:${password}` });
loginResponse.response.headers.getSetCookie().map(c => jar.setCookie(c, rommAddress));
}
}
export const romm = new Elysia({ prefix: "/romm" })
.post('/login', async ({ body: { host, username, password } }) =>
{
if (config.has('rommAddress') && config.has('rommUser'))
{
await logout();
const oldRommAddress = config.get('rommAddress');
if (oldRommAddress)
{
const cookies = await jar.getCookies(oldRommAddress);
cookies.map(c => jar.store.removeCookie(c.domain, c.path, c.key));
}
}
config.set('rommAddress', host);
config.set('rommUser', username);
await keytar.setPassword('romm', 'gameflow', password);
await login();
return status(200);
}, { body: z.object({ host: z.url(), username: z.string(), password: z.string() }) })
.get('/login', async () =>
{
const credentials = await keytar.getPassword('romm', 'gameflow');
return { hasPassword: !!credentials };
}, { response: z.object({ hasPassword: z.boolean() }) })
.post('/logout', async () =>
{
await keytar.deletePassword('romm', 'gameflow');
await logout();
const rommAddress = config.get('rommAddress');
if (rommAddress)
{
const cookies = await jar.getCookies(rommAddress);
cookies.map(c => jar.store.removeCookie(c.domain, c.path, c.key));
}
return status(200);
})
export default new Elysia({ prefix: "/api/romm" })
.use([games, platforms, auth])
.all("/*", async ({ request, params, set }) =>
{
if (!config.has('rommAddress') && !config.get('rommAddress'))
@ -119,19 +34,6 @@ export const romm = new Elysia({ prefix: "/romm" })
redirect: 'manual', // avoid ROMM redirects
});
/*
if (rommResponse.status === 403 && config.has('rommUser'))
{
await login();
headers.set('cookie', await jar.getCookieString(rommUrl.href));
rommResponse = await fetch(url, {
method: request.method,
headers,
body: await request.arrayBuffer(),
redirect: 'manual', // avoid ROMM redirects
});
}*/
set.status = rommResponse.status;
rommResponse.headers.forEach((value, key) =>
{
@ -139,4 +41,5 @@ export const romm = new Elysia({ prefix: "/romm" })
});
return new Response(rommResponse.body, { status: rommResponse.status });
}).on('stop', logout);
}, { response: z.instanceof(Response) });