Skip to content

Commit

Permalink
fix: respect canOpen on re-opening programs on program restart
Browse files Browse the repository at this point in the history
  • Loading branch information
marcus-pousette committed Feb 17, 2025
1 parent 69021fd commit a97d716
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 16 deletions.
20 changes: 13 additions & 7 deletions packages/programs/data/document/document/src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export class Documents<
private idResolver!: (any: any) => indexerTypes.IdPrimitive;
private domain?: CustomDocumentDomain<InferR<D>>;

canOpen?: (program: T, entry: Entry<Operation>) => Promise<boolean> | boolean;
canOpen?: (program: T) => Promise<boolean> | boolean;

compatibility: 6 | 7 | undefined;

Expand All @@ -145,6 +145,16 @@ export class Documents<
return this._index;
}

private async maybeSubprogramOpen(value: T & Program): Promise<T & Program> {
if (await this.canOpen!(value)) {
return (await this.node.open(value, {
parent: this as Program<any, any>,
existing: "reuse",
})) as any as T & Program; // TODO types
}

return value;
}
async open(options: SetupOptions<T, I, D>) {
this._clazz = options.type;
this.canOpen = options.canOpen;
Expand Down Expand Up @@ -195,6 +205,7 @@ export class Documents<
);
},
dbType: this.constructor,
maybeOpen: this.maybeSubprogramOpen.bind(this),
});

// document v6 and below need log compatibility of v8 or below
Expand Down Expand Up @@ -594,12 +605,7 @@ export class Documents<
// Program specific
if (value instanceof Program) {
// if replicator, then open
if (await this.canOpen!(value, item)) {
value = (await this.node.open(value, {
parent: this as Program<any, any>,
existing: "reuse",
})) as any as T; // TODO types
}
value = await this.maybeSubprogramOpen(value);
}
documentsChanged.added.push(value);
await this._index.put(value, item, key);
Expand Down
8 changes: 6 additions & 2 deletions packages/programs/data/document/document/src/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ export type OpenOptions<
transform?: TransformOptions<T, I>;
cacheSize?: number;
compatibility: 6 | 7 | 8 | undefined;
maybeOpen: (value: T & Program) => Promise<T & Program>;
};

type IndexableClass<I> = new (
Expand Down Expand Up @@ -374,6 +375,7 @@ export class DocumentIndex<
private _resolverProgramCache?: Map<string | number | bigint, T>;
private _resolverCache?: Cache<T>;
private isProgramValued: boolean;
private _maybeOpen: (value: T & Program) => Promise<T & Program>;

private _resultQueue: Map<
string,
Expand Down Expand Up @@ -474,7 +476,7 @@ export class DocumentIndex<
})) || new HashmapIndex<IDocumentWithContext<I>>();

this._resumableIterators = new ResumableIterators(this.index);

this._maybeOpen = properties.maybeOpen;
if (this.isProgramValued) {
this._resolverProgramCache = new Map();
}
Expand Down Expand Up @@ -545,8 +547,10 @@ export class DocumentIndex<
);
continue;
}
programValue.value = await this._maybeOpen(
programValue.value as Program & T,
);
this._resolverProgramCache.set(id.primitive, programValue.value as T);
await this.node.open(programValue.value as Program);
}
}
return super.afterOpen();
Expand Down
41 changes: 34 additions & 7 deletions packages/programs/data/document/document/test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
AccessError,
Ed25519PublicKey,
type PublicSignKey,
equals,
randomBytes,
toBase64,
} from "@peerbit/crypto";
Expand Down Expand Up @@ -3070,34 +3071,60 @@ describe("index", () => {
directory: "./tmp/document-store/program-perstance-test/" + new Date(),
});
const peer = session.peers[0];

const subProgram1 = new SubProgram();

const subProgram2 = new SubProgram();

let store = await peer.open(
new TestStoreSubPrograms({
docs: new Documents<SubProgram, SubProgramIndexable>(),
}),
{
args: {
canOpen: () => true,
canOpen: (d) => equals(d.id, subProgram1.id),
},
},
);

const subProgram = new SubProgram();
await store.docs.put(subProgram);
expect(subProgram.closed).to.be.false;
await store.docs.put(subProgram1);
await store.docs.put(subProgram2);

expect(subProgram1.closed).to.be.false;
expect(subProgram2.closed).to.be.true;

await session.peers[0].stop();

expect(subProgram1.closed).to.be.true;
expect(subProgram2.closed).to.be.true;

await session.peers[0].start();
store = await peer.open(store.clone(), {
args: {
canOpen: () => true,
canOpen: (d) => equals(d.id, subProgram1.id),
},
});

const programsInIndex = await store.docs.index
.iterate({}, { local: true, remote: false })
.all();
expect(programsInIndex).to.have.length(1);
expect(programsInIndex[0].closed).to.be.false;
expect(programsInIndex).to.have.length(2);
expect(
programsInIndex
.map((x) => x.closed)
.sort((a, b) => String(a).localeCompare(String(b))),
).to.deep.eq([false, true]); // one is allowed to be opened and one is not

// open all, and make sure that if we query all again, they are all open
for (const program of programsInIndex) {
program.closed && (await peer.open(program));
}

const programsInIndex2 = await store.docs.index
.iterate({}, { local: true, remote: false })
.all();
expect(programsInIndex2).to.have.length(2);
expect(programsInIndex2.map((x) => x.closed)).to.deep.eq([false, false]);
});

describe("index", () => {
Expand Down

0 comments on commit a97d716

Please sign in to comment.