Skip to content

Commit

Permalink
feat: notifications inbox remove and notifications outbox remove
Browse files Browse the repository at this point in the history
…commands
  • Loading branch information
amydevs committed May 6, 2024
1 parent dc1d7dc commit 8f06b4b
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 6 deletions.
2 changes: 2 additions & 0 deletions src/notifications/inbox/CommandInbox.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import CommandClear from './CommandClear';
import CommandRead from './CommandRead';
import CommandRemove from './CommandRemove';
import CommandPolykey from '../../CommandPolykey';

class CommandInbox extends CommandPolykey {
Expand All @@ -9,6 +10,7 @@ class CommandInbox extends CommandPolykey {
this.description('Notifications Inbox Operations');
this.addCommand(new CommandClear(...args));
this.addCommand(new CommandRead(...args));
this.addCommand(new CommandRemove(...args));
}
}

Expand Down
69 changes: 69 additions & 0 deletions src/notifications/inbox/CommandRemove.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type PolykeyClient from 'polykey/dist/PolykeyClient';
import * as notificationsUtils from 'polykey/dist/notifications/utils';
import CommandPolykey from '../../CommandPolykey';
import * as binUtils from '../../utils';
import * as binOptions from '../../utils/options';
import * as binProcessors from '../../utils/processors';
import * as binParsers from '../../utils/parsers';

class CommandRemove extends CommandPolykey {
constructor(...args: ConstructorParameters<typeof CommandPolykey>) {
super(...args);
this.name('remove');
this.description('Remove a Notification in the Inbox');
this.argument(
'<notificationId>',
'Id of the notification to remove',
binParsers.parseNotificationId,
);
this.addOption(binOptions.nodeId);
this.addOption(binOptions.clientHost);
this.addOption(binOptions.clientPort);
this.action(async (notificationId, options) => {
const { default: PolykeyClient } = await import(
'polykey/dist/PolykeyClient'
);
const clientOptions = await binProcessors.processClientOptions(
options.nodePath,
options.nodeId,
options.clientHost,
options.clientPort,
this.fs,
this.logger.getChild(binProcessors.processClientOptions.name),
);
const auth = await binProcessors.processAuthentication(
options.passwordFile,
this.fs,
);

let pkClient: PolykeyClient;
this.exitHandlers.handlers.push(async () => {
if (pkClient != null) await pkClient.stop();
});
try {
pkClient = await PolykeyClient.createPolykeyClient({
nodeId: clientOptions.nodeId,
host: clientOptions.clientHost,
port: clientOptions.clientPort,
options: {
nodePath: options.nodePath,
},
logger: this.logger.getChild(PolykeyClient.name),
});
await binUtils.retryAuthentication(
(auth) =>
pkClient.rpcClient.methods.notificationsInboxRemove({
notificationIdEncoded:
notificationsUtils.encodeNotificationId(notificationId),
metadata: auth,
}),
auth,
);
} finally {
if (pkClient! != null) await pkClient.stop();
}
});
}
}

export default CommandRemove;
2 changes: 2 additions & 0 deletions src/notifications/outbox/CommandOutbox.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import CommandClear from './CommandClear';
import CommandRead from './CommandRead';
import CommandRemove from './CommandRemove';
import CommandPolykey from '../../CommandPolykey';

class CommandOutbox extends CommandPolykey {
Expand All @@ -9,6 +10,7 @@ class CommandOutbox extends CommandPolykey {
this.description('Notifications Outbox Operations');
this.addCommand(new CommandClear(...args));
this.addCommand(new CommandRead(...args));
this.addCommand(new CommandRemove(...args));
}
}

Expand Down
69 changes: 69 additions & 0 deletions src/notifications/outbox/CommandRemove.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type PolykeyClient from 'polykey/dist/PolykeyClient';
import * as notificationsUtils from 'polykey/dist/notifications/utils';
import CommandPolykey from '../../CommandPolykey';
import * as binUtils from '../../utils';
import * as binOptions from '../../utils/options';
import * as binProcessors from '../../utils/processors';
import * as binParsers from '../../utils/parsers';

class CommandRemove extends CommandPolykey {
constructor(...args: ConstructorParameters<typeof CommandPolykey>) {
super(...args);
this.name('remove');
this.description('Remove a Pending Notification to be Sent in the Outbox');
this.argument(
'<notificationId>',
'Id of the notification to remove',
binParsers.parseNotificationId,
);
this.addOption(binOptions.nodeId);
this.addOption(binOptions.clientHost);
this.addOption(binOptions.clientPort);
this.action(async (notificationId, options) => {
const { default: PolykeyClient } = await import(
'polykey/dist/PolykeyClient'
);
const clientOptions = await binProcessors.processClientOptions(
options.nodePath,
options.nodeId,
options.clientHost,
options.clientPort,
this.fs,
this.logger.getChild(binProcessors.processClientOptions.name),
);
const auth = await binProcessors.processAuthentication(
options.passwordFile,
this.fs,
);

let pkClient: PolykeyClient;
this.exitHandlers.handlers.push(async () => {
if (pkClient != null) await pkClient.stop();
});
try {
pkClient = await PolykeyClient.createPolykeyClient({
nodeId: clientOptions.nodeId,
host: clientOptions.clientHost,
port: clientOptions.clientPort,
options: {
nodePath: options.nodePath,
},
logger: this.logger.getChild(PolykeyClient.name),
});
await binUtils.retryAuthentication(
(auth) =>
pkClient.rpcClient.methods.notificationsOutboxRemove({
notificationIdEncoded:
notificationsUtils.encodeNotificationId(notificationId),
metadata: auth,
}),
auth,
);
} finally {
if (pkClient! != null) await pkClient.stop();
}
});
}
}

export default CommandRemove;
4 changes: 4 additions & 0 deletions src/utils/parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ const parseNodeId: (data: string) => ids.NodeId = validateParserToArgParser(
ids.parseNodeId,
);

const parseNotificationId: (data: string) => ids.NotificationId =
validateParserToArgParser(ids.parseNotificationId);

const parseGestaltId: (data: string) => ids.GestaltId =
validateParserToArgParser(ids.parseGestaltId);

Expand Down Expand Up @@ -153,6 +156,7 @@ export {
parseInteger,
parseNumber,
parseNodeId,
parseNotificationId,
parseGestaltId,
parseGestaltIdentityId,
parseGestaltAction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import * as nodesUtils from 'polykey/dist/nodes/utils';
import * as testUtils from '../../utils';

describe('send/read/claim', () => {
const logger = new Logger('inbox send/read/clear test', LogLevel.WARN, [
new StreamHandler(),
]);
const logger = new Logger(
'inbox send/read/remove/clear test',
LogLevel.WARN,
[new StreamHandler()],
);
let dataDir: string;
let senderId: NodeId;
let senderHost: string;
Expand Down Expand Up @@ -287,6 +289,56 @@ describe('send/read/claim', () => {
sub: nodesUtils.encodeNodeId(receiverId),
isRead: true,
});
// Get a notificationId to remove
({ exitCode, stdout } = await testUtils.pkExec(
['notifications', 'inbox', 'read', '--format', 'json'],
{
env: {
PK_NODE_PATH: receiverAgentDir,
PK_PASSWORD: receiverAgentPassword,
},
cwd: receiverAgentDir,
},
));
expect(exitCode).toBe(0);
readNotificationMessages = JSON.parse(stdout);
expect(readNotificationMessages).toHaveLength(3);
const deletedNotificationIdEncoded =
readNotificationMessages[0].notification.notificationIdEncoded;
// Remove inbox notificataions
await testUtils.pkExec(
['notifications', 'inbox', 'remove', deletedNotificationIdEncoded],
{
env: {
PK_NODE_PATH: receiverAgentDir,
PK_PASSWORD: receiverAgentPassword,
},
cwd: receiverAgentDir,
},
);
// Check that the notification no longer exists
({ exitCode, stdout } = await testUtils.pkExec(
['notifications', 'inbox', 'read', '--format', 'json'],
{
env: {
PK_NODE_PATH: receiverAgentDir,
PK_PASSWORD: receiverAgentPassword,
},
cwd: receiverAgentDir,
},
));
expect(exitCode).toBe(0);
readNotificationMessages = JSON.parse(stdout);
expect(readNotificationMessages).toHaveLength(2);
expect(readNotificationMessages).not.toEqual(
expect.arrayContaining([
expect.objectContaining({
notification: {
notificationIdEncoded: deletedNotificationIdEncoded,
},
}),
]),
);
// Clear inbox notifications
await testUtils.pkExec(['notifications', 'inbox', 'clear'], {
env: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import * as nodesUtils from 'polykey/dist/nodes/utils';
import * as testUtils from '../../utils';

describe('send/read/claim', () => {
const logger = new Logger('outbox send/read/clear test', LogLevel.WARN, [
new StreamHandler(),
]);
const logger = new Logger(
'outbox send/read/remove/clear test',
LogLevel.WARN,
[new StreamHandler()],
);
let dataDir: string;
let senderId: NodeId;
let senderAgentStatus: StatusLive;
Expand Down Expand Up @@ -183,6 +185,56 @@ describe('send/read/claim', () => {
iss: nodesUtils.encodeNodeId(senderId),
sub: receiverId,
});
// Get a notificationId to remove
({ exitCode, stdout } = await testUtils.pkExec(
['notifications', 'outbox', 'read', '--format', 'json'],
{
env: {
PK_NODE_PATH: senderAgentDir,
PK_PASSWORD: senderAgentPassword,
},
cwd: senderAgentDir,
},
));
expect(exitCode).toBe(0);
readNotificationMessages = JSON.parse(stdout);
expect(readNotificationMessages).toHaveLength(3);
const deletedNotificationIdEncoded =
readNotificationMessages[0].notification.notificationIdEncoded;
// Remove outbox notificataions
await testUtils.pkExec(
['notifications', 'outbox', 'remove', deletedNotificationIdEncoded],
{
env: {
PK_NODE_PATH: senderAgentDir,
PK_PASSWORD: senderAgentPassword,
},
cwd: senderAgentDir,
},
);
// Check that the notification no longer exists
({ exitCode, stdout } = await testUtils.pkExec(
['notifications', 'outbox', 'read', '--format', 'json'],
{
env: {
PK_NODE_PATH: senderAgentDir,
PK_PASSWORD: senderAgentPassword,
},
cwd: senderAgentDir,
},
));
expect(exitCode).toBe(0);
readNotificationMessages = JSON.parse(stdout);
expect(readNotificationMessages).toHaveLength(2);
expect(readNotificationMessages).not.toEqual(
expect.arrayContaining([
expect.objectContaining({
notification: {
notificationIdEncoded: deletedNotificationIdEncoded,
},
}),
]),
);
// Clear outbox notifications
await testUtils.pkExec(['notifications', 'outbox', 'clear'], {
env: {
Expand Down

0 comments on commit 8f06b4b

Please sign in to comment.