mirror of
https://github.com/HeyPuter/puter.git
synced 2025-12-31 02:00:13 -06:00
PDE command provider
This commit is contained in:
committed by
Eric Dubé
parent
5169d4bb40
commit
fd387597bb
@@ -37,6 +37,7 @@ import { CompositeCommandProvider } from './providers/CompositeCommandProvider.j
|
||||
import { ScriptCommandProvider } from './providers/ScriptCommandProvider.js';
|
||||
import { PuterAppCommandProvider } from './providers/PuterAppCommandProvider.js';
|
||||
import { EmuCommandProvider } from './providers/EmuCommandProvider.js';
|
||||
import { PDECommandProvider } from './providers/PDECommandProvider.js';
|
||||
|
||||
const argparser_registry = {
|
||||
[SimpleArgParser.name]: SimpleArgParser
|
||||
@@ -90,6 +91,7 @@ export const launchPuterShell = async (ctx) => {
|
||||
...(ctx.platform.name === 'puter' ? [new PuterAppCommandProvider()] : []),
|
||||
new ScriptCommandProvider(),
|
||||
new EmuCommandProvider(),
|
||||
new PDECommandProvider()
|
||||
]);
|
||||
|
||||
ctx = ctx.sub({
|
||||
|
||||
187
src/phoenix/src/puter-shell/providers/PDECommandProvider.js
Normal file
187
src/phoenix/src/puter-shell/providers/PDECommandProvider.js
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (C) 2024-present 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 { Exit } from '../coreutils/coreutil_lib/exit.js';
|
||||
import { signals } from '../../ansi-shell/signals.js';
|
||||
|
||||
const BUILT_IN_APPS = [
|
||||
'explorer',
|
||||
];
|
||||
|
||||
const lookup_app = async (id) => {
|
||||
// if (BUILT_IN_APPS.includes(id)) {
|
||||
// return { success: true, path: null };
|
||||
// }
|
||||
|
||||
const request = await fetch(`${puter.APIOrigin}/drivers/call`, {
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${puter.authToken}`,
|
||||
},
|
||||
"body": JSON.stringify({ interface: 'puter-apps', method: 'read', args: { id: { name: id } } }),
|
||||
"method": "POST",
|
||||
});
|
||||
|
||||
const { success, result } = await request.json();
|
||||
return { success, path: result?.index_url };
|
||||
};
|
||||
|
||||
export class PDECommandProvider {
|
||||
|
||||
async lookup (id) {
|
||||
try {
|
||||
await puter.fs.stat("/admin/Public/bin/" + id + ".pde")
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
const { success, path } = await lookup_app("pderunner");
|
||||
|
||||
return {
|
||||
name: id,
|
||||
path: path ?? 'Built-in Puter app',
|
||||
// TODO: Let apps expose option/positional definitions like builtins do, and parse them here?
|
||||
async execute(ctx) {
|
||||
console.log(ctx)
|
||||
const args = {
|
||||
command_line: {
|
||||
args: ["/admin/Public/bin/" + id + ".pde" , ...ctx.locals.args],
|
||||
},
|
||||
env: {...ctx.env},
|
||||
};
|
||||
console.log(args)
|
||||
const child = await puter.ui.launchApp("pderunner", args);
|
||||
|
||||
const resize_listener = evt => {
|
||||
child.postMessage({
|
||||
$: 'ioctl.set',
|
||||
windowSize: {
|
||||
rows: evt.detail.rows,
|
||||
cols: evt.detail.cols,
|
||||
}
|
||||
});
|
||||
};
|
||||
ctx.shell.addEventListener('signal.window-resize', resize_listener);
|
||||
|
||||
// Wait for app to close.
|
||||
// console.log('waiting for app to close (phoenix)', window, {
|
||||
// child_appid: child.targetAppInstanceID,
|
||||
// phoen_appid: puter.appInstanceID,
|
||||
// });
|
||||
const app_close_promise = new Promise((resolve, reject) => {
|
||||
child.on('close', (data) => {
|
||||
if ((data.statusCode ?? 0) != 0) {
|
||||
reject(new Exit(data.statusCode));
|
||||
} else {
|
||||
resolve({ done: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Wait for SIGINT
|
||||
const sigint_promise = new Promise((resolve, reject) => {
|
||||
ctx.externs.sig.on((signal) => {
|
||||
if (signal === signals.SIGINT) {
|
||||
child.close();
|
||||
reject(new Exit(130));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// We don't connect stdio to non-SDK apps, because they won't make use of it.
|
||||
if (child.usesSDK) {
|
||||
const decoder = new TextDecoder();
|
||||
child.on('message', message => {
|
||||
if (message.$ === 'stdout') {
|
||||
ctx.externs.out.write(decoder.decode(message.data));
|
||||
}
|
||||
if (message.$ === 'chtermios') {
|
||||
if ( message.termios.echo !== undefined ) {
|
||||
if ( message.termios.echo ) {
|
||||
ctx.externs.echo.on();
|
||||
} else {
|
||||
ctx.externs.echo.off();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Repeatedly copy data from stdin to the child, while it's running.
|
||||
// DRY: Initially copied from PathCommandProvider
|
||||
let data, done;
|
||||
const next_data = async () => {
|
||||
({ value: data, done } = await Promise.race([
|
||||
app_close_promise, sigint_promise, ctx.externs.in_.read(),
|
||||
]));
|
||||
if (data) {
|
||||
child.postMessage({
|
||||
$: 'stdin',
|
||||
data: data,
|
||||
});
|
||||
if (!done) setTimeout(next_data, 0);
|
||||
}
|
||||
};
|
||||
setTimeout(next_data, 0);
|
||||
}
|
||||
|
||||
// TODO: propagate sigint to the app
|
||||
const exit = await Promise.race([ app_close_promise, sigint_promise ]);
|
||||
ctx.shell.removeEventListener('signal.window-resize', resize_listener);
|
||||
return exit;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Only a single Puter app can match a given name
|
||||
async lookupAll (...a) {
|
||||
const result = await this.lookup(...a);
|
||||
if ( result ) {
|
||||
return [ result ];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async complete (query, { ctx }) {
|
||||
if (query === '') return [];
|
||||
|
||||
const results = [];
|
||||
|
||||
// for (const app_name of BUILT_IN_APPS) {
|
||||
// if (app_name.startsWith(query)) {
|
||||
// results.push(app_name);
|
||||
// }
|
||||
// }
|
||||
|
||||
// const request = await fetch(`${puter.APIOrigin}/drivers/call`, {
|
||||
// "headers": {
|
||||
// "Content-Type": "application/json",
|
||||
// "Authorization": `Bearer ${puter.authToken}`,
|
||||
// },
|
||||
// "body": JSON.stringify({ interface: 'puter-apps', method: 'select', args: { predicate: [ 'name-like', query + '%' ] } }),
|
||||
// "method": "POST",
|
||||
// });
|
||||
|
||||
// const json = await request.json();
|
||||
// if (json.success) {
|
||||
// for (const app of json.result) {
|
||||
// results.push(app.name);
|
||||
// }
|
||||
// }
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user