port updater to ws, also small refactoring

This commit is contained in:
AAGaming
2023-12-30 21:32:23 -05:00
parent 70104065e2
commit 40c7c1b515
22 changed files with 86 additions and 145 deletions
+7 -31
View File
@@ -2,7 +2,6 @@ from __future__ import annotations
import os import os
import shutil import shutil
from asyncio import sleep from asyncio import sleep
from json.decoder import JSONDecodeError
from logging import getLogger from logging import getLogger
from os import getcwd, path, remove from os import getcwd, path, remove
from typing import TYPE_CHECKING, List, TypedDict from typing import TYPE_CHECKING, List, TypedDict
@@ -10,7 +9,7 @@ if TYPE_CHECKING:
from .main import PluginManager from .main import PluginManager
from .localplatform.localplatform import chmod, service_restart, ON_LINUX, get_keep_systemd_service, get_selinux from .localplatform.localplatform import chmod, service_restart, ON_LINUX, get_keep_systemd_service, get_selinux
from aiohttp import ClientSession, web from aiohttp import ClientSession
from . import helpers from . import helpers
from .injector import get_gamepadui_tab from .injector import get_gamepadui_tab
@@ -30,14 +29,6 @@ class Updater:
def __init__(self, context: PluginManager) -> None: def __init__(self, context: PluginManager) -> None:
self.context = context self.context = context
self.settings = self.context.settings self.settings = self.context.settings
# Exposes updater methods to frontend
self.updater_methods = {
"get_branch": self._get_branch,
"get_version": self.get_version,
"do_update": self.do_update,
"do_restart": self.do_restart,
"check_for_updates": self.check_for_updates
}
self.remoteVer: RemoteVer | None = None self.remoteVer: RemoteVer | None = None
self.allRemoteVers: List[RemoteVer] = [] self.allRemoteVers: List[RemoteVer] = []
self.localVer = helpers.get_loader_version() self.localVer = helpers.get_loader_version()
@@ -49,27 +40,12 @@ class Updater:
logger.error("Current branch could not be determined, defaulting to \"Stable\"") logger.error("Current branch could not be determined, defaulting to \"Stable\"")
if context: if context:
context.web_app.add_routes([ context.ws.add_route("updater/get_version_info", self.get_version_info);
web.post("/updater/{method_name}", self._handle_server_method_call) context.ws.add_route("updater/check_for_updates", self.check_for_updates);
]) context.ws.add_route("updater/do_restart", self.do_restart);
context.ws.add_route("updater/do_update", self.do_update);
context.loop.create_task(self.version_reloader()) context.loop.create_task(self.version_reloader())
async def _handle_server_method_call(self, request: web.Request):
method_name = request.match_info["method_name"]
try:
args = await request.json()
except JSONDecodeError:
args = {}
res = {}
try:
r = await self.updater_methods[method_name](**args) # type: ignore
res["result"] = r
res["success"] = True
except Exception as e:
res["result"] = str(e)
res["success"] = False
return web.json_response(res)
def get_branch(self, manager: SettingsManager): def get_branch(self, manager: SettingsManager):
ver = manager.getSetting("branch", -1) ver = manager.getSetting("branch", -1)
logger.debug("current branch: %i" % ver) logger.debug("current branch: %i" % ver)
@@ -102,7 +78,7 @@ class Updater:
url = "https://raw.githubusercontent.com/SteamDeckHomebrew/decky-loader/main/dist/plugin_loader-prerelease.service" url = "https://raw.githubusercontent.com/SteamDeckHomebrew/decky-loader/main/dist/plugin_loader-prerelease.service"
return str(url) return str(url)
async def get_version(self): async def get_version_info(self):
return { return {
"current": self.localVer, "current": self.localVer,
"remote": self.remoteVer, "remote": self.remoteVer,
@@ -139,7 +115,7 @@ class Updater:
logger.info("Updated remote version information") logger.info("Updated remote version information")
tab = await get_gamepadui_tab() tab = await get_gamepadui_tab()
await tab.evaluate_js(f"window.DeckyPluginLoader.notifyUpdates()", False, True, False) await tab.evaluate_js(f"window.DeckyPluginLoader.notifyUpdates()", False, True, False)
return await self.get_version() return await self.get_version_info()
async def version_reloader(self): async def version_reloader(self):
await sleep(30) await sleep(30)
+1 -1
View File
@@ -16,7 +16,7 @@ from .helpers import get_csrf_token
class MessageType(IntEnum): class MessageType(IntEnum):
ERROR = -1 ERROR = -1
# Call-reply, Frontend -> Backend # Call-reply, Frontend -> Backend -> Frontend
CALL = 0 CALL = 0
REPLY = 1 REPLY = 1
# Pub/Sub, Backend -> Frontend # Pub/Sub, Backend -> Frontend
@@ -46,7 +46,7 @@ const MultiplePluginsInstallModal: FC<MultiplePluginsInstallModalProps> = ({
setLoading(true); setLoading(true);
await onOK(); await onOK();
setTimeout(() => Navigation.OpenQuickAccessMenu(QuickAccessTab.Decky), 250); setTimeout(() => Navigation.OpenQuickAccessMenu(QuickAccessTab.Decky), 250);
setTimeout(() => window.DeckyPluginLoader.checkPluginUpdates(), 1000); setTimeout(() => DeckyPluginLoader.checkPluginUpdates(), 1000);
}} }}
onCancel={async () => { onCancel={async () => {
await onCancel(); await onCancel();
@@ -34,7 +34,7 @@ const PluginInstallModal: FC<PluginInstallModalProps> = ({
setLoading(true); setLoading(true);
await onOK(); await onOK();
setTimeout(() => Navigation.OpenQuickAccessMenu(QuickAccessTab.Decky), 250); setTimeout(() => Navigation.OpenQuickAccessMenu(QuickAccessTab.Decky), 250);
setTimeout(() => window.DeckyPluginLoader.checkPluginUpdates(), 1000); setTimeout(() => DeckyPluginLoader.checkPluginUpdates(), 1000);
}} }}
onCancel={async () => { onCancel={async () => {
await onCancel(); await onCancel();
@@ -19,7 +19,7 @@ const PluginUninstallModal: FC<PluginUninstallModalProps> = ({ name, title, butt
await uninstallPlugin(name); await uninstallPlugin(name);
// uninstalling a plugin resets the hidden setting for it server-side // uninstalling a plugin resets the hidden setting for it server-side
// we invalidate here so if you re-install it, you won't have an out-of-date hidden filter // we invalidate here so if you re-install it, you won't have an out-of-date hidden filter
await window.DeckyPluginLoader.hiddenPluginsService.invalidate(); await DeckyPluginLoader.hiddenPluginsService.invalidate();
}} }}
strTitle={title} strTitle={title}
strOKButtonText={buttonText} strOKButtonText={buttonText}
@@ -95,7 +95,7 @@ const sortOptions = [
}, },
]; ];
const getList = window.DeckyBackend.callable< const getList = DeckyBackend.callable<
[ [
path: string, path: string,
includeFiles?: boolean, includeFiles?: boolean,
@@ -13,9 +13,7 @@ function rePatch() {
const details = window.appDetailsStore.GetAppDetails(appid); const details = window.appDetailsStore.GetAppDetails(appid);
logger.debug('game details', details); logger.debug('game details', details);
// strShortcutStartDir // strShortcutStartDir
const file = await window.DeckyPluginLoader.openFilePicker( const file = await DeckyPluginLoader.openFilePicker(details?.strShortcutStartDir.replaceAll('"', '') || '/');
details?.strShortcutStartDir.replaceAll('"', '') || '/',
);
logger.debug('user selected', file); logger.debug('user selected', file);
window.SteamClient.Apps.SetShortcutExe(appid, JSON.stringify(file.path)); window.SteamClient.Apps.SetShortcutExe(appid, JSON.stringify(file.path));
const pathArr = file.path.split('/'); const pathArr = file.path.split('/');
@@ -28,20 +28,13 @@ const installFromZip = async () => {
logger.error('The default path has not been found!'); logger.error('The default path has not been found!');
return; return;
} }
window.DeckyPluginLoader.openFilePickerV2( DeckyPluginLoader.openFilePickerV2(FileSelectionType.FILE, path, true, true, undefined, ['zip'], false, false).then(
FileSelectionType.FILE, (val) => {
path, const url = `file://${val.path}`;
true, console.log(`Installing plugin locally from ${url}`);
true, installFromURL(url);
undefined, },
['zip'], );
false,
false,
).then((val) => {
const url = `file://${val.path}`;
console.log(`Installing plugin locally from ${url}`);
installFromURL(url);
});
}; };
export default function DeveloperSettings() { export default function DeveloperSettings() {
@@ -92,10 +85,7 @@ export default function DeveloperSettings() {
<DialogButton <DialogButton
onClick={async () => { onClick={async () => {
try { try {
let tabId = await window.DeckyBackend.call<[name: string], string>( let tabId = await DeckyBackend.call<[name: string], string>('utilities/get_tab_id', 'SharedJSContext');
'utilities/get_tab_id',
'SharedJSContext',
);
Navigation.NavigateToExternalWeb( Navigation.NavigateToExternalWeb(
'localhost:8080/devtools/inspector.html?ws=localhost:8080/devtools/page/' + tabId, 'localhost:8080/devtools/inspector.html?ws=localhost:8080/devtools/page/' + tabId,
); );
@@ -3,7 +3,7 @@ import { FunctionComponent } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Logger from '../../../../logger'; import Logger from '../../../../logger';
import { callUpdaterMethod } from '../../../../updater'; import { checkForUpdates } from '../../../../updater';
import { useSetting } from '../../../../utils/hooks/useSetting'; import { useSetting } from '../../../../utils/hooks/useSetting';
const logger = new Logger('BranchSelect'); const logger = new Logger('BranchSelect');
@@ -37,7 +37,7 @@ const BranchSelect: FunctionComponent<{}> = () => {
selectedOption={selectedBranch} selectedOption={selectedBranch}
onChange={async (newVal) => { onChange={async (newVal) => {
await setSelectedBranch(newVal.data); await setSelectedBranch(newVal.data);
callUpdaterMethod('check_for_updates'); checkForUpdates();
logger.log('switching branches!'); logger.log('switching branches!');
}} }}
/> />
@@ -6,7 +6,7 @@ import { useDeckyState } from '../../../DeckyState';
const NotificationSettings: FC = () => { const NotificationSettings: FC = () => {
const { notificationSettings } = useDeckyState(); const { notificationSettings } = useDeckyState();
const notificationService = window.DeckyPluginLoader.notificationService; const notificationService = DeckyPluginLoader.notificationService;
const { t } = useTranslation(); const { t } = useTranslation();
@@ -18,8 +18,8 @@ export default function RemoteDebuggingSettings() {
value={allowRemoteDebugging || false} value={allowRemoteDebugging || false}
onChange={(toggleValue) => { onChange={(toggleValue) => {
setAllowRemoteDebugging(toggleValue); setAllowRemoteDebugging(toggleValue);
if (toggleValue) window.DeckyBackend.call('allow_remote_debugging'); if (toggleValue) DeckyBackend.call('allow_remote_debugging');
else window.DeckyBackend.call('disallow_remote_debugging'); else DeckyBackend.call('disallow_remote_debugging');
}} }}
/> />
</Field> </Field>
@@ -15,7 +15,7 @@ import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { FaExclamation } from 'react-icons/fa'; import { FaExclamation } from 'react-icons/fa';
import { VerInfo, callUpdaterMethod, finishUpdate } from '../../../../updater'; import { VerInfo, checkForUpdates, doRestart, doUpdate } from '../../../../updater';
import { useDeckyState } from '../../../DeckyState'; import { useDeckyState } from '../../../DeckyState';
import InlinePatchNotes from '../../../patchnotes/InlinePatchNotes'; import InlinePatchNotes from '../../../patchnotes/InlinePatchNotes';
import WithSuspense from '../../../WithSuspense'; import WithSuspense from '../../../WithSuspense';
@@ -85,7 +85,7 @@ export default function UpdaterSettings() {
finish: async () => { finish: async () => {
setUpdateProgress(0); setUpdateProgress(0);
setReloading(true); setReloading(true);
await finishUpdate(); await doRestart();
}, },
}; };
}, []); }, []);
@@ -122,13 +122,13 @@ export default function UpdaterSettings() {
!versionInfo?.remote || versionInfo?.remote?.tag_name == versionInfo?.current !versionInfo?.remote || versionInfo?.remote?.tag_name == versionInfo?.current
? async () => { ? async () => {
setCheckingForUpdates(true); setCheckingForUpdates(true);
const res = (await callUpdaterMethod('check_for_updates')) as { result: VerInfo }; const verInfo = await checkForUpdates();
setVersionInfo(res.result); setVersionInfo(verInfo);
setCheckingForUpdates(false); setCheckingForUpdates(false);
} }
: async () => { : async () => {
setUpdateProgress(0); setUpdateProgress(0);
callUpdaterMethod('do_update'); doUpdate();
} }
} }
> >
@@ -35,7 +35,7 @@ async function reinstallPlugin(pluginName: string, currentVersion?: string) {
type PluginTableData = PluginData & { name: string; hidden: boolean; onHide(): void; onShow(): void }; type PluginTableData = PluginData & { name: string; hidden: boolean; onHide(): void; onShow(): void };
const reloadPluginBackend = window.DeckyBackend.callable<[pluginName: string], void>('loader/reload_plugin'); const reloadPluginBackend = DeckyBackend.callable<[pluginName: string], void>('loader/reload_plugin');
function PluginInteractables(props: { entry: ReorderableEntry<PluginTableData> }) { function PluginInteractables(props: { entry: ReorderableEntry<PluginTableData> }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -58,14 +58,14 @@ function PluginInteractables(props: { entry: ReorderableEntry<PluginTableData> }
console.error('Error Reloading Plugin Backend', err); console.error('Error Reloading Plugin Backend', err);
} }
window.DeckyPluginLoader.importPlugin(name, version); DeckyPluginLoader.importPlugin(name, version);
}} }}
> >
{t('PluginListIndex.reload')} {t('PluginListIndex.reload')}
</MenuItem> </MenuItem>
<MenuItem <MenuItem
onSelected={() => onSelected={() =>
window.DeckyPluginLoader.uninstallPlugin( DeckyPluginLoader.uninstallPlugin(
name, name,
t('PluginLoader.plugin_uninstall.title', { name }), t('PluginLoader.plugin_uninstall.title', { name }),
t('PluginLoader.plugin_uninstall.button'), t('PluginLoader.plugin_uninstall.button'),
@@ -143,11 +143,11 @@ export default function PluginList() {
const { t } = useTranslation(); const { t } = useTranslation();
useEffect(() => { useEffect(() => {
window.DeckyPluginLoader.checkPluginUpdates(); DeckyPluginLoader.checkPluginUpdates();
}, []); }, []);
const [pluginEntries, setPluginEntries] = useState<ReorderableEntry<PluginTableData>[]>([]); const [pluginEntries, setPluginEntries] = useState<ReorderableEntry<PluginTableData>[]>([]);
const hiddenPluginsService = window.DeckyPluginLoader.hiddenPluginsService; const hiddenPluginsService = DeckyPluginLoader.hiddenPluginsService;
useEffect(() => { useEffect(() => {
setPluginEntries( setPluginEntries(
+2 -2
View File
@@ -38,7 +38,7 @@ export async function setShowValveInternal(show: boolean) {
} }
export async function setShouldConnectToReactDevTools(enable: boolean) { export async function setShouldConnectToReactDevTools(enable: boolean) {
window.DeckyPluginLoader.toaster.toast({ DeckyPluginLoader.toaster.toast({
title: enable ? ( title: enable ? (
<TranslationHelper trans_class={TranslationClass.DEVELOPER} trans_text={'enabling'} /> <TranslationHelper trans_class={TranslationClass.DEVELOPER} trans_text={'enabling'} />
) : ( ) : (
@@ -48,7 +48,7 @@ export async function setShouldConnectToReactDevTools(enable: boolean) {
icon: <FaReact />, icon: <FaReact />,
}); });
await sleep(5000); await sleep(5000);
return enable ? window.DeckyBackend.call('utilities/enable_rdt') : window.DeckyBackend.call('utilities/disable_rdt'); return enable ? DeckyBackend.call('utilities/enable_rdt') : DeckyBackend.call('utilities/disable_rdt');
} }
export async function startup() { export async function startup() {
+1 -1
View File
@@ -6,7 +6,7 @@
window.deckyAuthToken = await fetch('http://127.0.0.1:1337/auth/token').then((r) => r.text()); window.deckyAuthToken = await fetch('http://127.0.0.1:1337/auth/token').then((r) => r.text());
console.debug('Connecting to Decky backend...'); console.debug('Connecting to Decky backend...');
window.DeckyBackend = new (await import('./wsrouter')).WSRouter(); window.DeckyBackend = new (await import('./wsrouter')).WSRouter();
await window.DeckyBackend.connect(); await DeckyBackend.connect();
console.debug('Starting Decky!'); console.debug('Starting Decky!');
await import('./start'); await import('./start');
})(); })();
+18 -22
View File
@@ -28,10 +28,10 @@ import { NotificationService } from './notification-service';
import { InstallType, Plugin } from './plugin'; import { InstallType, Plugin } from './plugin';
import RouterHook from './router-hook'; import RouterHook from './router-hook';
import { deinitSteamFixes, initSteamFixes } from './steamfixes'; import { deinitSteamFixes, initSteamFixes } from './steamfixes';
import { checkForUpdates } from './store'; import { checkForPluginUpdates } from './store';
import TabsHook from './tabs-hook'; import TabsHook from './tabs-hook';
import Toaster from './toaster'; import Toaster from './toaster';
import { VerInfo, callUpdaterMethod } from './updater'; import { getVersionInfo } from './updater';
import { getSetting, setSetting } from './utils/settings'; import { getSetting, setSetting } from './utils/settings';
import TranslationHelper, { TranslationClass } from './utils/TranslationHelper'; import TranslationHelper, { TranslationClass } from './utils/TranslationHelper';
@@ -106,9 +106,7 @@ class PluginLoader extends Logger {
.then(() => this.log('Initialized')); .then(() => this.log('Initialized'));
} }
private getPluginsFromBackend = window.DeckyBackend.callable<[], { name: string; version: string }[]>( private getPluginsFromBackend = DeckyBackend.callable<[], { name: string; version: string }[]>('loader/get_plugins');
'loader/get_plugins',
);
private async loadPlugins() { private async loadPlugins() {
// wait for SP window to exist before loading plugins // wait for SP window to exist before loading plugins
@@ -129,13 +127,13 @@ class PluginLoader extends Logger {
} }
public async getUserInfo() { public async getUserInfo() {
const userInfo = await window.DeckyBackend.call<[], UserInfo>('utilities/get_user_info'); const userInfo = await DeckyBackend.call<[], UserInfo>('utilities/get_user_info');
setSetting('user_info.user_name', userInfo.username); setSetting('user_info.user_name', userInfo.username);
setSetting('user_info.user_home', userInfo.path); setSetting('user_info.user_home', userInfo.path);
} }
public async updateVersion() { public async updateVersion() {
const versionInfo = (await callUpdaterMethod('get_version')).result as VerInfo; const versionInfo = await getVersionInfo();
this.deckyState.setVersionInfo(versionInfo); this.deckyState.setVersionInfo(versionInfo);
return versionInfo; return versionInfo;
@@ -164,7 +162,7 @@ class PluginLoader extends Logger {
} }
public async checkPluginUpdates() { public async checkPluginUpdates() {
const updates = await checkForUpdates(this.plugins); const updates = await checkForPluginUpdates(this.plugins);
this.deckyState.setUpdates(updates); this.deckyState.setUpdates(updates);
return updates; return updates;
} }
@@ -199,8 +197,8 @@ class PluginLoader extends Logger {
version={version} version={version}
hash={hash} hash={hash}
installType={install_type} installType={install_type}
onOK={() => window.DeckyBackend.call<[string]>('utilities/confirm_plugin_install', request_id)} onOK={() => DeckyBackend.call<[string]>('utilities/confirm_plugin_install', request_id)}
onCancel={() => window.DeckyBackend.call<[string]>('utilities/cancel_plugin_install', request_id)} onCancel={() => DeckyBackend.call<[string]>('utilities/cancel_plugin_install', request_id)}
/>, />,
); );
} }
@@ -212,8 +210,8 @@ class PluginLoader extends Logger {
showModal( showModal(
<MultiplePluginsInstallModal <MultiplePluginsInstallModal
requests={requests} requests={requests}
onOK={() => window.DeckyBackend.call<[string]>('utilities/confirm_plugin_install', request_id)} onOK={() => DeckyBackend.call<[string]>('utilities/confirm_plugin_install', request_id)}
onCancel={() => window.DeckyBackend.call<[string]>('utilities/cancel_plugin_install', request_id)} onCancel={() => DeckyBackend.call<[string]>('utilities/cancel_plugin_install', request_id)}
/>, />,
); );
} }
@@ -298,7 +296,7 @@ class PluginLoader extends Logger {
let res = await fetch(`http://127.0.0.1:1337/plugins/${name}/frontend_bundle`, { let res = await fetch(`http://127.0.0.1:1337/plugins/${name}/frontend_bundle`, {
credentials: 'include', credentials: 'include',
headers: { headers: {
Authentication: window.deckyAuthToken, Authentication: deckyAuthToken,
}, },
}); });
@@ -364,7 +362,7 @@ class PluginLoader extends Logger {
this.warn( this.warn(
`Calling ${methodName} via callServerMethod, which is deprecated and will be removed in a future release. Please switch to the backend API.`, `Calling ${methodName} via callServerMethod, which is deprecated and will be removed in a future release. Please switch to the backend API.`,
); );
return await window.DeckyBackend.call<[methodName: string, kwargs: any], any>( return await DeckyBackend.call<[methodName: string, kwargs: any], any>(
'utilities/_call_legacy_utility', 'utilities/_call_legacy_utility',
methodName, methodName,
args, args,
@@ -429,7 +427,7 @@ class PluginLoader extends Logger {
const pluginAPI = { const pluginAPI = {
backend: { backend: {
call<Args extends any[] = any[], Return = void>(method: string, ...args: Args): Promise<Return> { call<Args extends any[] = any[], Return = void>(method: string, ...args: Args): Promise<Return> {
return window.DeckyBackend.call<[pluginName: string, method: string, ...args: Args], Return>( return DeckyBackend.call<[pluginName: string, method: string, ...args: Args], Return>(
'loader/call_plugin_method', 'loader/call_plugin_method',
pluginName, pluginName,
method, method,
@@ -448,7 +446,7 @@ class PluginLoader extends Logger {
openFilePickerV2: this.openFilePickerV2, openFilePickerV2: this.openFilePickerV2,
// Legacy // Legacy
async callPluginMethod(methodName: string, args = {}) { async callPluginMethod(methodName: string, args = {}) {
return window.DeckyBackend.call<[pluginName: string, methodName: string, kwargs: any], any>( return DeckyBackend.call<[pluginName: string, methodName: string, kwargs: any], any>(
'loader/call_legacy_plugin_method', 'loader/call_legacy_plugin_method',
pluginName, pluginName,
methodName, methodName,
@@ -472,7 +470,7 @@ class PluginLoader extends Logger {
} }
// this is terrible but a. we're going to redo this entire method anyway and b. it was already terrible // this is terrible but a. we're going to redo this entire method anyway and b. it was already terrible
try { try {
const ret = await window.DeckyBackend.call< const ret = await DeckyBackend.call<
[method: string, url: string, extra_opts?: any], [method: string, url: string, extra_opts?: any],
{ status: number; headers: { [key: string]: string }; body: string } { status: number; headers: { [key: string]: string }; body: string }
>('utilities/http_request', method, url, req); >('utilities/http_request', method, url, req);
@@ -481,14 +479,12 @@ class PluginLoader extends Logger {
return { success: false, result: e?.toString() }; return { success: false, result: e?.toString() };
} }
}, },
executeInTab: window.DeckyBackend.callable< executeInTab: DeckyBackend.callable<
[tab: String, runAsync: Boolean, code: string], [tab: String, runAsync: Boolean, code: string],
{ success: boolean; result: any } { success: boolean; result: any }
>('utilities/execute_in_tab'), >('utilities/execute_in_tab'),
injectCssIntoTab: window.DeckyBackend.callable<[tab: string, style: string], string>( injectCssIntoTab: DeckyBackend.callable<[tab: string, style: string], string>('utilities/inject_css_into_tab'),
'utilities/inject_css_into_tab', removeCssFromTab: DeckyBackend.callable<[tab: string, cssId: string]>('utilities/remove_css_from_tab'),
),
removeCssFromTab: window.DeckyBackend.callable<[tab: string, cssId: string]>('utilities/remove_css_from_tab'),
}; };
return pluginAPI; return pluginAPI;
+3 -3
View File
@@ -22,7 +22,7 @@ type installPluginArgs = [
installType?: InstallType, installType?: InstallType,
]; ];
export let installPlugin = window.DeckyBackend.callable<installPluginArgs>('utilities/install_plugin'); export let installPlugin = DeckyBackend.callable<installPluginArgs>('utilities/install_plugin');
type installPluginsArgs = [ type installPluginsArgs = [
requests: { requests: {
@@ -34,6 +34,6 @@ type installPluginsArgs = [
}[], }[],
]; ];
export let installPlugins = window.DeckyBackend.callable<installPluginsArgs>('utilities/install_plugins'); export let installPlugins = DeckyBackend.callable<installPluginsArgs>('utilities/install_plugins');
export let uninstallPlugin = window.DeckyBackend.callable<[name: string]>('utilities/uninstall_plugin'); export let uninstallPlugin = DeckyBackend.callable<[name: string]>('utilities/uninstall_plugin');
+12 -14
View File
@@ -6,15 +6,13 @@ import PluginLoader from './plugin-loader';
import { DeckyUpdater } from './updater'; import { DeckyUpdater } from './updater';
declare global { declare global {
interface Window { export var DeckyPluginLoader: PluginLoader;
DeckyPluginLoader: PluginLoader; export var DeckyUpdater: DeckyUpdater | undefined; // TODO get rid of this
DeckyUpdater?: DeckyUpdater; export var importDeckyPlugin: Function;
importDeckyPlugin: Function; export var deckyHasLoaded: boolean;
deckyHasLoaded: boolean; export var deckyHasConnectedRDT: boolean | undefined;
deckyHasConnectedRDT?: boolean; export var deckyAuthToken: string;
deckyAuthToken: string; export var DFL: any | undefined;
DFL?: any;
}
} }
(async () => { (async () => {
@@ -37,7 +35,7 @@ declare global {
backend: { backend: {
loadPath: 'http://127.0.0.1:1337/locales/{{lng}}.json', loadPath: 'http://127.0.0.1:1337/locales/{{lng}}.json',
customHeaders: { customHeaders: {
Authentication: window.deckyAuthToken, Authentication: deckyAuthToken,
}, },
requestOptions: { requestOptions: {
credentials: 'include', credentials: 'include',
@@ -45,12 +43,12 @@ declare global {
}, },
}); });
window.DeckyPluginLoader?.dismountAll(); window?.DeckyPluginLoader?.dismountAll();
window.DeckyPluginLoader?.deinit(); window?.DeckyPluginLoader?.deinit();
window.DeckyPluginLoader = new PluginLoader(); window.DeckyPluginLoader = new PluginLoader();
window.DeckyPluginLoader.init(); DeckyPluginLoader.init();
window.importDeckyPlugin = function (name: string, version: string) { window.importDeckyPlugin = function (name: string, version: string) {
window.DeckyPluginLoader?.importPlugin(name, version); DeckyPluginLoader?.importPlugin(name, version);
}; };
})(); })();
+2 -2
View File
@@ -37,7 +37,7 @@ export async function getStore(): Promise<Store> {
} }
export async function getPluginList(): Promise<StorePlugin[]> { export async function getPluginList(): Promise<StorePlugin[]> {
let version = await window.DeckyPluginLoader.updateVersion(); let version = await DeckyPluginLoader.updateVersion();
let store = await getSetting<Store | null>('store', null); let store = await getSetting<Store | null>('store', null);
let customURL = await getSetting<string>('store-url', 'https://plugins.deckbrew.xyz/plugins'); let customURL = await getSetting<string>('store-url', 'https://plugins.deckbrew.xyz/plugins');
let storeURL; let storeURL;
@@ -112,7 +112,7 @@ export async function requestMultiplePluginInstalls(requests: PluginInstallReque
); );
} }
export async function checkForUpdates(plugins: Plugin[]): Promise<PluginUpdateMapping> { export async function checkForPluginUpdates(plugins: Plugin[]): Promise<PluginUpdateMapping> {
const serverData = await getPluginList(); const serverData = await getPluginList();
const updateMap = new Map<string, StorePluginVersion>(); const updateMap = new Map<string, StorePluginVersion>();
for (let plugin of plugins) { for (let plugin of plugins) {
+4 -17
View File
@@ -28,20 +28,7 @@ export interface VerInfo {
updatable: boolean; updatable: boolean;
} }
export async function callUpdaterMethod(methodName: string, args = {}) { export const doUpdate = DeckyBackend.callable('updater/do_update');
const response = await fetch(`http://127.0.0.1:1337/updater/${methodName}`, { export const doRestart = DeckyBackend.callable('updater/do_restart');
method: 'POST', export const getVersionInfo = DeckyBackend.callable<[], VerInfo>('updater/get_version_info');
credentials: 'include', export const checkForUpdates = DeckyBackend.callable<[], VerInfo>('updater/check_for_updates');
headers: {
'Content-Type': 'application/json',
Authentication: window.deckyAuthToken,
},
body: JSON.stringify(args),
});
return response.json();
}
export async function finishUpdate() {
callUpdaterMethod('do_restart');
}
+2 -2
View File
@@ -1,8 +1,8 @@
export async function getSetting<T>(key: string, def: T): Promise<T> { export async function getSetting<T>(key: string, def: T): Promise<T> {
const res = await window.DeckyBackend.call<[string, T], T>('utilities/settings/get', key, def); const res = await DeckyBackend.call<[string, T], T>('utilities/settings/get', key, def);
return res; return res;
} }
export async function setSetting<T>(key: string, value: T): Promise<void> { export async function setSetting<T>(key: string, value: T): Promise<void> {
await window.DeckyBackend.call<[string, T], void>('utilities/settings/set', key, value); await DeckyBackend.call<[string, T], void>('utilities/settings/set', key, value);
} }
+6 -10
View File
@@ -3,14 +3,12 @@ import { sleep } from 'decky-frontend-lib';
import Logger from './logger'; import Logger from './logger';
declare global { declare global {
interface Window { export var DeckyBackend: WSRouter;
DeckyBackend: WSRouter;
}
} }
enum MessageType { enum MessageType {
ERROR = -1, ERROR = -1,
// Call-reply, Frontend -> Backend // Call-reply, Frontend -> Backend -> Frontend
CALL = 0, CALL = 0,
REPLY = 1, REPLY = 1,
// Pub/Sub, Backend -> Frontend // Pub/Sub, Backend -> Frontend
@@ -22,8 +20,6 @@ interface CallMessage {
args: any[]; args: any[];
route: string; route: string;
id: number; id: number;
// TODO implement this
// skipResponse?: boolean;
} }
interface ReplyMessage { interface ReplyMessage {
@@ -61,7 +57,7 @@ export class WSRouter extends Logger {
connect() { connect() {
return (this.connectPromise = new Promise<void>((resolve) => { return (this.connectPromise = new Promise<void>((resolve) => {
// Auth is a query param as JS WebSocket doesn't support headers // Auth is a query param as JS WebSocket doesn't support headers
this.ws = new WebSocket(`ws://127.0.0.1:1337/ws?auth=${window.deckyAuthToken}`); this.ws = new WebSocket(`ws://127.0.0.1:1337/ws?auth=${deckyAuthToken}`);
this.ws.addEventListener('open', () => { this.ws.addEventListener('open', () => {
this.debug('WS Connected'); this.debug('WS Connected');
@@ -129,7 +125,7 @@ export class WSRouter extends Logger {
if (this.runningCalls.has(data.id)) { if (this.runningCalls.has(data.id)) {
this.runningCalls.get(data.id)!.reject(data.error); this.runningCalls.get(data.id)!.reject(data.error);
this.runningCalls.delete(data.id); this.runningCalls.delete(data.id);
this.debug(`Errored PY call ${data.id} with error`, data.error); this.debug(`Rejected PY call ${data.id} with error`, data.error);
} }
break; break;
@@ -143,7 +139,7 @@ export class WSRouter extends Logger {
} }
// this.call<[number, number], string>('methodName', 1, 2); // this.call<[number, number], string>('methodName', 1, 2);
call<Args extends any[] = any[], Return = void>(route: string, ...args: Args): Promise<Return> { call<Args extends any[] = [], Return = void>(route: string, ...args: Args): Promise<Return> {
const resolver = this.createPromiseResolver<Return>(); const resolver = this.createPromiseResolver<Return>();
const id = ++this.reqId; const id = ++this.reqId;
@@ -157,7 +153,7 @@ export class WSRouter extends Logger {
return resolver.promise; return resolver.promise;
} }
callable<Args extends any[] = any[], Return = void>(route: string): (...args: Args) => Promise<Return> { callable<Args extends any[] = [], Return = void>(route: string): (...args: Args) => Promise<Return> {
return (...args) => this.call<Args, Return>(route, ...args); return (...args) => this.call<Args, Return>(route, ...args);
} }