Skip to content

Commit

Permalink
feat: added operation signatures support
Browse files Browse the repository at this point in the history
  • Loading branch information
gpuente committed Jul 1, 2024
1 parent 06cad9a commit f3c5159
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 67 deletions.
8 changes: 4 additions & 4 deletions api/src/graphql/server/generated/drive/nexus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export interface NexusGenInputs {
}
InputOperationSigner: { // input type
app: NexusGenInputs['InputOperationSignerApp']; // InputOperationSignerApp!
signature: string; // String!
signatures: string[][]; // [[String!]!]!
user: NexusGenInputs['InputOperationSignerUser']; // InputOperationSignerUser!
}
InputOperationSignerApp: { // input type
Expand Down Expand Up @@ -409,7 +409,7 @@ export interface NexusGenObjects {
}
OperationSigner: { // root type
app: NexusGenRootTypes['OperationSignerApp']; // OperationSignerApp!
signature: string; // String!
signatures: string[][]; // [[String!]!]!
user: NexusGenRootTypes['OperationSignerUser']; // OperationSignerUser!
}
OperationSignerApp: { // root type
Expand Down Expand Up @@ -905,7 +905,7 @@ export interface NexusGenFieldTypes {
}
OperationSigner: { // field return type
app: NexusGenRootTypes['OperationSignerApp']; // OperationSignerApp!
signature: string; // String!
signatures: string[][]; // [[String!]!]!
user: NexusGenRootTypes['OperationSignerUser']; // OperationSignerUser!
}
OperationSignerApp: { // field return type
Expand Down Expand Up @@ -1428,7 +1428,7 @@ export interface NexusGenFieldTypeNames {
}
OperationSigner: { // field return type name
app: 'OperationSignerApp'
signature: 'String'
signatures: 'String'
user: 'OperationSignerUser'
}
OperationSignerApp: { // field return type name
Expand Down
4 changes: 2 additions & 2 deletions api/src/graphql/server/generated/drive/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ input InputOperationContext {

input InputOperationSigner {
app: InputOperationSignerApp!
signature: String!
signatures: [[String!]!]!
user: InputOperationSignerUser!
}

Expand Down Expand Up @@ -444,7 +444,7 @@ type OperationContext {

type OperationSigner {
app: OperationSignerApp!
signature: String!
signatures: [[String!]!]!
user: OperationSignerUser!
}

Expand Down
149 changes: 88 additions & 61 deletions api/src/modules/document-drive/drive-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ import {
} from 'nexus';
import { systemType } from '../system';
import {
ListenerRevision as IListenerRevision, UpdateStatus as IUpdateStatus,
ListenerRevision as IListenerRevision,
UpdateStatus as IUpdateStatus,
} from 'document-drive';
import { Operation, OperationScope } from 'document-model/document';
import stringify from 'json-stringify-deterministic';
import { getChildLogger } from '../../logger';
import { Context } from '../../graphql/server/drive/context';
import { DocumentDriveAction, DocumentDriveState } from 'document-model-libs/document-drive';
import {
DocumentDriveAction,
DocumentDriveState,
} from 'document-model-libs/document-drive';
import DocumentDriveError from '../../errors/DocumentDriveError';
import NotFoundError from '../../errors/NotFoundError';

Expand Down Expand Up @@ -107,16 +111,16 @@ export const OperationSigner = objectType({
definition(t) {
t.nonNull.field('user', { type: OperationSignerUser });
t.nonNull.field('app', { type: OperationSignerApp });
t.nonNull.string('signature');
}
t.nonNull.list.nonNull.list.nonNull.field('signatures', { type: 'String' });
},
});

export const OperationContext = objectType({
name: 'OperationContext',
definition(t) {
t.field('signer', { type: OperationSigner });
}
})
},
});

export const OperationUpdate = objectType({
name: 'OperationUpdate',
Expand Down Expand Up @@ -154,16 +158,16 @@ export const InputOperationSigner = inputObjectType({
definition(t) {
t.nonNull.field('user', { type: InputOperationSignerUser });
t.nonNull.field('app', { type: InputOperationSignerApp });
t.nonNull.string('signature');
}
t.nonNull.list.nonNull.list.nonNull.field('signatures', { type: 'String' });
},
});

export const InputOperationContext = inputObjectType({
name: 'InputOperationContext',
definition(t) {
t.field('signer', { type: InputOperationSigner });
}
})
},
});

