Skip to content

Commit

Permalink
feat: add long tracker operation
Browse files Browse the repository at this point in the history
  • Loading branch information
bao-sotatek committed May 7, 2024
1 parent 1796db2 commit 780214b
Show file tree
Hide file tree
Showing 13 changed files with 155 additions and 7 deletions.
3 changes: 2 additions & 1 deletion src/core/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ class Agent {
if (!this.signifyNotificationService) {
this.signifyNotificationService = new SignifyNotificationService(
this.agentServicesProps,
this.notificationStorage
this.notificationStorage,
this.identifierStorage
);
}
return this.signifyNotificationService;
Expand Down
3 changes: 3 additions & 0 deletions src/core/agent/records/identifierMetadataRecord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface IdentifierMetadataRecordProps {
theme: number;
signifyOpName?: string;
multisigManageAid?: string;
delegated?: Record<string, unknown>;
}

class IdentifierMetadataRecord extends BaseRecord {
Expand All @@ -22,6 +23,7 @@ class IdentifierMetadataRecord extends BaseRecord {
signifyName!: string;
theme!: number;
multisigManageAid?: string | undefined;
delegated?: Record<string, unknown>;

static readonly type = "IdentifierMetadataRecord";
readonly type = IdentifierMetadataRecord.type;
Expand All @@ -40,6 +42,7 @@ class IdentifierMetadataRecord extends BaseRecord {
this.multisigManageAid = props.multisigManageAid;
this.createdAt = props.createdAt ?? new Date();
this.theme = props.theme;
this.delegated = props.delegated;
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/core/agent/records/identifierStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ class IdentifierStorage {
return records;
}

async getAllPendingIdentifierMetadata(): Promise<IdentifierMetadataRecord[]> {
const records = await this.storageService.findAllByQuery(
{
isPending: true,
},
IdentifierMetadataRecord
);
return records;
}

async getKeriIdentifiersMetadata(): Promise<IdentifierMetadataRecord[]> {
return this.storageService.getAll(IdentifierMetadataRecord);
}
Expand Down
1 change: 1 addition & 0 deletions src/core/agent/services/delegationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class DelegationService extends AgentService {
...metadata,
signifyName: signifyName,
isPending: true,
delegated: { delegatePrefix: delegatorPrefix },
});
return { identifier, signifyName };
}
Expand Down
1 change: 1 addition & 0 deletions src/core/agent/services/identifier.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface IdentifierShortDetails {
signifyName: string;
theme: number;
isPending: boolean;
delegated?: Record<string, unknown>;
}

interface IdentifierDetails extends IdentifierShortDetails {
Expand Down
2 changes: 2 additions & 0 deletions src/core/agent/services/identifierService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ describe("Single sig service of agent", () => {
createdAtUTC: nowISO,
theme: 0,
isPending: false,
delegated: undefined,
},
]);
});
Expand Down Expand Up @@ -213,6 +214,7 @@ describe("Single sig service of agent", () => {
signifyOpName: undefined,
signifyName: "uuid-here",
isPending: false,
delegated: undefined,
});
});

Expand Down
2 changes: 2 additions & 0 deletions src/core/agent/services/identifierService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class IdentifierService extends AgentService {
createdAtUTC: metadata.createdAt.toISOString(),
theme: metadata.theme,
isPending: metadata.isPending ?? false,
delegated: metadata.delegated,
});
}
return identifiers;
Expand Down Expand Up @@ -82,6 +83,7 @@ class IdentifierService extends AgentService {
theme: metadata.theme,
signifyOpName: metadata.signifyOpName,
isPending: metadata.isPending ?? false,
delegated: metadata.delegated,
s: aid.state.s,
dt: aid.state.dt,
kt: aid.state.kt,
Expand Down
6 changes: 2 additions & 4 deletions src/core/agent/services/signifyNotificationService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,8 @@ const identifierStorage = jest.mocked({
});

const agentServicesProps = {
basicStorage: basicStorage as any,
signifyClient: signifyClient as any,
eventService: new EventService(),
identifierStorage: identifierStorage as any,
credentialStorage: {} as any,
};

const notificationStorage = jest.mocked({
Expand All @@ -114,7 +111,8 @@ const notificationStorage = jest.mocked({

const signifyNotificationService = new SignifyNotificationService(
agentServicesProps,
notificationStorage as any
notificationStorage as any,
identifierStorage as any
);

describe("Signify notification service of agent", () => {
Expand Down
54 changes: 52 additions & 2 deletions src/core/agent/services/signifyNotificationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,23 @@ import {
} from "../agent.types";
import { Notification } from "./credentialService.types";
import { PreferencesKeys, PreferencesStorage } from "../../storage";
import { NotificationStorage } from "../records";
import { IdentifierStorage, NotificationStorage } from "../records";
import { IdentifierShortDetails } from "./identifier.types";

class SignifyNotificationService extends AgentService {
static readonly NOTIFICATION_NOT_FOUND = "Notification record not found";

protected readonly notificationStorage!: NotificationStorage;
protected readonly identifierStorage: IdentifierStorage;

constructor(
agentServiceProps: AgentServicesProps,
notificationStorage: NotificationStorage
notificationStorage: NotificationStorage,
identifierStorage: IdentifierStorage
) {
super(agentServiceProps);
this.notificationStorage = notificationStorage;
this.identifierStorage = identifierStorage;
}

async onNotificationStateChanged(
Expand Down Expand Up @@ -164,6 +168,52 @@ class SignifyNotificationService extends AgentService {
private markNotification(notiSaid: string) {
return this.signifyClient.notifications().mark(notiSaid);
}

async onSignifyOperationStateChanged(
callback: (identifierShortDetails: IdentifierShortDetails) => void
) {
// eslint-disable-next-line no-constant-condition
while (true) {
const pendingIdentifiers =
await this.identifierStorage.getAllPendingIdentifierMetadata();
if (pendingIdentifiers.length > 0) {
const promises = await Promise.allSettled(
pendingIdentifiers.map((aid) => {
return this.signifyClient.operations().get(aid.signifyOpName!);
})
);
for (const pm of promises) {
if (pm.status === "fulfilled") {
const operation = pm.value;
if (operation.done) {
const aid = pendingIdentifiers.find(
(aid) => aid.signifyOpName === operation.name
)!;
await this.identifierStorage.updateIdentifierMetadata(aid.id, {
isPending: false,
});
callback({
displayName: aid.displayName,
id: aid.id,
signifyName: aid.signifyName,
createdAtUTC: aid.createdAt.toISOString(),
theme: aid.theme,
isPending: false,
delegated: aid.delegated,
});
}
} else {
//TODO: must handle case get operation failed
}
}
}
await new Promise((rs) => {
setTimeout(() => {
rs(true);
}, 2000);
});
}
}
}

export { SignifyNotificationService };
31 changes: 31 additions & 0 deletions src/store/reducers/identifiersCache/identifiersCache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
addFavouriteIdentifierCache,
removeFavouriteIdentifierCache,
getFavouritesIdentifiersCache,
updateOrAddIdentifiersCache,
} from "./identifiersCache";
import { RootState } from "../../index";
import { IdentifierShortDetails } from "../../../core/agent/services/identifier.types";
Expand Down Expand Up @@ -40,6 +41,36 @@ describe("identifiersCacheSlice", () => {
);
expect(newState.identifiers).toEqual(identifiers);
});

it("should handle updateOrAddIdentifiersCache", () => {
const identifiers: IdentifierShortDetails[] = [
{
id: "id-1",
displayName: "example-name",
createdAtUTC: "example-date",
theme: 0,
isPending: false,
signifyName: "Test",
},
];
const currentState = identifiersCacheSlice.reducer(
initialState,
setIdentifiersCache(identifiers)
);
const identifier: IdentifierShortDetails = {
id: "id-2",
displayName: "example-name",
createdAtUTC: "example-date",
theme: 0,
isPending: false,
signifyName: "Test",
};
const newState = identifiersCacheSlice.reducer(
currentState,
updateOrAddIdentifiersCache(identifier)
);
expect(newState.identifiers).toEqual([...identifiers, identifier]);
});
it("should handle setFavouritesIdentifiersCache", () => {
const favourites: FavouriteIdentifier[] = [
{
Expand Down
10 changes: 10 additions & 0 deletions src/store/reducers/identifiersCache/identifiersCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ const identifiersCacheSlice = createSlice({
) => {
state.identifiers = action.payload;
},
updateOrAddIdentifiersCache: (
state,
action: PayloadAction<IdentifierShortDetails>
) => {
const identifiers = state.identifiers.filter(
(aid) => aid.id !== action.payload.id
);
state.identifiers = [...identifiers, action.payload];
},
setFavouritesIdentifiersCache: (
state,
action: PayloadAction<FavouriteIdentifier[]>
Expand All @@ -45,6 +54,7 @@ export { initialState, identifiersCacheSlice };

export const {
setIdentifiersCache,
updateOrAddIdentifiersCache,
setFavouritesIdentifiersCache,
addFavouriteIdentifierCache,
removeFavouriteIdentifierCache,
Expand Down
23 changes: 23 additions & 0 deletions src/ui/components/AppWrapper/AppWrapper.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
acdcChangeHandler,
connectionStateChangedHandler,
keriaNotificationsChangeHandler,
signifyOperationStateChangeHandler,
} from "./AppWrapper";
import { store } from "../../../store";
import { Agent } from "../../../core/agent/agent";
Expand All @@ -31,6 +32,8 @@ import {
CredentialShortDetails,
CredentialStatus,
} from "../../../core/agent/services/credentialService.types";
import { IdentifierShortDetails } from "../../../core/agent/services/identifier.types";
import { updateOrAddIdentifiersCache } from "../../../store/reducers/identifiersCache";

jest.mock("../../../core/agent/agent", () => ({
Agent: {
Expand Down Expand Up @@ -239,4 +242,24 @@ describe("AppWrapper handler", () => {
);
});
});

describe("Signify operation state changed handler", () => {
test("handles operation updated", async () => {
const aid = {
id: "id",
displayName: "string",
createdAtUTC: "string",
signifyName: "string",
theme: 0,
isPending: false,
delegated: {},
} as IdentifierShortDetails;
await signifyOperationStateChangeHandler(aid, dispatch);
expect(dispatch).toBeCalledWith(updateOrAddIdentifiersCache(aid));
expect(dispatch).toBeCalledWith(setCurrentOperation(OperationType.IDLE));
expect(dispatch).toBeCalledWith(
setToastMsg(ToastMsgType.IDENTIFIER_UPDATED)
);
});
});
});
16 changes: 16 additions & 0 deletions src/ui/components/AppWrapper/AppWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import {
setFavouritesIdentifiersCache,
setIdentifiersCache,
updateOrAddIdentifiersCache,
} from "../../../store/reducers/identifiersCache";
import {
setCredsCache,
Expand All @@ -43,6 +44,7 @@ import { CredentialStatus } from "../../../core/agent/services/credentialService
import { FavouriteIdentifier } from "../../../store/reducers/identifiersCache/identifiersCache.types";
import "./AppWrapper.scss";
import { ConfigurationService } from "../../../core/configuration";
import { IdentifierShortDetails } from "../../../core/agent/services/identifier.types";

const connectionStateChangedHandler = async (
event: ConnectionStateChangedEvent,
Expand Down Expand Up @@ -105,6 +107,15 @@ const acdcChangeHandler = async (
}
};

const signifyOperationStateChangeHandler = async (
aid: IdentifierShortDetails,
dispatch: ReturnType<typeof useAppDispatch>
) => {
dispatch(updateOrAddIdentifiersCache(aid));
dispatch(setToastMsg(ToastMsgType.IDENTIFIER_UPDATED));
dispatch(setCurrentOperation(OperationType.IDLE));
};

const AppWrapper = (props: { children: ReactNode }) => {
const dispatch = useAppDispatch();
const authentication = useAppSelector(getAuthentication);
Expand Down Expand Up @@ -260,6 +271,10 @@ const AppWrapper = (props: { children: ReactNode }) => {
return acdcChangeHandler(event, dispatch);
});

Agent.agent.signifyNotifications.onSignifyOperationStateChanged((event) => {
return signifyOperationStateChangeHandler(event, dispatch);
});

const oldMessages = (
await Promise.all([
Agent.agent.credentials.getUnhandledIpexGrantNotifications({
Expand Down Expand Up @@ -313,4 +328,5 @@ export {
connectionStateChangedHandler,
acdcChangeHandler,
keriaNotificationsChangeHandler,
signifyOperationStateChangeHandler,
};

0 comments on commit 780214b

Please sign in to comment.