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();