export const InputOperationUpdate = inputObjectType({
name: 'InputOperationUpdate',
Expand Down Expand Up @@ -260,7 +264,7 @@ export const syncType = objectType({
const result = await ctx.prisma.document.pullStrands(
ctx.driveId ?? '1',
listenerId,
since,
since
);
return result.map((e) => ({
driveId: e.driveId,
Expand All @@ -281,7 +285,7 @@ export const syncType = objectType({
}));
} catch (e) {
if ((e as Error).message?.match(/Transmitter .+ not found/)) {
throw new NotFoundError({ message: "Transmitter not found" });
throw new NotFoundError({ message: 'Transmitter not found' });
} else {
logger.error(e);
throw new Error('Failed to fetch strands');
Expand Down Expand Up @@ -312,10 +316,17 @@ export const getDrive = queryField('drive', {
type: DocumentDriveStateObject,
resolve: async (_parent, _args, ctx: Context) => {
try {
const drive = await ctx.prisma.document.getDrive(ctx.driveId ?? '1') as DocumentDriveState;
const drive = (await ctx.prisma.document.getDrive(
ctx.driveId ?? '1'
)) as DocumentDriveState;
return drive;
} catch (e: any) {
throw new DocumentDriveError({ code: 500, message: e.message ?? "Failed to get drive", logging: true, context: e })
throw new DocumentDriveError({
code: 500,
message: e.message ?? 'Failed to get drive',
logging: true,
context: e,
});
}
},
});
Expand All @@ -330,23 +341,26 @@ export const registerListener = mutationField('registerPullResponderListener', {
const result = await ctx.prisma.document.registerPullResponderListener(
ctx.driveId ?? '1',
{
branch: filter.branch?.filter(b => !!b) as string[] ?? [],
documentId: filter.documentId?.filter(b => !!b) as string[] ?? [],
documentType: filter.documentType?.filter(b => !!b) as string[] ?? [],
scope: filter.scope?.filter(b => !!b) as string[] ?? [],
},
branch: (filter.branch?.filter((b) => !!b) as string[]) ?? [],
documentId: (filter.documentId?.filter((b) => !!b) as string[]) ?? [],
documentType:
(filter.documentType?.filter((b) => !!b) as string[]) ?? [],
scope: (filter.scope?.filter((b) => !!b) as string[]) ?? [],
}
);

return result;

} catch (e: any) {
throw new DocumentDriveError({ code: 500, message: e.message ?? "Failed to register listener", logging: true, context: e })
throw new DocumentDriveError({
code: 500,
message: e.message ?? 'Failed to register listener',
logging: true,
context: e,
});
}

},
});


export const deleteListener = mutationField('deletePullResponderListener', {
type: Listener,
args: {
Expand All @@ -356,12 +370,17 @@ export const deleteListener = mutationField('deletePullResponderListener', {
try {
const result = await ctx.prisma.document.deletePullResponderListener(
ctx.driveId ?? '1',
filter,
filter
);

return result;
} catch (e: any) {
throw new DocumentDriveError({ code: 500, message: e.message ?? "Failed to delete listener", logging: true, context: e })
throw new DocumentDriveError({
code: 500,
message: e.message ?? 'Failed to delete listener',
logging: true,
context: e,
});
}
},
});
Expand All @@ -376,45 +395,48 @@ export const pushUpdates = mutationField('pushUpdates', {
if (!strands || strands?.length === 0) return [];

try {
const listenerRevisions: IListenerRevision[] = await Promise.all(strands.map(async (s) => {
const operations = s.operations?.map((o) => ({
...o,
input: JSON.parse(o.input),
skip: o.skip ?? 0,
scope: s.scope as OperationScope,
branch: "main",
})) ?? [];

const result = await ctx.prisma.document.pushUpdates(
s.driveId,
operations as Operation<DocumentDriveAction>[],
s.documentId ?? undefined,
);

if (result.status !== "SUCCESS") logger.error(result.error);

const revision = result.document?.operations[s.scope as OperationScope]
.slice()
.pop()?.index ?? -1;

return {
revision,
branch: s.branch,
documentId: s.documentId ?? "",
driveId: s.driveId,
scope: s.scope as OperationScope,
status: result.status,
error: result.error?.message,
};
}));
const listenerRevisions: IListenerRevision[] = await Promise.all(
strands.map(async (s) => {
const operations =
s.operations?.map((o) => ({
...o,
input: JSON.parse(o.input),
skip: o.skip ?? 0,
scope: s.scope as OperationScope,
branch: 'main',
})) ?? [];

const result = await ctx.prisma.document.pushUpdates(
s.driveId,
operations as Operation<DocumentDriveAction>[],
s.documentId ?? undefined
);

if (result.status !== 'SUCCESS') logger.error(result.error);

const revision =
result.document?.operations[s.scope as OperationScope].slice().pop()
?.index ?? -1;

return {
revision,
branch: s.branch,
documentId: s.documentId ?? '',
driveId: s.driveId,
scope: s.scope as OperationScope,
status: result.status,
error: result.error?.message,
};
})
);

return listenerRevisions;
} catch (e: any) {
throw new DocumentDriveError({
code: 500,
message: e.message ?? "Failed to push updates",
message: e.message ?? 'Failed to push updates',
logging: true,
context: e
context: e,
});
}
},
Expand All @@ -441,14 +463,19 @@ export const acknowledge = mutationField('acknowledge', {
}));

const result = await ctx.prisma.document.processAcknowledge(
ctx.driveId ?? "1",
ctx.driveId ?? '1',
listenerId,
validEntries,
validEntries
);

return result;
} catch (e: any) {
throw new DocumentDriveError({ code: 500, message: e.message ?? "Failed to acknowledge", logging: true, context: e })
throw new DocumentDriveError({
code: 500,
message: e.message ?? 'Failed to acknowledge',
logging: true,
context: e,
});
}
},
});

0 comments on commit f3c5159

Please sign in to comment.