Add a message broadcasting service

A broadcast is a message sent to every running app that uses Puter.js.
Broadcasts have a name and a data payload, and are sent as a 'broadcast'
message.

Send a broadcast using:
`globalThis.services.get('broadcast').sendBroadcast(...)`

When doing so, you have the option to keep the broadcast message around,
so that it can be sent to any newly-launched apps. Sending another
broadcast with the same name will overwrite the previous one, so you
don't have to worry about flooding a new app with duplicates.
This commit is contained in:
Sam Atkins 2024-04-09 10:39:06 +01:00
parent 79f98795c7
commit 068e620249
3 changed files with 66 additions and 0 deletions

View File

@ -105,6 +105,9 @@ window.addEventListener('message', async (event) => {
}, '*');
delete window.child_launch_callbacks[event.data.appInstanceID];
}
// Send any saved broadcasts to the new app
globalThis.services.get('broadcast').sendSavedBroadcastsTo(event.data.appInstanceID);
}
//-------------------------------------------------
// windowFocused

View File

@ -36,6 +36,7 @@ import PuterDialog from './UI/PuterDialog.js';
import determine_active_container_parent from './helpers/determine_active_container_parent.js';
import { ThemeService } from './services/ThemeService.js';
import UIWindowThemeDialog from './UI/UIWindowThemeDialog.js';
import { BroadcastService } from './services/BroadcastService.js';
const launch_services = async function () {
const services_l_ = [];
@ -49,6 +50,7 @@ const launch_services = async function () {
services_m_[name] = instance;
}
register('broadcast', new BroadcastService());
register('theme', new ThemeService());
for (const [_, instance] of services_l_) {

View File

@ -0,0 +1,61 @@
/**
* Copyright (C) 2024 Puter Technologies Inc.
*
* This file is part of Puter.
*
* Puter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Service } from "../definitions.js";
export class BroadcastService extends Service {
// 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.
sendBroadcast(name, data, { sendToNewAppInstances = false } = {}) {
$('.window-app-iframe[data-appUsesSDK=true]').each((_, iframe) => {
iframe.contentWindow.postMessage({
msg: 'broadcast',
name: name,
data: data,
}, '*');
});
if (sendToNewAppInstances) {
this.#broadcastsToSendToNewAppInstances.set(name, data);
}
}
// Send all saved broadcast messages to the given app instance.
sendSavedBroadcastsTo(appInstanceID) {
const iframe = $(`.window[data-element_uuid="${appInstanceID}"] .window-app-iframe[data-appUsesSDK=true]`).get(0);
if (!iframe) {
console.error(`Attempted to send saved broadcasts to app instance ${appInstanceID}, which is not using the Puter SDK`);
return;
}
for (const [name, data] of this.#broadcastsToSendToNewAppInstances) {
iframe.contentWindow.postMessage({
msg: 'broadcast',
name: name,
data: data,
}, '*');
}
}
}