Bound chunked source hashing with workspace worker pools

This commit is contained in:
2026-11-08 20:44:29 +08:00
parent 4035956607
commit 9769f80cf5
15 changed files with 190 additions and 26 deletions
+5 -3
View File
@@ -1,11 +1,12 @@
import type { Document, Id, Registry } from '../canvas-core/types.ts';
import { fault, readMap } from '../canvas-core/values.ts';
import { openProjectEngine, type EngineOptions } from './engine.ts';
import {createDigestPool,type DigestPort} from './digest-pool.ts';
import type { StoragePort } from './storage.ts';
export type ProjectEngine = Awaited<ReturnType<typeof openProjectEngine>>;
export type WorkspaceOptions = {
accountId: Id; workspaceId: Id; authEpoch: number; registry: Registry; storage: StoragePort;
accountId: Id; workspaceId: Id; authEpoch: number; registry: Registry; storage: StoragePort; digests?:DigestPort;
isCurrentIdentity(): boolean;
adapters(projectId: Id, current: () => boolean): Pick<EngineOptions, 'persistence' | 'assets' | 'runs'>;
onError?: (error: unknown) => void;
@@ -13,6 +14,7 @@ export type WorkspaceOptions = {
/** Workspace owns persistent projects; a view only borrows one and never closes it. */
export function createWorkspaceRuntime(options: WorkspaceOptions) {
const digests=options.digests??createDigestPool();
const projects = new Map<Id, Promise<ProjectEngine>>();
let accepting = true, closed = false, closing: Promise<void> | undefined;
const current = () => accepting && !closed && options.isCurrentIdentity();
@@ -24,7 +26,7 @@ export function createWorkspaceRuntime(options: WorkspaceOptions) {
if (!current()) return Promise.reject(fault('identity_changed'));
const existing = projects.get(document.projectId);
if (existing) return existing.then(engine => { if (!current()) throw fault('identity_changed'); engine.refresh(document, versions); return engine; });
const opening = openProjectEngine({ scope: { accountId: options.accountId, workspaceId: options.workspaceId, projectId: document.projectId }, registry: options.registry, document, versions, storage: options.storage, ...options.adapters(document.projectId, current), onError: options.onError,
const opening = openProjectEngine({ scope: { accountId: options.accountId, workspaceId: options.workspaceId, projectId: document.projectId }, registry: options.registry, document, versions, storage: options.storage, digests, ...options.adapters(document.projectId, current), onError: options.onError,
traversalPolicy: () => current() ? { enabled: true } : { enabled: false, code: 'identity_changed', targets: [] },
policy: () => current() ? { enabled: true } : { enabled: false, code: 'identity_changed', targets: [] },
});
@@ -44,7 +46,7 @@ export function createWorkspaceRuntime(options: WorkspaceOptions) {
}));
const errors = results.flatMap(result => result.status === 'rejected' ? [result.reason] : []);
if (errors.length) throw new AggregateError(errors, 'workspace_close_failed');
options.storage.close(); projects.clear(); closed = true;
digests.close();options.storage.close(); projects.clear(); closed = true;
})();
closing = task.finally(() => { closing = undefined; });
return closing;