Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(daemon,cli): Serve one weblet per fixed HTTP port. #2148

Merged
merged 11 commits into from
Mar 16, 2024
Merged
6 changes: 3 additions & 3 deletions packages/cli/demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,16 +248,16 @@ messages from your various guests.
Weblets are web page caplets.
These are programs, like the counter and doubler above, except that
they run in a web page.
The pet daemon can host any number of fully independent web applications on
subdomains of `endo.localhost:8920`.
Each of these applications is connected to the pet daemon and can make
the same kinds of requests for data and powers.
Each weblet runs on a separate local HTTP port so they have independent
origins, so they own their local storage.

_Familiar Chat_ is an example application that provides a web app for
interacting with your pet daemon.

```
> endo install familiar-chat cat.js --powers SELF
> endo install cat.js --listen 8920 --powers SELF --name familiar-chat
```

This command creates a web page named familiar-chat and endows it with the
Expand Down
12 changes: 5 additions & 7 deletions packages/cli/demo/cat.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const dateFormatter = new window.Intl.DateTimeFormat(undefined, {
timeStyle: 'long',
});

const followMessagesComponent = async ($parent, $end, powers) => {
const inboxComponent = async ($parent, $end, powers) => {
for await (const message of makeRefIterator(E(powers).followMessages())) {
const { number, who, when, dismissed } = message;

Expand Down Expand Up @@ -183,7 +183,7 @@ const followMessagesComponent = async ($parent, $end, powers) => {
}
};

const followNamesComponent = async ($parent, $end, powers) => {
const inventoryComponent = async ($parent, $end, powers) => {
const $title = document.createElement('h2');
$title.innerText = 'Inventory';
$parent.insertBefore($title, $end);
Expand All @@ -192,7 +192,7 @@ const followNamesComponent = async ($parent, $end, powers) => {
$parent.insertBefore($ul, $end);

const $names = new Map();
for await (const change of makeRefIterator(E(powers).followNames())) {
for await (const change of makeRefIterator(E(powers).followChanges())) {
if ('add' in change) {
const name = change.add;

Expand Down Expand Up @@ -226,13 +226,11 @@ const bodyComponent = ($parent, powers) => {

const $endOfMessages = document.createTextNode('');
$parent.appendChild($endOfMessages);
followMessagesComponent($parent, $endOfMessages, powers).catch(
window.reportError,
);
inboxComponent($parent, $endOfMessages, powers).catch(window.reportError);

const $endOfNames = document.createTextNode('');
$parent.appendChild($endOfNames);
followNamesComponent($parent, $endOfNames, powers).catch(window.reportError);
inventoryComponent($parent, $endOfNames, powers).catch(window.reportError);
};

export const make = async powers => {
Expand Down
29 changes: 14 additions & 15 deletions packages/cli/src/commands/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export const install = async ({
bundleName,
partyNames,
powersName,
webPageName,
webletName,
requestedPort,
programPath,
doOpen,
}) => {
Expand Down Expand Up @@ -45,21 +46,19 @@ export const install = async ({
}

try {
/** @type {string | undefined} */
let webPageUrl;
if (bundleName !== undefined) {
({ url: webPageUrl } = await E(party).provideWebPage(
webPageName,
bundleName,
powersName,
));
} else {
({ url: webPageUrl } = await E(party).lookup(webPageName));
}
assert(webPageUrl !== undefined);
process.stdout.write(`${webPageUrl}\n`);
const weblet = E(party).evaluate(
'MAIN',
`E(apps).makeWeblet(bundle, powers, ${JSON.stringify(
requestedPort,
)}, $id, $cancelled)`,
['apps', 'bundle', 'powers'],
['APPS', bundleName, powersName],
webletName,
);
const webletLocation = await E(weblet).getLocation();
process.stdout.write(`${webletLocation}\n`);
if (doOpen) {
openWebPage(webPageUrl);
openWebPage(webletLocation);
}
} finally {
if (temporaryBundleName) {
Expand Down
9 changes: 5 additions & 4 deletions packages/cli/src/commands/open.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import { E } from '@endo/far';

import { withEndoParty } from '../context.js';

export const open = async ({ webPageName, partyNames }) => {
export const open = async ({ webletName, partyNames }) => {
await withEndoParty(partyNames, { os, process }, async ({ party }) => {
const { url: webPageUrl } = await E(party).lookup(webPageName);
process.stdout.write(`${webPageUrl}\n`);
openWebPage(webPageUrl);
const weblet = E(party).lookup(webletName);
const webletLocation = await E(weblet).getLocation();
process.stdout.write(`${webletLocation}\n`);
openWebPage(webletLocation);
});
};
39 changes: 33 additions & 6 deletions packages/cli/src/endo.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-nocheck
/* global process */
/* eslint-disable no-await-in-loop */
/* eslint-disable no-await-in-loop, no-bitwise, no-throw-literal */

// Establish a perimeter:
import 'ses';
Expand All @@ -23,6 +23,10 @@ const commonOptions = {
'-n,--name <name>',
'Assigns a name to the result for future reference',
],
requiredName: [
'-n,--name <name>',
'Assigns a name to the result for future reference (required)',
],
};

const parseOptionAsMapping = (optionValueString, obj) => {
Expand All @@ -48,26 +52,49 @@ export const main = async rawArgs => {
program.name('endo').version(packageDescriptor.version);

program
.command('install <name> [filePath]')
.command('install [filePath]')
.description('installs a web page (weblet)')
.option(...commonOptions.as)
.option(
'-l,--listen,--port <number>',
'Port assignment (required)',
(arg, previous) => {
if (previous !== undefined) {
throw `-l,--listen,--port can only be specified once`;
}
const port = parseInt(arg, 10);
if (Number.isNaN(port) || (port & ~0xffff) !== 0) {
throw `-l,--listen,--port flag must be a valid port number, got ${JSON.stringify(
arg,
)}`;
}
return port;
},
)
.option('-b,--bundle <bundle>', 'Bundle for a web page (weblet)')
.option(
'-p,--powers <endowment>',
'Endowment to give the weblet (a name, NONE, SELF, or ENDO)',
)
.option(...commonOptions.requiredName)
.option('-o,--open', 'Open the new web page immediately (weblet)')
.action(async (webPageName, programPath, cmd) => {
.action(async (programPath, cmd) => {
const {
name: webletName,
bundle: bundleName,
powers: powersName = 'NONE',
listen: requestedPort,
as: partyNames,
open: doOpen,
} = cmd.opts();
if (requestedPort === undefined) {
throw 'The -l, --listen, or --port <number> flag is required';
}
const { install } = await import('./commands/install.js');
return install({
doOpen,
webPageName,
webletName,
requestedPort,
programPath,
bundleName,
powersName,
Expand All @@ -79,11 +106,11 @@ export const main = async rawArgs => {
.command('open <name>')
.description('opens a web page (weblet)')
.option(...commonOptions.as)
.action(async (webPageName, cmd) => {
.action(async (webletName, cmd) => {
const { as: partyNames } = cmd.opts();
const { open } = await import('./commands/open.js');
return open({
webPageName,
webletName,
partyNames,
});
});
Expand Down
3 changes: 0 additions & 3 deletions packages/daemon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@ export const start = async (locator = defaultLocator) => {
const output = fs.openSync(logPath, 'a');

const env = { ...process.env };
if (locator.httpPort !== undefined) {
env.ENDO_HTTP_PORT = `${locator.httpPort}`;
}

const child = popen.fork(
endoDaemonPath,
Expand Down
1 change: 1 addition & 0 deletions packages/daemon/src/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const makeContextMaker = ({
};

return {
id: formulaIdentifier,
cancel,
cancelled,
disposed,
Expand Down
Loading
Loading