mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-13 12:15:09 +03:00
Add event handler
This commit is contained in:
@@ -189,7 +189,7 @@ class Updater:
|
||||
raw += len(c)
|
||||
new_progress = round((raw / total) * 100)
|
||||
if progress != new_progress:
|
||||
self.context.loop.create_task(tab.evaluate_js(f"window.DeckyUpdater.updateProgress({new_progress})", False, False, False))
|
||||
self.context.loop.create_task(self.context.ws.emit("frontend/update_download_percentage", new_progress))
|
||||
progress = new_progress
|
||||
|
||||
if ON_LINUX:
|
||||
@@ -202,7 +202,7 @@ class Updater:
|
||||
logger.info(f"Setting the executable flag with chcon returned {await process.wait()}")
|
||||
|
||||
logger.info("Updated loader installation.")
|
||||
await tab.evaluate_js("window.DeckyUpdater.finish()", False, False)
|
||||
await self.context.ws.emit("frontend/finish_download")
|
||||
await self.do_restart()
|
||||
await tab.close_websocket()
|
||||
|
||||
|
||||
@@ -7,9 +7,7 @@ from aiohttp.web import Application, WebSocketResponse, Request, Response, get
|
||||
|
||||
from enum import IntEnum
|
||||
|
||||
from typing import Callable, Coroutine, Dict, Any, cast, TypeVar, Type
|
||||
|
||||
from dataclasses import asdict, is_dataclass
|
||||
from typing import Callable, Coroutine, Dict, Any, cast, TypeVar
|
||||
|
||||
from traceback import format_exc
|
||||
|
||||
@@ -127,11 +125,6 @@ class WSRouter:
|
||||
self.logger.debug('Websocket connection closed')
|
||||
return ws
|
||||
|
||||
# DataType defaults to None so that if a plugin opts in to strict pyright checking and attempts to pass data witbout specifying the type (or any), the type check fails
|
||||
async def emit(self, event: str, data: DataType | None = None, data_type: Type[DataType] | None = None):
|
||||
self.logger.debug('Firing frontend event %s with args %s', data)
|
||||
sent_data: Dict[Any, Any] | None = cast(Dict[Any, Any], data)
|
||||
if is_dataclass(data):
|
||||
sent_data = asdict(data) # type: ignore Argument of type "DataclassInstance | type[DataclassInstance]" cannot be assigned to parameter "obj" of type "DataclassInstance" in function "asdict"
|
||||
|
||||
await self.write({ "type": MessageType.EVENT.value, "event": event, "data": sent_data })
|
||||
async def emit(self, event: str, *args: Any):
|
||||
self.logger.debug(f'Firing frontend event {event} with args {args}')
|
||||
await self.write({ "type": MessageType.EVENT.value, "event": event, "args": args })
|
||||
|
||||
@@ -77,16 +77,20 @@ export default function UpdaterSettings() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
window.DeckyUpdater = {
|
||||
updateProgress: (i) => {
|
||||
setUpdateProgress(i);
|
||||
setIsLoaderUpdating(true);
|
||||
},
|
||||
finish: async () => {
|
||||
setUpdateProgress(0);
|
||||
setReloading(true);
|
||||
await doRestart();
|
||||
},
|
||||
const a = DeckyBackend.addEventListener('frontend/update_download_percentage', (percentage) => {
|
||||
setUpdateProgress(percentage);
|
||||
setIsLoaderUpdating(true);
|
||||
});
|
||||
|
||||
const b = DeckyBackend.addEventListener('frontend/finish_download', async () => {
|
||||
setUpdateProgress(0);
|
||||
setReloading(true);
|
||||
await doRestart();
|
||||
});
|
||||
|
||||
return () => {
|
||||
DeckyBackend.removeEventListener('frontend/update_download_percentage', a);
|
||||
DeckyBackend.removeEventListener('frontend/finish_download', b);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -3,11 +3,9 @@ import Backend from 'i18next-http-backend';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
import PluginLoader from './plugin-loader';
|
||||
import { DeckyUpdater } from './updater';
|
||||
|
||||
declare global {
|
||||
export var DeckyPluginLoader: PluginLoader;
|
||||
export var DeckyUpdater: DeckyUpdater | undefined; // TODO get rid of this
|
||||
export var importDeckyPlugin: Function;
|
||||
export var deckyHasLoaded: boolean;
|
||||
export var deckyHasConnectedRDT: boolean | undefined;
|
||||
|
||||
@@ -4,11 +4,6 @@ export enum Branches {
|
||||
// Testing,
|
||||
}
|
||||
|
||||
export interface DeckyUpdater {
|
||||
updateProgress: (val: number) => void;
|
||||
finish: () => void;
|
||||
}
|
||||
|
||||
export interface RemoteVerInfo {
|
||||
assets: {
|
||||
browser_download_url: string;
|
||||
|
||||
@@ -34,7 +34,13 @@ interface ErrorMessage {
|
||||
id: number;
|
||||
}
|
||||
|
||||
type Message = CallMessage | ReplyMessage | ErrorMessage;
|
||||
interface EventMessage {
|
||||
type: MessageType.EVENT;
|
||||
event: string;
|
||||
args: any;
|
||||
}
|
||||
|
||||
type Message = CallMessage | ReplyMessage | ErrorMessage | EventMessage;
|
||||
|
||||
// Helper to resolve a promise from the outside
|
||||
interface PromiseResolver<T> {
|
||||
@@ -46,6 +52,7 @@ interface PromiseResolver<T> {
|
||||
export class WSRouter extends Logger {
|
||||
routes: Map<string, (...args: any) => any> = new Map();
|
||||
runningCalls: Map<number, PromiseResolver<any>> = new Map();
|
||||
eventListeners: Map<string, Set<(...args: any) => any>> = new Map();
|
||||
ws?: WebSocket;
|
||||
connectPromise?: Promise<void>;
|
||||
// Used to map results and errors to calls
|
||||
@@ -87,7 +94,7 @@ export class WSRouter extends Logger {
|
||||
this.ws?.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
addRoute(name: string, route: (args: any) => any) {
|
||||
addRoute(name: string, route: (...args: any) => any) {
|
||||
this.routes.set(name, route);
|
||||
}
|
||||
|
||||
@@ -95,6 +102,25 @@ export class WSRouter extends Logger {
|
||||
this.routes.delete(name);
|
||||
}
|
||||
|
||||
addEventListener(event: string, listener: (...args: any) => any) {
|
||||
if (!this.eventListeners.has(event)) {
|
||||
this.eventListeners.set(event, new Set([listener]));
|
||||
} else {
|
||||
this.eventListeners.get(event)?.add(listener);
|
||||
}
|
||||
return listener;
|
||||
}
|
||||
|
||||
removeEventListener(event: string, listener: (...args: any) => any) {
|
||||
if (this.eventListeners.has(event)) {
|
||||
const set = this.eventListeners.get(event);
|
||||
set?.delete(listener);
|
||||
if (set?.size === 0) {
|
||||
this.eventListeners.delete(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onMessage(msg: MessageEvent) {
|
||||
try {
|
||||
const data = JSON.parse(msg.data) as Message;
|
||||
@@ -129,6 +155,20 @@ export class WSRouter extends Logger {
|
||||
}
|
||||
break;
|
||||
|
||||
case MessageType.EVENT:
|
||||
if (this.eventListeners.has(data.event)) {
|
||||
for (const listener of this.eventListeners.get(data.event)!) {
|
||||
try {
|
||||
listener(...data.args);
|
||||
} catch (e) {
|
||||
this.error(`error in event ${data.event}`, e, listener);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.debug(`event ${data.event} has no listeners`);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
this.error('Unknown message type', data);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user