feat: Implemented public plugin system accessible from the store.
feat: Implemented external ryujinx integration plugin refactor: moved sdk types and schemas to own workspace package fix: Fixed emulator launch with no game
This commit is contained in:
parent
9051834ace
commit
38cb752552
124 changed files with 1918 additions and 1067 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import z from "zod";
|
||||
import { IJob, JobContext } from "../task-queue";
|
||||
import { IJob, JobContext } from "../../../packages/gameflow-sdk/task-queue";
|
||||
import { config, plugins } from "../app";
|
||||
import { simulateProgress } from "@/bun/utils";
|
||||
import { Downloader } from "@/bun/utils/downloader";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { EmulatorPackageType } from "@/shared/constants";
|
||||
import { EmulatorPackageType } from '@simeonradivoev/gameflow-sdk/shared';
|
||||
import { getStoreEmulatorPackage } from "../store/services/gamesService";
|
||||
import { IJob, JobContext } from "../task-queue";
|
||||
import { IJob, JobContext } from "../../../packages/gameflow-sdk/task-queue";
|
||||
import z from "zod";
|
||||
import { config, plugins } from "../app";
|
||||
import path from 'node:path';
|
||||
|
|
@ -12,7 +12,7 @@ import { simulateProgress } from "@/bun/utils";
|
|||
import { path7za } from "7zip-bin";
|
||||
import { getEmulatorDownload, getEmulatorPath } from "../store/services/emulatorsService";
|
||||
import { $ } from "bun";
|
||||
import { EmulatorSourceEntryType } from "@/shared/types";
|
||||
import { EmulatorSourceEntryType } from "@simeonradivoev/gameflow-sdk/shared";
|
||||
|
||||
type EmulatorDownloadStates = "download" | "extract";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { eq, or } from "drizzle-orm";
|
||||
import { db, plugins } from "../app";
|
||||
import { createLocalGame } from "../games/services/utils";
|
||||
import { IJob, JobContext } from "../task-queue";
|
||||
import { IJob, JobContext } from "../../../packages/gameflow-sdk/task-queue";
|
||||
import * as schema from "@schema/app";
|
||||
import z from "zod";
|
||||
import { GameLookup } from "@/shared/types";
|
||||
import { GameLookup } from "@simeonradivoev/gameflow-sdk/shared";
|
||||
|
||||
export class ImportJob implements IJob<z.infer<typeof ImportJob.dataSchema>, string>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { IJob, JobContext } from "../task-queue";
|
||||
import { IJob, JobContext } from "../../../packages/gameflow-sdk/task-queue";
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { config, events, plugins } from "../app";
|
||||
|
|
@ -11,7 +11,7 @@ import { ensureDir, move } from "fs-extra";
|
|||
import { path7za } from "7zip-bin";
|
||||
import StreamZip from 'node-stream-zip';
|
||||
import { which } from "bun";
|
||||
import { DownloadInfo } from "@/shared/types";
|
||||
import { DownloadInfo } from "@simeonradivoev/gameflow-sdk/shared";
|
||||
|
||||
interface JobConfig
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import TwitchLoginJob from "./twitch-login-job";
|
|||
import UpdateStoreJob from "./update-store";
|
||||
import { EmulatorDownloadJob } from "./emulator-download-job";
|
||||
import { getErrorMessage } from "@/bun/utils";
|
||||
import { IJob } from "../task-queue";
|
||||
import { IJob } from "../../../packages/gameflow-sdk/task-queue";
|
||||
import { LaunchGameJob } from "./launch-game-job";
|
||||
import { BiosDownloadJob } from "./bios-download-job";
|
||||
import { InstallJob } from "./install-job";
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import z from "zod";
|
||||
import { IJob, JobContext } from "../task-queue";
|
||||
import { ActiveGameSchema, ActiveGameType } from "@/bun/types/types.schema";
|
||||
import { IJob, JobContext } from "../../../packages/gameflow-sdk/task-queue";
|
||||
import { ActiveGameSchema, ActiveGameType } from "@simeonradivoev/gameflow-sdk";
|
||||
import { config, db, events, plugins } from "../app";
|
||||
import * as appSchema from "@schema/app";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { spawn } from 'node:child_process';
|
||||
import { updateLocalLastPlayed } from "../games/services/statusService";
|
||||
import { getErrorMessage } from "@/bun/utils";
|
||||
import { CommandEntry, FrontEndId, SaveSlots } from "@/shared/types";
|
||||
import { CommandEntry, FrontEndId, SaveSlots } from "@simeonradivoev/gameflow-sdk/shared";
|
||||
|
||||
export class LaunchGameJob implements IJob<z.infer<typeof LaunchGameJob.dataSchema>, string>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import Elysia, { status } from "elysia";
|
||||
import { IJob, JobContext } from "../task-queue";
|
||||
import { IJob, JobContext } from "../../../packages/gameflow-sdk/task-queue";
|
||||
import { LOGIN_PORT, SERVER_URL } from "@/shared/constants";
|
||||
import { host, localIp } from "@/bun/utils/host";
|
||||
import cors from "@elysiajs/cors";
|
||||
|
|
|
|||
62
src/bun/api/jobs/plugin-operation-job.ts
Normal file
62
src/bun/api/jobs/plugin-operation-job.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import z from "zod";
|
||||
import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk";
|
||||
import { plugins } from "../app";
|
||||
import { canUninstall, runBunPackageCommand } from "../plugins/services";
|
||||
import { getPlugin, registerPlugin, unregisterPlugin } from "../plugins/register-plugins";
|
||||
import { PluginRegistry } from "@/shared/constants";
|
||||
|
||||
export default class PluginOperationJob implements IJob<never, string>
|
||||
{
|
||||
static id = "plugin-operation-job" as const;
|
||||
static dataSchema = z.never();
|
||||
group = "plugin-operations";
|
||||
operation: "add" | "update" | "remove";
|
||||
plugin: string;
|
||||
|
||||
constructor(operation: "add" | "update" | "remove", plugin: string)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
async start (context: JobContext<IJob<never, string>, never, string>)
|
||||
{
|
||||
switch (this.operation)
|
||||
{
|
||||
case "add":
|
||||
//TODO: find the latest compatible version with the current sdk version
|
||||
const addResponse = await runBunPackageCommand(["add", this.plugin, '--omit', 'peer', "--registry", PluginRegistry]);
|
||||
console.log(addResponse);
|
||||
const addPlugin = await getPlugin(this.plugin, plugins);
|
||||
if (!addPlugin) throw new Error(`${this.plugin} Not Found`);
|
||||
await registerPlugin(addPlugin, 'store', plugins);
|
||||
break;
|
||||
case "update":
|
||||
const existingPlugin = plugins.plugins[this.plugin];
|
||||
if (!existingPlugin) throw new Error(`${this.plugin} Not Found`);
|
||||
if (!existingPlugin.update?.new) throw new Error(`No Update Found`);
|
||||
let updatePlugin = await getPlugin(this.plugin, plugins);
|
||||
if (!updatePlugin) throw new Error(`${this.plugin} Not Found`);
|
||||
await unregisterPlugin(this.plugin, plugins);
|
||||
const updateResponse = await runBunPackageCommand(["update", `${this.plugin}@${existingPlugin.update?.new}`, '--omit', 'peer', "--registry", PluginRegistry, '--latest']);
|
||||
console.log(updateResponse);
|
||||
updatePlugin = await getPlugin(this.plugin, plugins);
|
||||
if (!updatePlugin) throw new Error(`Something Went Wrong during update. Missing Plugin: ${this.plugin}`);
|
||||
await registerPlugin(updatePlugin, existingPlugin.source, plugins);
|
||||
break;
|
||||
case "remove":
|
||||
const removePlugin = plugins.plugins[this.plugin];
|
||||
if (!removePlugin) throw new Error(`${this.plugin} Not Found`);
|
||||
if (!canUninstall(removePlugin.description, removePlugin.source))
|
||||
{
|
||||
throw new Error("Uninstall Not Allowed");
|
||||
}
|
||||
const response = await runBunPackageCommand(['remove', this.plugin, "--registry", PluginRegistry, '--omit', 'peer']);
|
||||
console.log(response);
|
||||
await unregisterPlugin(this.plugin, plugins);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import z from "zod";
|
||||
import { IJob, JobContext } from "../task-queue";
|
||||
import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk";
|
||||
import { plugins } from "../app";
|
||||
|
||||
export default class ReloadPluginsJob implements IJob<never, string>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import z from "zod";
|
||||
import { IJob, JobContext } from "../task-queue";
|
||||
import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk";
|
||||
import { events } from "../app";
|
||||
import { Downloader } from "@/bun/utils/downloader";
|
||||
import path from 'node:path';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { IJob, JobContext } from "../task-queue";
|
||||
import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk";
|
||||
import secrets from "../secrets";
|
||||
import open from "open";
|
||||
import z from "zod";
|
||||
|
|
|
|||
|
|
@ -1,59 +1,57 @@
|
|||
import { ensureDir } from "fs-extra";
|
||||
import { IJob, JobContext } from "../task-queue";
|
||||
import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk";
|
||||
import { getStoreRootFolder } from "../store/services/gamesService";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import z from "zod";
|
||||
import { runBunPackageCommand } from "../plugins/services";
|
||||
import { PluginRegistry } from "@/shared/constants";
|
||||
import path from "node:path";
|
||||
import sdkPkg from '@simeonradivoev/gameflow-sdk/package.json';
|
||||
|
||||
export default class UpdateStoreJob implements IJob<never, never>
|
||||
export default class UpdateStoreJob implements IJob<never, string>
|
||||
{
|
||||
static id = "update-store" as const;
|
||||
static dataSchema = z.never();
|
||||
packageName: string;
|
||||
registry: URL;
|
||||
storeVersion: string;
|
||||
|
||||
constructor()
|
||||
{
|
||||
this.packageName = process.env.STORE_PACKAGE_NAME ?? "@simeonradivoev/gameflow-store";
|
||||
this.registry = new URL(process.env.STORE_REGISTRY ?? "https://registry.npmjs.org");
|
||||
this.storeVersion = process.env.STORE_VERSION ?? "^0.1.0";
|
||||
}
|
||||
|
||||
async runCommand (commands: string[])
|
||||
async start (context: JobContext<UpdateStoreJob, never, string>)
|
||||
{
|
||||
const tempCache = path.join(tmpdir(), "gameflow-bun-cache");
|
||||
const storeFolder = getStoreRootFolder();
|
||||
|
||||
let proc = Bun.spawn([process.execPath, ...commands, "--registry", this.registry.href, '--json'], {
|
||||
cwd: storeFolder,
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
env: {
|
||||
BUN_BE_BUN: "1",
|
||||
BUN_INSTALL_CACHE_DIR: tempCache
|
||||
}
|
||||
});
|
||||
|
||||
let stdout = await new Response(proc.stdout).text();
|
||||
console.log(stdout);
|
||||
let stderr = await new Response(proc.stderr).text();
|
||||
if (stderr)
|
||||
console.error(stderr);
|
||||
await proc.exited;
|
||||
}
|
||||
|
||||
async start (context: JobContext<UpdateStoreJob, never, never>)
|
||||
{
|
||||
if (process.env.CUSTOM_STORE_PATH) return;
|
||||
|
||||
const storeFolder = getStoreRootFolder();
|
||||
await ensureDir(storeFolder);
|
||||
const storePackageFile = Bun.file(path.join(storeFolder, "package.json"));
|
||||
if (!await storePackageFile.exists())
|
||||
{
|
||||
await storePackageFile.write(JSON.stringify({ dependencies: {} }, null, 3));
|
||||
}
|
||||
|
||||
console.log("Adding Store Package");
|
||||
await this.runCommand(["add", `${this.packageName}@${this.storeVersion}`]);
|
||||
const storePackage = await Bun.file(path.join(storeFolder, "package.json")).json();
|
||||
|
||||
console.log("Updating Store Package");
|
||||
await this.runCommand(["update", `${this.packageName}@${this.storeVersion}`]);
|
||||
if (!storePackage.dependencies?.[sdkPkg.name] || storePackage.dependencies?.[sdkPkg.name] !== sdkPkg.version)
|
||||
{
|
||||
let response = await runBunPackageCommand(["add", `${sdkPkg.name}@${sdkPkg.version}`, "--registry", PluginRegistry, '--omit', 'peer']);
|
||||
console.log(response);
|
||||
}
|
||||
|
||||
// probably just means we couldn't find a version of the sdk, just install latest
|
||||
if (storePackage.dependencies?.[sdkPkg.name] !== sdkPkg.version)
|
||||
{
|
||||
let response = await runBunPackageCommand(["add", '--exact', `${sdkPkg.name}@latest`, "--registry", PluginRegistry, '--omit', 'peer']);
|
||||
console.log(response);
|
||||
}
|
||||
|
||||
if (process.env.CUSTOM_STORE_PATH) return;
|
||||
|
||||
if (!storePackage.dependencies?.['@simeonradivoev/gameflow-store'])
|
||||
{
|
||||
context.setProgress(0.5, "Adding Store");
|
||||
let response = await runBunPackageCommand(["add", `${this.packageName}@${this.storeVersion}`, "--registry", PluginRegistry, '--omit', 'peer']);
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue