mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-07-11 06:01:58 +00:00
port updater to ws, also small refactoring
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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');
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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');
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user