Skip to content

Commit

Permalink
Open refactor(daemon): Synchronize incarnateReadableBlob() (merge #2142
Browse files Browse the repository at this point in the history
)

Progresses: #2086 

Merges the daemon's `storeReaderRef()` into `incarnateReadableBlob()` and synchronizes the implementation. Also converts `makeReadableBlob()` into `makeControllerForReadableBlob()` to align it with the family of functions that already exist for most other formulas.

Contrary to its predecessor, `incarnateReadableBlob()` returns the value for stored value, namely a `FarEndoReadable`. A unit test is added for the case of immediately using a stored value without naming it.
  • Loading branch information
rekmarks authored Mar 16, 2024
2 parents 5fadd4a + d1fb664 commit f162e19
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 48 deletions.
3 changes: 0 additions & 3 deletions packages/daemon/src/daemon-node-powers.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,15 +288,13 @@ export const makeCryptoPowers = crypto => {
};

/**
* @param {(URL) => string} fileURLToPath
* @param {import('./types.js').FilePowers} filePowers
* @param {import('./types.js').CryptoPowers} cryptoPowers
* @param {import('./types.js').Locator} locator
* @param {boolean} [includeWebPageBundler]
* @returns {import('./types.js').DaemonicPersistencePowers}
*/
export const makeDaemonicPersistencePowers = (
fileURLToPath,
filePowers,
cryptoPowers,
locator,
Expand Down Expand Up @@ -565,7 +563,6 @@ export const makeDaemonicPowers = ({

const petStorePowers = makePetStoreMaker(filePowers, locator);
const daemonicPersistencePowers = makeDaemonicPersistencePowers(
fileURLToPath,
filePowers,
cryptoPowers,
locator,
Expand Down
67 changes: 39 additions & 28 deletions packages/daemon/src/daemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,28 +218,6 @@ const makeDaemonCore = async (
/** @type {import('./types.js').WeakMultimap<Record<string | symbol, unknown>, string>['get']} */
const getFormulaIdentifierForRef = ref => formulaIdentifierForRef.get(ref);

/**
* @param {string} sha512
* @returns {import('./types.js').FarEndoReadable}
*/
const makeReadableBlob = sha512 => {
const { text, json, streamBase64 } = contentStore.fetch(sha512);
return Far(`Readable file with SHA-512 ${sha512.slice(0, 8)}...`, {
sha512: () => sha512,
streamBase64,
text,
json,
});
};

/** @type {import('./types.js').DaemonCore['storeReaderRef']} */
const storeReaderRef = async readerRef => {
const sha512Hex = await contentStore.store(makeRefReader(readerRef));
// eslint-disable-next-line no-use-before-define
const { formulaIdentifier } = await incarnateReadableBlob(sha512Hex);
return formulaIdentifier;
};

/**
* @param {string} workerId512
*/
Expand Down Expand Up @@ -297,6 +275,23 @@ const makeDaemonCore = async (
};
};

/**
* @param {string} sha512
*/
const makeControllerForReadableBlob = sha512 => {
const { text, json, streamBase64 } = contentStore.fetch(sha512);
return {
/** @type {import('./types.js').FarEndoReadable} */
external: Far(`Readable file with SHA-512 ${sha512.slice(0, 8)}...`, {
sha512: () => sha512,
streamBase64,
text,
json,
}),
internal: undefined,
};
};

/**
* @param {string} workerFormulaIdentifier
* @param {string} source
Expand Down Expand Up @@ -487,8 +482,7 @@ const makeDaemonCore = async (
context,
);
} else if (formula.type === 'readable-blob') {
const external = makeReadableBlob(formula.content);
return { external, internal: undefined };
return makeControllerForReadableBlob(formula.content);
} else if (formula.type === 'lookup') {
return makeControllerForLookup(formula.hub, formula.path, context);
} else if (formula.type === 'worker') {
Expand Down Expand Up @@ -906,13 +900,31 @@ const makeDaemonCore = async (
};

/** @type {import('./types.js').DaemonCore['incarnateReadableBlob']} */
const incarnateReadableBlob = async contentSha512 => {
const formulaNumber = await randomHex512();
const incarnateReadableBlob = async (readerRef, deferredTasks) => {
const { formulaNumber, contentSha512 } = await formulaGraphJobs.enqueue(
async () => {
const values = {
formulaNumber: await randomHex512(),
contentSha512: await contentStore.store(makeRefReader(readerRef)),
};

await deferredTasks.execute({
readableBlobFormulaIdentifier: formatId({
number: values.formulaNumber,
node: ownNodeIdentifier,
}),
});

return values;
},
);

/** @type {import('./types.js').ReadableBlobFormula} */
const formula = {
type: 'readable-blob',
content: contentSha512,
};

return /** @type {import('./types.js').IncarnateResult<import('./types.js').FarEndoReadable>} */ (
provideValueForNumberedFormula(formula.type, formulaNumber, formula)
);
Expand Down Expand Up @@ -1597,7 +1609,7 @@ const makeDaemonCore = async (
incarnateEval,
incarnateUnconfined,
incarnateBundle,
storeReaderRef,
incarnateReadableBlob,
makeMailbox,
makeDirectoryNode,
getAllNetworkAddresses,
Expand Down Expand Up @@ -1726,7 +1738,6 @@ const makeDaemonCore = async (
getFormulaIdentifierForRef,
getAllNetworkAddresses,
cancelValue,
storeReaderRef,
makeMailbox,
makeDirectoryNode,
incarnateEndoBootstrap,
Expand Down
17 changes: 10 additions & 7 deletions packages/daemon/src/host.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const assertPowersName = name => {
* @param {import('./types.js').DaemonCore['incarnateEval']} args.incarnateEval
* @param {import('./types.js').DaemonCore['incarnateUnconfined']} args.incarnateUnconfined
* @param {import('./types.js').DaemonCore['incarnateBundle']} args.incarnateBundle
* @param {import('./types.js').DaemonCore['storeReaderRef']} args.storeReaderRef
* @param {import('./types.js').DaemonCore['incarnateReadableBlob']} args.incarnateReadableBlob
* @param {import('./types.js').DaemonCore['getAllNetworkAddresses']} args.getAllNetworkAddresses
* @param {import('./types.js').MakeMailbox} args.makeMailbox
* @param {import('./types.js').MakeDirectoryNode} args.makeDirectoryNode
Expand All @@ -40,7 +40,7 @@ export const makeHostMaker = ({
incarnateEval,
incarnateUnconfined,
incarnateBundle,
storeReaderRef,
incarnateReadableBlob,
getAllNetworkAddresses,
makeMailbox,
makeDirectoryNode,
Expand Down Expand Up @@ -107,15 +107,18 @@ export const makeHostMaker = ({
* @param {string} [petName]
*/
const store = async (readerRef, petName) => {
/** @type {import('./types.js').DeferredTasks<import('./types.js').ReadableBlobDeferredTaskParams>} */
const tasks = makeDeferredTasks();

if (petName !== undefined) {
assertPetName(petName);
tasks.push(identifiers =>
petStore.write(petName, identifiers.readableBlobFormulaIdentifier),
);
}

const formulaIdentifier = await storeReaderRef(readerRef);

if (petName !== undefined) {
await petStore.write(petName, formulaIdentifier);
}
const { value } = await incarnateReadableBlob(readerRef, tasks);
return value;
};

/**
Expand Down
12 changes: 7 additions & 5 deletions packages/daemon/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ type ReadableBlobFormula = {
content: string;
};

export type ReadableBlobDeferredTaskParams = {
readableBlobFormulaIdentifier: string;
};

type LookupFormula = {
type: 'lookup';

Expand Down Expand Up @@ -518,7 +522,7 @@ export interface EndoHost extends EndoDirectory {
store(
readerRef: ERef<AsyncIterableIterator<string>>,
petName: string,
): Promise<void>;
): Promise<FarEndoReadable>;
provideGuest(
petName?: string,
opts?: MakeHostOrGuestOptions,
Expand Down Expand Up @@ -798,7 +802,8 @@ export interface DaemonCore {
deferredTasks: DeferredTasks<AgentDeferredTaskParams>,
) => IncarnateResult<EndoGuest>;
incarnateReadableBlob: (
contentSha512: string,
readerRef: ERef<AsyncIterableIterator<string>>,
deferredTasks: DeferredTasks<ReadableBlobDeferredTaskParams>,
) => IncarnateResult<FarEndoReadable>;
incarnateEval: (
hostFormulaIdentifier: string,
Expand Down Expand Up @@ -829,9 +834,6 @@ export interface DaemonCore {
incarnateNetworksDirectory: () => IncarnateResult<EndoDirectory>;
incarnateLoopbackNetwork: () => IncarnateResult<EndoNetwork>;
cancelValue: (formulaIdentifier: string, reason: Error) => Promise<void>;
storeReaderRef: (
readerRef: ERef<AsyncIterableIterator<string>>,
) => Promise<string>;
makeMailbox: MakeMailbox;
makeDirectoryNode: MakeDirectoryNode;
}
Expand Down
34 changes: 29 additions & 5 deletions packages/daemon/test/test-endo.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,34 @@ test('persist spawn and evaluation', async t => {
await stop(locator);
});

test('store', async t => {
test('store without name', async t => {
const { promise: cancelled, reject: cancel } = makePromiseKit();
t.teardown(() => cancel(Error('teardown')));
const locator = makeLocator('tmp', 'store');
const locator = makeLocator('tmp', 'store-without-name');

await stop(locator).catch(() => {});
await purge(locator);
await start(locator);

const { getBootstrap } = await makeEndoClient(
'client',
locator.sockPath,
cancelled,
);
const bootstrap = getBootstrap();
const host = E(bootstrap).host();
const readerRef = makeReaderRef([new TextEncoder().encode('hello\n')]);
const readable = await E(host).store(readerRef);
const actualText = await E(readable).text();
t.is(actualText, 'hello\n');

await stop(locator);
});

test('store with name', async t => {
const { promise: cancelled, reject: cancel } = makePromiseKit();
t.teardown(() => cancel(Error('teardown')));
const locator = makeLocator('tmp', 'store-with-name');

await stop(locator).catch(() => {});
await purge(locator);
Expand All @@ -249,7 +273,9 @@ test('store', async t => {
const bootstrap = getBootstrap();
const host = E(bootstrap).host();
const readerRef = makeReaderRef([new TextEncoder().encode('hello\n')]);
await E(host).store(readerRef, 'hello-text');
const readable = await E(host).store(readerRef, 'hello-text');
const actualText = await E(readable).text();
t.is(actualText, 'hello\n');
}

{
Expand Down Expand Up @@ -1320,11 +1346,9 @@ test('read unknown nodeId', async t => {
// write a bogus value for a bogus nodeId
const node = await cryptoPowers.randomHex512();
const number = await cryptoPowers.randomHex512();
const type = 'eval';
const formulaIdentifier = formatId({
node,
number,
type,
});
await E(host).write(['abc'], formulaIdentifier);
// observe reification failure
Expand Down

0 comments on commit f162e19

Please sign in to comment.