diff --git a/src/backend/services/homepage/PuterHomepageService.ts b/src/backend/services/homepage/PuterHomepageService.ts
index 1aaf84622a..dd76d3d1d4 100644
--- a/src/backend/services/homepage/PuterHomepageService.ts
+++ b/src/backend/services/homepage/PuterHomepageService.ts
@@ -68,8 +68,6 @@ interface PuterGuiAddonsEvent {
* Serves the root HTML shell that bootstraps the Puter GUI.
*
* Extensions contribute by:
- * - `registerScript(url)` — adds a ``)
- .join('\n');
-
const guiParamsJson = JSON.stringify(guiParams).replace(
/
-
-
${manifestCss}
${event.headContent}
@@ -341,7 +314,6 @@ export class PuterHomepageService extends PuterService {
gui(${guiParamsJson});
});
- ${serviceScriptTags}
${event.bodyContent}
diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js
index 685451f4d0..bfcbd97829 100644
--- a/src/gui/src/IPC.js
+++ b/src/gui/src/IPC.js
@@ -37,6 +37,8 @@ import UIWindowSignup from './UI/UIWindowSignup.js';
import UINotification from './UI/UINotification.js';
import { PROCESS_IPC_ATTACHED } from './definitions.js';
+import { process_service } from './modules/process.js';
+import { ipc_service } from './modules/ipc.js';
import TeePromise from './util/TeePromise.js';
window.ipc_handlers = {};
@@ -113,9 +115,6 @@ const ipc_listener = async (event, handled) => {
// New IPC handlers should be registered here.
// Do this by calling `register_ipc_handler` of IPCService.
if ( window.ipc_handlers.hasOwnProperty(event.data.msg) ) {
- const services = globalThis.services;
- const svc_process = services.get('process');
-
// Add version info to old puter.js messages
// (and coerce them into the format of new ones)
if ( event.data.$ === undefined ) {
@@ -130,7 +129,7 @@ const ipc_listener = async (event, handled) => {
// The IPC context contains information about the call
const iframe = window.iframe_for_app_instance(event.data.appInstanceID);
- const process = svc_process.get_by_uuid(event.data.appInstanceID);
+ const process = process_service.get_by_uuid(event.data.appInstanceID);
const ipc_context = {
caller: {
process: process,
@@ -162,9 +161,7 @@ const ipc_listener = async (event, handled) => {
// READY
//-------------------------------------------------
if ( event.data.msg === 'READY' ) {
- const services = globalThis.services;
- const svc_process = services.get('process');
- const process = svc_process.get_by_uuid(event.data.appInstanceID);
+ const process = process_service.get_by_uuid(event.data.appInstanceID);
process.ipc_status = PROCESS_IPC_ATTACHED;
}
@@ -1888,10 +1885,7 @@ const ipc_listener = async (event, handled) => {
const { appInstanceID, targetAppInstanceID, targetAppOrigin, contents } = event.data;
// TODO: Determine if we should allow the message
// TODO: Track message traffic between apps
- const svc_ipc = globalThis.services.get('ipc');
- // const svc_exec = globalThis.services()
-
- const conn = svc_ipc.get_connection(targetAppInstanceID);
+ const conn = ipc_service.get_connection(targetAppInstanceID);
if ( conn ) {
conn.send(contents);
return;
diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js
index bc03257a9e..5423ec4a37 100644
--- a/src/gui/src/UI/UIDesktop.js
+++ b/src/gui/src/UI/UIDesktop.js
@@ -18,6 +18,7 @@
*/
import path from '../lib/path.js';
+import { process_service } from '../modules/process.js';
import UIContextMenu from './UIContextMenu.js';
import UIItem from './UIItem.js';
@@ -1262,7 +1263,7 @@ async function UIDesktop (options) {
// GUI is ready to launch apps!
//-----------------------------
window.dispatchEvent(new CustomEvent('desktop:ready'));
- globalThis.services.emit('gui:ready');
+ process_service.on_gui_ready();
//--------------------------------------------------------
// Open the AI app (best-effort — the `ai` app isn't seeded
diff --git a/src/gui/src/UI/UIWindowManageSessions.js b/src/gui/src/UI/UIWindowManageSessions.js
index c8b95a9cf6..57bac3f62a 100644
--- a/src/gui/src/UI/UIWindowManageSessions.js
+++ b/src/gui/src/UI/UIWindowManageSessions.js
@@ -17,6 +17,8 @@
* along with this program. If not, see .
*/
+import { anti_csrf_service } from '../modules/anti-csrf.js';
+
// Renders the Session Manager as a self-contained, responsive modal (a plain
// DOM overlay) rather than a draggable UIWindow. Confirmations are shown as
// in-modal sheets instead of UIAlert windows, so nothing here depends on the
@@ -94,8 +96,6 @@ const kindBadgeLabel = (kind) => {
const UIWindowManageSessions = async function UIWindowManageSessions (options) {
options = options ?? {};
- const services = globalThis.services;
-
// =====================================================================
// Responsive modal shell
// =====================================================================
@@ -450,7 +450,7 @@ const UIWindowManageSessions = async function UIWindowManageSessions (options) {
session.label = next || null;
el_title.textContent = sessionTitle(session);
try {
- const anti_csrf = await services.get('anti-csrf').token();
+ const anti_csrf = await anti_csrf_service.token();
const resp = await fetch(
`${window.api_origin}/auth/sessions/${encodeURIComponent(session.uuid)}/label`,
{
@@ -558,7 +558,7 @@ const UIWindowManageSessions = async function UIWindowManageSessions (options) {
});
if ( ! ok ) return;
- const anti_csrf = await services.get('anti-csrf').token();
+ const anti_csrf = await anti_csrf_service.token();
// Route access-token rows to the dedicated endpoint
// so `access_token_permissions` is cleared in addition
@@ -732,7 +732,7 @@ const UIWindowManageSessions = async function UIWindowManageSessions (options) {
});
if ( ! ok ) return;
- const anti_csrf = await services.get('anti-csrf').token();
+ const anti_csrf = await anti_csrf_service.token();
const resp = await fetch(
`${window.api_origin}/auth/revoke-all-sessions`,
{
diff --git a/src/gui/src/UI/UIWindowNewPassword.js b/src/gui/src/UI/UIWindowNewPassword.js
index 3e6e0fe38c..dbc4c3f891 100644
--- a/src/gui/src/UI/UIWindowNewPassword.js
+++ b/src/gui/src/UI/UIWindowNewPassword.js
@@ -19,6 +19,7 @@
import UIWindow from './UIWindow.js';
import UIAlert from './UIAlert.js';
+import { locale_service } from '../modules/locale.js';
import UIWindowLogin from './UIWindowLogin.js';
import check_password_strength from '../helpers/check_password_strength.js';
@@ -122,8 +123,7 @@ async function UIWindowNewPassword (options) {
return;
}
- const svc_locale = globalThis.services.get('locale');
- const countdown = svc_locale.format_duration(time_remaining);
+ const countdown = locale_service.format_duration(time_remaining);
$(el_window).find('.change-password-btn').html(`Set New Password (${countdown})`);
}, 1000);
diff --git a/src/gui/src/UI/UIWindowTaskManager.js b/src/gui/src/UI/UIWindowTaskManager.js
index 62851e7d62..c1476657a2 100644
--- a/src/gui/src/UI/UIWindowTaskManager.js
+++ b/src/gui/src/UI/UIWindowTaskManager.js
@@ -17,12 +17,13 @@
* along with this program. If not, see .
*/
import { END_HARD, END_SOFT } from '../definitions.js';
+import { process_service } from '../modules/process.js';
import UIAlert from './UIAlert.js';
import UIContextMenu from './UIContextMenu.js';
import UIWindow from './UIWindow.js';
const end_process = async (uuid, force) => {
- const svc_process = globalThis.services.get('process');
+ const svc_process = process_service;
const process = svc_process.get_by_uuid(uuid);
if ( ! process ) {
console.warn(`Can't end process with uuid='${uuid}': does not exist`);
@@ -86,7 +87,7 @@ const calculate_indent_string = (indent_level, is_last_item_stack, is_last_item)
};
const generate_task_rows = (items, { indent_level, is_last_item_stack }) => {
- const svc_process = globalThis.services.get('process');
+ const svc_process = process_service;
let rows_html = '';
for ( let i = 0; i < items.length; i++ ) {
@@ -141,7 +142,7 @@ const generate_task_rows = (items, { indent_level, is_last_item_stack }) => {
};
const UIWindowTaskManager = async function UIWindowTaskManager () {
- const svc_process = globalThis.services.get('process');
+ const svc_process = process_service;
let h = '';
diff --git a/src/gui/src/UI/UIWindowThemeDialog.js b/src/gui/src/UI/UIWindowThemeDialog.js
index 3a3d2d1ec2..28dcefe33c 100644
--- a/src/gui/src/UI/UIWindowThemeDialog.js
+++ b/src/gui/src/UI/UIWindowThemeDialog.js
@@ -18,11 +18,11 @@
*/
import { UIColorPickerWidget, hslaToHex8 } from './UIColorPickerWidget.js';
import UIWindow from './UIWindow.js';
+import { theme_service } from '../modules/theme.js';
const UIWindowThemeDialog = async function UIWindowThemeDialog (options) {
options = options ?? {};
- const services = globalThis.services;
- const svc_theme = services.get('theme');
+ const svc_theme = theme_service;
// Get current theme values and convert to hex8 for the color picker
const currentHue = svc_theme.get('hue');
diff --git a/src/gui/src/definitions.js b/src/gui/src/definitions.js
index 65e653a4d8..e9c4a292b7 100644
--- a/src/gui/src/definitions.js
+++ b/src/gui/src/definitions.js
@@ -19,40 +19,7 @@
import TeePromise from './util/TeePromise.js';
import AdvancedBase from './util/AdvancedBase.js';
-
-const NOOP = async () => {
-};
-
-export class Service extends AdvancedBase {
- // TODO: Service todo items
- static TODO = [
- 'consolidate with BaseService from backend',
- ];
- async __on (id, args) {
- const handler = this.__get_event_handler(id);
-
- return await handler(id, ...args);
- }
- __get_event_handler (id) {
- return this[`__on_${id}`]?.bind?.(this)
- || this.constructor[`__on_${id}`]?.bind?.(this.constructor)
- || NOOP;
- }
- construct (o) {
- this.$puter = {};
- for ( const k in o ) this.$puter[k] = o[k];
- if ( ! this._construct ) return;
- return this._construct();
- }
- init (...a) {
- if ( ! this._init ) return;
- this.services = a[0].services;
- return this._init(...a);
- }
- get context () {
- return { services: this.services };
- }
-};
+import { process_service } from './modules/process.js';
export const PROCESS_INITIALIZING = { i18n_key: 'initializing' };
export const PROCESS_RUNNING = { i18n_key: 'running' };
@@ -137,8 +104,7 @@ export class InitProcess extends Process {
}
_signal (sig) {
- const svc_process = globalThis.services.get('process');
- for ( const process of svc_process.processes ) {
+ for ( const process of process_service.processes ) {
if ( process === this ) continue;
process.signal(sig);
}
diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js
index ce6c1fc3e9..c72094be68 100644
--- a/src/gui/src/helpers.js
+++ b/src/gui/src/helpers.js
@@ -25,6 +25,7 @@ import update_title_based_on_uploads from './helpers/update_title_based_on_uploa
import update_username_in_gui from './helpers/update_username_in_gui.js';
import mime from './lib/mime.js';
import path from './lib/path.js';
+import { broadcast_service } from './modules/broadcast.js';
import UIAlert from './UI/UIAlert.js';
import UIItem from './UI/UIItem.js';
import UIWindowLogin from './UI/UIWindowLogin.js';
@@ -719,8 +720,7 @@ window.update_user_preferences = function (user_preferences) {
window.locale = language;
// Broadcast locale change to apps
- const broadcastService = globalThis.services.get('broadcast');
- broadcastService.sendBroadcast('localeChanged', {
+ broadcast_service.sendBroadcast('localeChanged', {
language: language,
}, { sendToNewAppInstances: true });
};
@@ -3271,7 +3271,7 @@ window.iframe_for_app_instance = (instance_id) => {
};
// Run any callbacks to say that the app has closed
-// ref(./services/ExecService.js): this is called from ExecService.js on
+// ref(./modules/exec.js): this is called from the exec module on
// close if the app does not use puter.js
window.report_app_closed = (instance_id, status_code) => {
const el_window = window.window_for_app_instance(instance_id);
diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js
index 23d7ec793b..ec08d3f131 100644
--- a/src/gui/src/helpers/launch_app.js
+++ b/src/gui/src/helpers/launch_app.js
@@ -19,6 +19,8 @@
import path from '../lib/path.js';
import { PROCESS_IPC_ATTACHED, PROCESS_RUNNING, PortalProcess, PseudoProcess } from '../definitions.js';
+import { process_service } from '../modules/process.js';
+import { broadcast_service } from '../modules/broadcast.js';
import UIWindow from '../UI/UIWindow.js';
const normalizePrivateAccessDecision = (privateAccess) => {
@@ -295,7 +297,7 @@ const launch_app = async (options) => {
app_info: app_info,
},
});
- const svc_process = globalThis.services.get('process');
+ const svc_process = process_service;
svc_process.register(process);
if ( options.path === window.home_path ) {
title = i18n('home');
@@ -367,7 +369,7 @@ const launch_app = async (options) => {
app_info: app_info,
},
});
- const svc_process = globalThis.services.get('process');
+ const svc_process = process_service;
svc_process.register(process);
//-----------------------------------
@@ -691,7 +693,7 @@ const launch_app = async (options) => {
$(process.references.iframe).attr('data-appUsesSDK', 'true');
// Send any saved broadcasts to the new app
- globalThis.services.get('broadcast').sendSavedBroadcastsTo(uuid);
+ broadcast_service.sendSavedBroadcastsTo(uuid);
// If `window-active` is set (meaning the window is focused), focus the window one more time
// this is to ensure that the iframe is `definitely` focused and can receive keyboard events (e.g. keydown)
@@ -704,7 +706,7 @@ const launch_app = async (options) => {
process.chstatus(PROCESS_RUNNING);
$(el).on('remove', () => {
- const svc_process = globalThis.services.get('process');
+ const svc_process = process_service;
svc_process.unregister(process.uuid);
});
diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js
index af63f8354f..7e76237124 100644
--- a/src/gui/src/initgui.js
+++ b/src/gui/src/initgui.js
@@ -44,15 +44,11 @@ import update_last_touch_coordinates from './helpers/update_last_touch_coordinat
import update_mouse_position from './helpers/update_mouse_position.js';
import update_title_based_on_uploads from './helpers/update_title_based_on_uploads.js';
import path from './lib/path.js';
-import { AntiCSRFService } from './services/AntiCSRFService.js';
-import { BroadcastService } from './services/BroadcastService.js';
-import { DebugService } from './services/DebugService.js';
-import { ExecService } from './services/ExecService.js';
-import { IPCService } from './services/IPCService.js';
-import { LaunchOnInitService } from './services/LaunchOnInitService.js';
-import { LocaleService } from './services/LocaleService.js';
-import { ProcessService } from './services/ProcessService.js';
-import { ThemeService } from './services/ThemeService.js';
+import { exec_service } from './modules/exec.js';
+import { debug_service } from './modules/debug.js';
+import { theme_service } from './modules/theme.js';
+import { process_service } from './modules/process.js';
+import { launch_on_init } from './modules/launch-on-init.js';
import { privacy_aware_path } from './util/desktop.js';
const postAuthActions = async (action) => {
@@ -397,75 +393,21 @@ const postAuthActions = async (action) => {
};
const launch_services = async function (options) {
- // === Services Data Structures ===
- const services_l_ = [];
- const services_m_ = {};
- globalThis.services = {
- get: (name) => services_m_[name],
- emit: (id, args) => {
- for (const [_, instance] of services_l_) {
- instance.__on(id, args ?? []);
- }
- },
- };
- const register = (name, instance) => {
- services_l_.push([name, instance]);
- services_m_[name] = instance;
- };
-
globalThis.def(UIComponentWindow, 'ui.UIComponentWindow');
- // === Hooks for Service Scripts from Backend ===
- const service_script_deferred = { services: [], on_ready: [] };
- const service_script_api = {
- register: (...a) => service_script_deferred.services.push(a),
- on_ready: (fn) => service_script_deferred.on_ready.push(fn),
- // Some files can't be imported by service scripts,
- // so this hack makes that possible.
- def: globalThis.def,
- use: globalThis.use,
- // use: name => ({ UIWindow, UIComponentWindow })[name],
- };
- globalThis.service_script_api_promise.resolve(service_script_api);
-
- // === Builtin Services ===
- register('ipc', new IPCService());
- register('exec', new ExecService());
- register('debug', new DebugService());
- register('broadcast', new BroadcastService());
- register('theme', new ThemeService());
- register('process', new ProcessService());
- register('locale', new LocaleService());
- register('anti-csrf', new AntiCSRFService());
- register('__launch-on-init', new LaunchOnInitService());
-
- // === Service-Script Services ===
- for (const [name, script] of service_script_deferred.services) {
- register(name, script);
- }
+ // These modules are plain singletons wired by direct import; their
+ // constructors have already run, so init() just performs the one-time
+ // setup that needs the runtime (DOM, puter, window.ipc_handlers).
+ exec_service.init();
+ debug_service.init();
+ theme_service.init();
+ process_service.init();
- for (const [_, instance] of services_l_) {
- await instance.construct({
- gui_params: options,
- });
- }
-
- for (const [_, instance] of services_l_) {
- await instance.init({
- services: globalThis.services,
- });
- }
-
- // === Service-Script Ready ===
- for (const fn of service_script_deferred.on_ready) {
- await fn();
- }
+ // Run any commands the GUI was launched with.
+ launch_on_init(options);
// Set init process status
- {
- const svc_process = globalThis.services.get('process');
- svc_process.get_init().chstatus(PROCESS_RUNNING);
- }
+ process_service.get_init().chstatus(PROCESS_RUNNING);
};
// This code snippet addresses the issue flagged by Lighthouse regarding the use of
diff --git a/src/gui/src/services/AntiCSRFService.js b/src/gui/src/modules/anti-csrf.js
similarity index 93%
rename from src/gui/src/services/AntiCSRFService.js
rename to src/gui/src/modules/anti-csrf.js
index 306e915a0c..3faa957c0b 100644
--- a/src/gui/src/services/AntiCSRFService.js
+++ b/src/gui/src/modules/anti-csrf.js
@@ -17,9 +17,7 @@
* along with this program. If not, see .
*/
-import { Service } from '../definitions.js';
-
-export class AntiCSRFService extends Service {
+class AntiCSRFService {
/**
* Request an anti-csrf token from the server
* @return anti_csrf: string
@@ -39,3 +37,5 @@ export class AntiCSRFService extends Service {
return anti_csrf;
}
}
+
+export const anti_csrf_service = new AntiCSRFService();
diff --git a/src/gui/src/services/BroadcastService.js b/src/gui/src/modules/broadcast.js
similarity index 94%
rename from src/gui/src/services/BroadcastService.js
rename to src/gui/src/modules/broadcast.js
index 540b4da914..dc0fe1e5a4 100644
--- a/src/gui/src/services/BroadcastService.js
+++ b/src/gui/src/modules/broadcast.js
@@ -17,16 +17,10 @@
* along with this program. If not, see .
*/
-import { Service } from '../definitions.js';
-
-export class BroadcastService extends Service {
+class BroadcastService {
// After a new app is launched, it will receive these broadcasts
#broadcastsToSendToNewAppInstances = new Map(); // name -> data
- async _init () {
- // Nothing
- }
-
// Send a 'broadcast' message to all open apps, with the given name and data.
// If sendToNewAppInstances is true, the message will be saved, and sent to any apps that are launched later.
// A new saved broadcast will replace an earlier one with the same name.
@@ -60,3 +54,5 @@ export class BroadcastService extends Service {
}
}
}
+
+export const broadcast_service = new BroadcastService();
diff --git a/src/gui/src/services/DebugService.js b/src/gui/src/modules/debug.js
similarity index 87%
rename from src/gui/src/services/DebugService.js
rename to src/gui/src/modules/debug.js
index 929522f72d..228ff4bfb9 100644
--- a/src/gui/src/services/DebugService.js
+++ b/src/gui/src/modules/debug.js
@@ -17,16 +17,17 @@
* along with this program. If not, see .
*/
-import { Service } from '../definitions.js';
+import { exec_service } from './exec.js';
-export class DebugService extends Service {
- async _init () {
+class DebugService {
+ constructor () {
// Track enabled log categories
this.enabled_logs = [];
+ }
+ init () {
// Provide enabled logs as a query param
- const svc_exec = this.services.get('exec');
- svc_exec.register_param_provider(() => {
+ exec_service.register_param_provider(() => {
return {
...(this.enabled_logs.length > 0
? { enabled_logs: this.enabled_logs.join(';') }
@@ -48,3 +49,5 @@ export class DebugService extends Service {
});
}
}
+
+export const debug_service = new DebugService();
diff --git a/src/gui/src/services/ExecService.js b/src/gui/src/modules/exec.js
similarity index 92%
rename from src/gui/src/services/ExecService.js
rename to src/gui/src/modules/exec.js
index 9ee686f2c4..ab1c8ea7d3 100644
--- a/src/gui/src/services/ExecService.js
+++ b/src/gui/src/modules/exec.js
@@ -17,15 +17,14 @@
* along with this program. If not, see .
*/
-import { PROCESS_IPC_ATTACHED, Service } from '../definitions.js';
+import { PROCESS_IPC_ATTACHED } from '../definitions.js';
import launch_app from '../helpers/launch_app.js';
+import { broadcast_service } from './broadcast.js';
+import { ipc_service } from './ipc.js';
+import { process_service } from './process.js';
-export class ExecService extends Service {
- static description = `
- Manages instances of apps on the Puter desktop.
- `;
-
- _construct () {
+class ExecService {
+ constructor () {
this.param_providers = [];
}
@@ -33,12 +32,11 @@ export class ExecService extends Service {
this.param_providers.push(param_provider);
}
- async _init ({ services }) {
- const svc_ipc = services.get('ipc');
- svc_ipc.register_ipc_handler('launchApp', {
+ init () {
+ ipc_service.register_ipc_handler('launchApp', {
handler: this.launchApp.bind(this),
});
- svc_ipc.register_ipc_handler('connectToInstance', {
+ ipc_service.register_ipc_handler('connectToInstance', {
handler: this.connectToInstance.bind(this),
});
@@ -55,8 +53,7 @@ export class ExecService extends Service {
// This mechanism will be replated with xdrpc soon
const child_instance_id = window.uuidv4();
- const svc_ipc = this.services.get('ipc');
- const connection = ipc_context ? svc_ipc.add_connection({
+ const connection = ipc_context ? ipc_service.add_connection({
source: process.uuid,
target: child_instance_id,
}) : undefined;
@@ -199,7 +196,7 @@ export class ExecService extends Service {
send_child_launched_msg({ uses_sdk: true });
// Send any saved broadcasts to the new app
- globalThis.services.get('broadcast').sendSavedBroadcastsTo(child_instance_id);
+ broadcast_service.sendSavedBroadcastsTo(child_instance_id);
// If `window-active` is set (meanign the window is focused), focus the window one more time
// this is to ensure that the iframe is `definitely` focused and can receive keyboard events (e.g. keydown)
@@ -245,16 +242,14 @@ export class ExecService extends Service {
throw new Error('Connection not allowed.');
}
- const svc_process = this.services.get('process');
- const options = svc_process.select_by_name(app_name);
+ const options = process_service.select_by_name(app_name);
const process = options[0];
if ( ! process ) {
throw new Error(`No process found: ${app_name}`);
}
- const svc_ipc = this.services.get('ipc');
- const connection = svc_ipc.add_connection({
+ const connection = ipc_service.add_connection({
source: caller_process.uuid,
target: process.uuid,
});
@@ -268,3 +263,5 @@ export class ExecService extends Service {
};
}
}
+
+export const exec_service = new ExecService();
diff --git a/src/gui/src/services/IPCService.js b/src/gui/src/modules/ipc.js
similarity index 78%
rename from src/gui/src/services/IPCService.js
rename to src/gui/src/modules/ipc.js
index 4f8dc634a4..dbffdc3c74 100644
--- a/src/gui/src/services/IPCService.js
+++ b/src/gui/src/modules/ipc.js
@@ -17,11 +17,10 @@
* along with this program. If not, see .
*/
-import { Service } from '../definitions.js';
+import { process_service } from './process.js';
class InternalConnection {
- constructor ({ source, target, uuid, reverse }, { services }) {
- this.services = services;
+ constructor ({ source, target, uuid, reverse }) {
this.source = source;
this.target = target;
this.uuid = uuid;
@@ -29,8 +28,7 @@ class InternalConnection {
}
send (data) {
- const svc_process = this.services.get('process');
- const process = svc_process.get_by_uuid(this.target);
+ const process = process_service.get_by_uuid(this.target);
const channel = {
returnAddress: this.reverse,
};
@@ -38,12 +36,8 @@ class InternalConnection {
}
}
-export class IPCService extends Service {
- static description = `
- Allows other services to expose methods to apps.
- `;
-
- async _init () {
+class IPCService {
+ constructor () {
this.connections_ = {};
}
@@ -69,10 +63,12 @@ export class IPCService extends Service {
const entry = this.connections_[uuid];
if ( ! entry ) return;
if ( entry.object ) return entry.object;
- return entry.object = new InternalConnection(entry, this.context);
+ return entry.object = new InternalConnection(entry);
}
register_ipc_handler (name, spec) {
window.ipc_handlers[name] = spec;
}
}
+
+export const ipc_service = new IPCService();
diff --git a/src/gui/src/services/LaunchOnInitService.js b/src/gui/src/modules/launch-on-init.js
similarity index 51%
rename from src/gui/src/services/LaunchOnInitService.js
rename to src/gui/src/modules/launch-on-init.js
index 87780a3da3..8a10a0cab2 100644
--- a/src/gui/src/services/LaunchOnInitService.js
+++ b/src/gui/src/modules/launch-on-init.js
@@ -16,32 +16,27 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-import UIAlert from '../UI/UIAlert.js';
-import { Service } from '../definitions.js';
+const commands = {
+ 'window-call': ({ fn_name, args }) => {
+ window[fn_name](...args);
+ },
+};
-export class LaunchOnInitService extends Service {
- _construct () {
- this.commands = {
- 'window-call': ({ fn_name, args }) => {
- window[fn_name](...args);
- },
- };
- }
- async _init () {
- const launch_options = this.$puter.gui_params.launch_options;
- if ( ! launch_options ) return;
+const run_command = (command) => {
+ const args = { ...command };
+ delete args.$;
+ commands[command.$](args);
+};
- if ( launch_options.on_initialized ) {
- for ( const command of launch_options.on_initialized ) {
- this.run_(command);
- }
- }
- }
+// Run any commands the GUI was launched with (gui_params.launch_options.on_initialized).
+export const launch_on_init = (gui_params) => {
+ const launch_options = gui_params?.launch_options;
+ if ( ! launch_options ) return;
- run_ (command) {
- const args = { ...command };
- delete args.$;
- this.commands[command.$](args);
+ if ( launch_options.on_initialized ) {
+ for ( const command of launch_options.on_initialized ) {
+ run_command(command);
+ }
}
-}
+};
diff --git a/src/gui/src/services/LocaleService.js b/src/gui/src/modules/locale.js
similarity index 94%
rename from src/gui/src/services/LocaleService.js
rename to src/gui/src/modules/locale.js
index 036087f193..61d088a6b1 100644
--- a/src/gui/src/services/LocaleService.js
+++ b/src/gui/src/modules/locale.js
@@ -16,10 +16,9 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-import { Service } from '../definitions.js';
import i18n from '../i18n/i18n.js';
-export class LocaleService extends Service {
+class LocaleService {
format_duration (seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
@@ -41,3 +40,5 @@ export class LocaleService extends Service {
return `${paddedHours}:${paddedMinutes}:${paddedSeconds}`;
}
}
+
+export const locale_service = new LocaleService();
diff --git a/src/gui/src/services/ProcessService.js b/src/gui/src/modules/process.js
similarity index 92%
rename from src/gui/src/services/ProcessService.js
rename to src/gui/src/modules/process.js
index b4fdaca5c6..c5e90551d0 100644
--- a/src/gui/src/services/ProcessService.js
+++ b/src/gui/src/modules/process.js
@@ -16,35 +16,37 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-import { InitProcess, Service } from '../definitions.js';
+import { InitProcess } from '../definitions.js';
+import { exec_service } from './exec.js';
// The NULL UUID is also the UUID for the init process.
const NULL_UUID = '00000000-0000-0000-0000-000000000000';
-export class ProcessService extends Service {
+class ProcessService {
static INITRC = [
// 'puter-linux'
];
- async _init () {
+ constructor () {
this.processes = [];
this.processes_map = new Map();
this.uuid_to_treelist = new Map();
+ }
+ init () {
const root = new InitProcess({
uuid: NULL_UUID,
});
this.register_(root);
}
- ['__on_gui:ready'] () {
- const svc_exec = this.services.get('exec');
+ on_gui_ready () {
for ( let spec of ProcessService.INITRC ) {
if ( typeof spec === 'string' ) {
spec = { name: spec };
}
- svc_exec.launchApp({
+ exec_service.launchApp({
app_name: spec.name,
});
}
@@ -120,3 +122,5 @@ export class ProcessService extends Service {
}
}
}
+
+export const process_service = new ProcessService();
diff --git a/src/gui/src/services/ThemeService.js b/src/gui/src/modules/theme.js
similarity index 94%
rename from src/gui/src/services/ThemeService.js
rename to src/gui/src/modules/theme.js
index 189b1e81b0..76827c201d 100644
--- a/src/gui/src/services/ThemeService.js
+++ b/src/gui/src/modules/theme.js
@@ -18,7 +18,7 @@
*/
import UIAlert from '../UI/UIAlert.js';
-import { Service } from '../definitions.js';
+import { broadcast_service } from './broadcast.js';
const PUTER_THEME_DATA_FILENAME = '~/.__puter_gui.json';
@@ -32,12 +32,8 @@ const default_values = {
light_text: false,
};
-export class ThemeService extends Service {
- #broadcastService;
-
- async _init () {
- this.#broadcastService = globalThis.services.get('broadcast');
-
+class ThemeService {
+ init () {
this.state = {
sat: 41.18,
hue: 210,
@@ -129,7 +125,7 @@ export class ThemeService extends Service {
this.root.style.setProperty('--primary-color-sidebar-item', s.light_text ? '#5a5d61aa' : '#fefeff');
// TODO: Should we debounce this to reduce traffic?
- this.#broadcastService.sendBroadcast('themeChanged', {
+ broadcast_service.sendBroadcast('themeChanged', {
palette: {
primaryHue: s.hue,
primarySaturation: `${s.sat }%`,
@@ -154,3 +150,5 @@ export class ThemeService extends Service {
5));
}
}
+
+export const theme_service = new ThemeService();