Преглед на файлове

Add support for launching child apps

Calling `puter.ui.launchApp()` now treats the new app as a child of the
one that launched it.

A child app is given a `puter.parent_instance_id` URL param, containing
its parent's instance ID.

Previously, `launchApp()` would resolve as soon as the app was launched.
This commit changes that, so that it is notified after the child app
sends its READY event to Puter. This means that as soon as `launchApp()`
has completed, the child app is ready to receive messages. The downside
is that launching an app that does not include Puter.js will now not
cause a notification, so `await puter.ui.launchApp()` will not resolve
in that case.
Sam Atkins преди 1 година
родител
ревизия
725cbf2e20
променени са 3 файла, в които са добавени 32 реда и са изтрити 7 реда
  1. 23 6
      src/IPC.js
  2. 3 0
      src/globals.js
  3. 6 1
      src/helpers.js

+ 23 - 6
src/IPC.js

@@ -92,6 +92,19 @@ window.addEventListener('message', async (event) => {
     //-------------------------------------------------
     if(event.data.msg === 'READY'){
         $(target_iframe).attr('data-appUsesSDK', 'true');
+
+        // If we were waiting to launch this as a child app, report to the parent that it succeeded.
+        const child_launch_callback = window.child_launch_callbacks[event.data.appInstanceID];
+        if (child_launch_callback) {
+            const parent_iframe = iframe_for_app_instance(child_launch_callback.parent_instance_id);
+            // send confirmation to requester window
+            parent_iframe.contentWindow.postMessage({
+                msg: 'childAppLaunched',
+                original_msg_id: child_launch_callback.launch_msg_id,
+                child_instance_id: event.data.appInstanceID,
+            }, '*');
+            delete window.child_launch_callbacks[event.data.appInstanceID];
+        }
     }
     //-------------------------------------------------
     // windowFocused
@@ -500,16 +513,20 @@ window.addEventListener('message', async (event) => {
     // launchApp
     //--------------------------------------------------------
     else if(event.data.msg === 'launchApp'){
-        // launch app
+        // TODO: Determine if the app is allowed to launch child apps? We may want to limit this to prevent abuse.
+        // remember app for launch callback later
+        const child_instance_id = uuidv4();
+        window.child_launch_callbacks[child_instance_id] = {
+            parent_instance_id: event.data.appInstanceID,
+            launch_msg_id: msg_id,
+        };
+        // launch child app
         launch_app({
             name: event.data.app_name ?? app_name,
             args: event.data.args ?? {},
+            parent_instance_id: event.data.appInstanceID,
+            uuid: child_instance_id,
         });
-
-        // send confirmation to requester window
-        target_iframe.contentWindow.postMessage({
-            original_msg_id: msg_id, 
-        }, '*');
     }
     //--------------------------------------------------------
     // readAppDataFile

+ 3 - 0
src/globals.js

@@ -130,6 +130,9 @@ window.launch_apps = [];
 window.launch_apps.recent = []
 window.launch_apps.recommended = []
 
+// Map of { child_instance_id -> { parent_instance_id, launch_msg_id } }
+window.child_launch_callbacks = {};
+
 // Is puter being loaded inside an iframe?
 if (window.location !== window.parent.location) {
     window.is_embedded = true;

+ 6 - 1
src/helpers.js

@@ -1849,7 +1849,7 @@ window.trigger_download = (paths)=>{
  * @param {*} options 
  */
 window.launch_app = async (options)=>{
-    const uuid = uuidv4();
+    const uuid = options.uuid ?? uuidv4();
     let icon, title, file_signature;
     const window_options = options.window_options ?? {};
 
@@ -1945,6 +1945,11 @@ window.launch_app = async (options)=>{
         // add app_id to URL
         iframe_url.searchParams.append('puter.app.id', app_info.uuid);
 
+        // add parent_app_instance_id to URL
+        if (options.parent_instance_id) {
+            iframe_url.searchParams.append('puter.parent_instance_id', options.parent_instance_id);
+        }
+
         if(file_signature){
             iframe_url.searchParams.append('puter.item.uid', file_signature.uid);
             iframe_url.searchParams.append('puter.item.path', options.file_path ? `~/` + options.file_path.split('/').slice(1).join('/') : file_signature.path);