Skip to content

Commit

Permalink
feat(daemon): multiplayer #2114
Browse files Browse the repository at this point in the history
feat(daemon): multiplayer
  • Loading branch information
kumavis authored Mar 7, 2024
2 parents 111c2ff + f0451bd commit 37b17ee
Show file tree
Hide file tree
Showing 10 changed files with 877 additions and 68 deletions.
396 changes: 367 additions & 29 deletions packages/daemon/src/daemon.js

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions packages/daemon/src/directory.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,21 @@ export const makeDirectoryMaker = ({
return hub.list();
};

/** @type {import('./types.js').EndoDirectory['listIdentifiers']} */
const listIdentifiers = async (...petNamePath) => {
const names = await list(...petNamePath);
const identities = new Set();
await Promise.all(
names.map(async name => {
const formulaIdentifier = await identify(...petNamePath, name);
if (formulaIdentifier !== undefined) {
identities.add(formulaIdentifier);
}
}),
);
return harden(Array.from(identities).sort());
};

/** @type {import('./types.js').EndoDirectory['followChanges']} */
const followChanges = async function* followChanges(...petNamePath) {
if (petNamePath.length === 0) {
Expand Down Expand Up @@ -179,6 +194,7 @@ export const makeDirectoryMaker = ({
has,
identify,
list,
listIdentifiers,
followChanges,
lookup,
reverseLookup,
Expand Down
12 changes: 9 additions & 3 deletions packages/daemon/src/formula-identifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ export const parseFormulaIdentifier = formulaIdentifier => {
);
}

const type = formulaIdentifier.slice(0, delimiterIndex);
const number = formulaIdentifier.slice(delimiterIndex + 1);
return { type, number };
const [type, number, node] = formulaIdentifier.split(':');
return { type, number, node };
};

/**
* @param {import("./types").FormulaIdentifierRecord} formulaRecord
* @returns {string}
*/
export const serializeFormulaIdentifier = ({ type, number, node }) =>
`${type}:${number}:${node}`;
2 changes: 2 additions & 0 deletions packages/daemon/src/guest.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export const makeGuestMaker = ({
has,
identify,
list,
listIdentifiers,
followChanges,
lookup,
reverseLookup,
Expand Down Expand Up @@ -97,6 +98,7 @@ export const makeGuestMaker = ({
has,
identify,
list,
listIdentifiers,
followChanges,
lookup,
reverseLookup,
Expand Down
55 changes: 50 additions & 5 deletions packages/daemon/src/host.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check

import { Far } from '@endo/far';
import { E, Far } from '@endo/far';
import { makeIteratorRef } from './reader-ref.js';
import { assertPetName, petNamePathFrom } from './pet-name.js';
import { makePetSitter } from './pet-sitter.js';
Expand All @@ -21,8 +21,10 @@ const { quote: q } = assert;
* @param {import('./types.js').DaemonCore['incarnateWebBundle']} args.incarnateWebBundle
* @param {import('./types.js').DaemonCore['incarnateHandle']} args.incarnateHandle
* @param {import('./types.js').DaemonCore['storeReaderRef']} args.storeReaderRef
* @param {import('./types.js').DaemonCore['getAllNetworkAddresses']} args.getAllNetworkAddresses
* @param {import('./types.js').MakeMailbox} args.makeMailbox
* @param {import('./types.js').MakeDirectoryNode} args.makeDirectoryNode
* @param {string} args.ownNodeIdentifier
*/
export const makeHostMaker = ({
provideValueForFormulaIdentifier,
Expand All @@ -37,24 +39,28 @@ export const makeHostMaker = ({
incarnateWebBundle,
incarnateHandle,
storeReaderRef,
getAllNetworkAddresses,
makeMailbox,
makeDirectoryNode,
ownNodeIdentifier,
}) => {
/**
* @param {string} hostFormulaIdentifier
* @param {string} endoFormulaIdentifier
* @param {string} storeFormulaIdentifier
* @param {string} inspectorFormulaIdentifier
* @param {string} mainWorkerFormulaIdentifier
* @param {string} endoFormulaIdentifier
* @param {string} networksDirectoryFormulaIdentifier
* @param {string} leastAuthorityFormulaIdentifier
* @param {import('./types.js').Context} context
*/
const makeIdentifiedHost = async (
hostFormulaIdentifier,
endoFormulaIdentifier,
storeFormulaIdentifier,
inspectorFormulaIdentifier,
mainWorkerFormulaIdentifier,
endoFormulaIdentifier,
networksDirectoryFormulaIdentifier,
leastAuthorityFormulaIdentifier,
context,
) => {
Expand All @@ -69,6 +75,7 @@ export const makeHostMaker = ({
const specialStore = makePetSitter(basePetStore, {
SELF: hostFormulaIdentifier,
ENDO: endoFormulaIdentifier,
NETS: networksDirectoryFormulaIdentifier,
INFO: inspectorFormulaIdentifier,
NONE: leastAuthorityFormulaIdentifier,
});
Expand All @@ -80,6 +87,15 @@ export const makeHostMaker = ({
});
const { petStore } = mailbox;
const directory = makeDirectoryNode(petStore);
const { lookup } = directory;

const getEndoBootstrap = async () => {
const endoBootstrap =
/** @type {import('./types.js').FarEndoBootstrap} */ (
await provideValueForFormulaIdentifier(endoFormulaIdentifier)
);
return endoBootstrap;
};

/**
* @returns {Promise<{ formulaIdentifier: string, value: import('./types').ExternalHandle }>}
Expand Down Expand Up @@ -326,7 +342,7 @@ export const makeHostMaker = ({

if (resultName !== undefined) {
addHook(identifiers =>
petStore.write(resultName, `eval:${identifiers.evalFormulaNumber}`),
petStore.write(resultName, identifiers.evalFormulaIdentifier),
);
}

Expand Down Expand Up @@ -438,6 +454,7 @@ export const makeHostMaker = ({
const { formulaIdentifier: newFormulaIdentifier, value } =
await incarnateHost(
endoFormulaIdentifier,
networksDirectoryFormulaIdentifier,
leastAuthorityFormulaIdentifier,
);
if (petName !== undefined) {
Expand Down Expand Up @@ -514,12 +531,36 @@ export const makeHostMaker = ({
return cancelValue(formulaIdentifier, reason);
};

/** @type {import('./types.js').EndoHost['gateway']} */
const gateway = async () => {
const endoBootstrap = getEndoBootstrap();
return E(endoBootstrap).gateway();
};

/** @type {import('./types.js').EndoHost['addPeerInfo']} */
const addPeerInfo = async peerInfo => {
const endoBootstrap = getEndoBootstrap();
await E(endoBootstrap).addPeerInfo(peerInfo);
};

/** @type {import('./types.js').EndoHost['getPeerInfo']} */
const getPeerInfo = async () => {
const addresses = await getAllNetworkAddresses(
networksDirectoryFormulaIdentifier,
);
const peerInfo = {
node: ownNodeIdentifier,
addresses,
};
return peerInfo;
};

const {
has,
identify,
list,
listIdentifiers,
followChanges,
lookup,
reverseLookup,
write,
remove,
Expand All @@ -546,6 +587,7 @@ export const makeHostMaker = ({
has,
identify,
list,
listIdentifiers,
followChanges,
lookup,
reverseLookup,
Expand Down Expand Up @@ -574,6 +616,9 @@ export const makeHostMaker = ({
makeBundle,
provideWebPage,
cancel,
gateway,
getPeerInfo,
addPeerInfo,
};

const external = Far('EndoHost', {
Expand Down
25 changes: 25 additions & 0 deletions packages/daemon/src/networks/loopback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// @ts-check
import { Far } from '@endo/far';

/**
* @param {object} args
* @param {import('../types.js').DaemonCore['provideValueForFormulaIdentifier']} args.provideValueForFormulaIdentifier
* @returns {import('@endo/far').FarRef<import('../types.js').EndoNetwork>}
*/
export const makeLoopbackNetwork = ({ provideValueForFormulaIdentifier }) => {
return Far(
'Loopback Network',
/** @type {import('../types.js').EndoNetwork} */ ({
addresses: () => [],
supports: address => new URL(address).protocol === 'loop:',
connect: address => {
if (address !== 'loop:') {
throw new Error(
'Failed invariant: loopback only supports "loop:" address',
);
}
return { provide: provideValueForFormulaIdentifier };
},
}),
);
};
Loading

0 comments on commit 37b17ee

Please sign in to comment.