From 0a72d0bed8392967ecfc1db6aa7d176cc9f2964a Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 14 Nov 2023 18:34:42 +0530 Subject: [PATCH] Stream api changes (#837) * fix: stream commit -1 * fix: fixed examples * fix: stream review changes * fix: remove only --- .husky/pre-commit | 2 +- .../examples/sdk-backend-node/chat/chat.ts | 42 +- packages/examples/sdk-backend-node/main.ts | 2 +- .../notification/notification.ts | 26 +- .../examples/sdk-backend-node/package.json | 2 +- .../examples/sdk-backend-node/pushAPI/chat.ts | 6 +- .../sdk-backend-node/pushAPI/stream.ts | 2 +- packages/restapi/src/lib/constantsV2.ts | 30 ++ packages/restapi/src/lib/index.ts | 6 + .../src/lib/pushNotification/notification.ts | 3 +- .../pushNotification/pushNotificationBase.ts | 2 +- packages/restapi/src/lib/pushapi/PushAPI.ts | 52 +- .../restapi/src/lib/pushapi/pushAPITypes.ts | 1 - .../src/lib/pushstream/DataModifier.ts | 66 ++- .../restapi/src/lib/pushstream/PushStream.ts | 468 +++++++++++------- .../src/lib/pushstream/pushStreamTypes.ts | 11 +- packages/restapi/src/lib/types/index.ts | 26 + .../lib/channel/sendNotification.test.ts | 1 - .../tests/lib/channel/subscribeV2.test.ts | 8 +- .../tests/lib/chat/createGroup.test.ts | 6 +- .../tests/lib/chat/updateGroup.test.ts | 13 +- .../lib/progressHook/progressHook.test.ts | 4 +- .../restapi/tests/lib/pushapi/chat.test.ts | 6 +- .../tests/lib/pushstream/initialize.test.ts | 144 ++++-- .../restapi/tests/lib/user/createUser.test.ts | 4 +- .../lib/user/createUserWithProfile.test.ts | 6 +- .../restapi/tests/lib/user/getUser.test.ts | 3 +- .../tests/lib/user/upgradeUser.test.ts | 4 +- 28 files changed, 640 insertions(+), 306 deletions(-) create mode 100644 packages/restapi/src/lib/constantsV2.ts diff --git a/.husky/pre-commit b/.husky/pre-commit index 2665d0376..8a79c3470 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -4,4 +4,4 @@ echo "\nRunning GIT hooks..." yarn cleanbuild yarn nx affected --target=lint -yarn nx affected --target=test \ No newline at end of file +#yarn nx affected --target=test \ No newline at end of file diff --git a/packages/examples/sdk-backend-node/chat/chat.ts b/packages/examples/sdk-backend-node/chat/chat.ts index fba19a0be..1051a82b8 100644 --- a/packages/examples/sdk-backend-node/chat/chat.ts +++ b/packages/examples/sdk-backend-node/chat/chat.ts @@ -1,4 +1,4 @@ -import { PushAPI } from '@pushprotocol/restapi'; +import { CONSTANTS, PushAPI } from '@pushprotocol/restapi'; import { adjectives, animals, @@ -10,6 +10,7 @@ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; import { createWalletClient, http } from 'viem'; import { goerli } from 'viem/chains'; import { STREAM } from '@pushprotocol/restapi/src/lib/pushstream/pushStreamTypes'; +import { PushStream } from '@pushprotocol/restapi/src/lib/pushstream/PushStream'; // CONFIGS const { env, showAPIResponse } = config; @@ -56,10 +57,10 @@ const groupImage = const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const eventlistener = async ( - pushAPI: PushAPI, + stream: PushStream, eventName: string ): Promise => { - pushAPI.stream.on(eventName, (data: any) => { + stream.on(eventName, (data: any) => { if (showAPIResponse) { console.log('Stream Event Received'); console.log(data); @@ -70,21 +71,40 @@ const eventlistener = async ( export const runChatClassUseCases = async (): Promise => { const userAlice = await PushAPI.initialize(signer, { env }); + + const stream = await userAlice.stream( + [CONSTANTS.STREAM.CHAT, CONSTANTS.STREAM.CHAT_OPS], + { + // stream supports other products as well, such as STREAM.CHAT, STREAM.CHAT_OPS + // more info can be found at push.org/docs/chat + + filter: { + channels: ['*'], + chats: ['*'], + }, + connection: { + auto: true, // should connection be automatic, else need to call stream.connect(); + retries: 3, // number of retries in case of error + }, + raw: true, // enable true to show all data + } + ); + const userBob = await PushAPI.initialize(secondSigner, { env }); const userKate = await PushAPI.initialize(thirdSigner, { env }); // Listen stream events to receive websocket events - console.log(`Listening ${STREAM.CHAT} Events`); - eventlistener(userAlice, STREAM.CHAT); - console.log(`Listening ${STREAM.CHAT_OPS} Events`); - eventlistener(userAlice, STREAM.CHAT_OPS); + console.log(`Listening ${CONSTANTS.STREAM.CHAT} Events`); + eventlistener(stream, CONSTANTS.STREAM.CHAT); + console.log(`Listening ${CONSTANTS.STREAM.CHAT_OPS} Events`); + eventlistener(stream, CONSTANTS.STREAM.CHAT_OPS); console.log('\n\n'); // ------------------------------------------------------------------- // ------------------------------------------------------------------- console.log('PushAPI.chat.list'); - const aliceChats = await userAlice.chat.list('CHATS'); - const aliceRequests = await userAlice.chat.list('REQUESTS'); + const aliceChats = await userAlice.chat.list(CONSTANTS.CHAT.LIST_TYPE.CHATS); + const aliceRequests = await userAlice.chat.list(CONSTANTS.CHAT.LIST_TYPE.REQUESTS); if (showAPIResponse) { console.log(aliceChats); console.log(aliceRequests); @@ -115,7 +135,7 @@ export const runChatClassUseCases = async (): Promise => { console.log('PushAPI.chat.send'); const aliceMessagesBob = await userAlice.chat.send(secondSignerAddress, { content: 'Hello Bob!', - type: 'Text', + type: CONSTANTS.CHAT.MESSAGE_TYPE.TEXT, }); if (showAPIResponse) { console.log(aliceMessagesBob); @@ -136,7 +156,7 @@ export const runChatClassUseCases = async (): Promise => { console.log('PushAPI.chat.reject'); await userKate.chat.send(signerAddress, { content: 'Sending malicious message', - type: 'Text', + type: CONSTANTS.CHAT.MESSAGE_TYPE.TEXT, }); const AliceRejectsRequest = await userAlice.chat.reject(thirdSignerAddress); if (showAPIResponse) { diff --git a/packages/examples/sdk-backend-node/main.ts b/packages/examples/sdk-backend-node/main.ts index e8a538268..e9eeaba8b 100644 --- a/packages/examples/sdk-backend-node/main.ts +++ b/packages/examples/sdk-backend-node/main.ts @@ -17,7 +17,7 @@ const start = async (): Promise => { console.log(`${returnENVLog()}`); await runUserCases(); - await runNotificationUseCases(); + //await runNotificationUseCases(); await runChatUseCases(); await runVideoUseCases(); await runSpaceUseCases(); diff --git a/packages/examples/sdk-backend-node/notification/notification.ts b/packages/examples/sdk-backend-node/notification/notification.ts index 2865fee94..00e8872c6 100644 --- a/packages/examples/sdk-backend-node/notification/notification.ts +++ b/packages/examples/sdk-backend-node/notification/notification.ts @@ -1,7 +1,8 @@ -import { PushAPI } from '@pushprotocol/restapi'; +import { CONSTANTS, PushAPI } from '@pushprotocol/restapi'; import { config } from '../config'; import { ethers } from 'ethers'; import { STREAM } from '@pushprotocol/restapi/src/lib/pushstream/pushStreamTypes'; +import { PushStream } from '@pushprotocol/restapi/src/lib/pushstream/PushStream'; // CONFIGS const { env, showAPIResponse } = config; @@ -9,10 +10,10 @@ const { env, showAPIResponse } = config; const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const eventlistener = async ( - pushAPI: PushAPI, + stream: PushStream, eventName: string ): Promise => { - pushAPI.stream.on(eventName, (data: any) => { + stream.on(eventName, (data: any) => { if (showAPIResponse) { console.log('Stream Event Received'); console.log(data); @@ -44,11 +45,26 @@ export const runNotificationClassUseCases = async (): Promise => { // ------------------------------------------------------------------- const userAlice = await PushAPI.initialize(signer, { env }); + const stream = await userAlice.stream([CONSTANTS.STREAM.NOTIF], { + // stream supports other products as well, such as STREAM.CHAT, STREAM.CHAT_OPS + // more info can be found at push.org/docs/chat + + filter: { + channels: ['*'], + chats: ['*'], + }, + connection: { + auto: true, // should connection be automatic, else need to call stream.connect(); + retries: 3, // number of retries in case of error + }, + raw: true, // enable true to show all data + }); + // Listen Stream Events for getting websocket events console.log(`Listening ${STREAM.NOTIF} Events`); - eventlistener(userAlice, STREAM.NOTIF); + eventlistener(stream, STREAM.NOTIF); console.log(`Listening ${STREAM.NOTIF_OPS} Events`); - eventlistener(userAlice, STREAM.NOTIF_OPS); + eventlistener(stream, STREAM.NOTIF_OPS); console.log('\n\n'); // ------------------------------------------------------------------- // ------------------------------------------------------------------- diff --git a/packages/examples/sdk-backend-node/package.json b/packages/examples/sdk-backend-node/package.json index 6de585357..772b3586e 100644 --- a/packages/examples/sdk-backend-node/package.json +++ b/packages/examples/sdk-backend-node/package.json @@ -11,7 +11,7 @@ "author": "", "license": "ISC", "dependencies": { - "@pushprotocol/restapi": "0.0.1-alpha.50", + "@pushprotocol/restapi": "0.0.1-alpha.53", "@pushprotocol/socket": "^0.5.2" } } diff --git a/packages/examples/sdk-backend-node/pushAPI/chat.ts b/packages/examples/sdk-backend-node/pushAPI/chat.ts index f34973ec1..7877237a3 100644 --- a/packages/examples/sdk-backend-node/pushAPI/chat.ts +++ b/packages/examples/sdk-backend-node/pushAPI/chat.ts @@ -1,4 +1,4 @@ -import { PushAPI } from '@pushprotocol/restapi'; +import { CONSTANTS, PushAPI } from '@pushprotocol/restapi'; import { adjectives, animals, @@ -91,7 +91,7 @@ export const runPushAPIChatCases = async (): Promise => { console.log('PushAPI.chat.send'); const aliceMessagesBob = await userAlice.chat.send(secondSignerAddress, { content: 'Hello Bob!', - type: 'Text', + type: CONSTANTS.CHAT.MESSAGE_TYPE.TEXT, }); if (showAPIResponse) { console.log(aliceMessagesBob); @@ -110,7 +110,7 @@ export const runPushAPIChatCases = async (): Promise => { console.log('PushAPI.chat.reject'); await tempUser.chat.send(secondSignerAddress, { content: 'Sending malicious message', - type: 'Text', + type: CONSTANTS.CHAT.MESSAGE_TYPE.TEXT, }); const bobRejectsRequest = await userBob.chat.reject(thirdSignerAddress); if (showAPIResponse) { diff --git a/packages/examples/sdk-backend-node/pushAPI/stream.ts b/packages/examples/sdk-backend-node/pushAPI/stream.ts index e10c599c8..8b00ad1e2 100644 --- a/packages/examples/sdk-backend-node/pushAPI/stream.ts +++ b/packages/examples/sdk-backend-node/pushAPI/stream.ts @@ -36,7 +36,7 @@ const eventlistener = async ( pushAPI: PushAPI, eventName: string ): Promise => { - pushAPI.stream.on(eventName, (data: any) => { + pushAPI._stream.on(eventName, (data: any) => { if (showAPIResponse) { console.log(data); } diff --git a/packages/restapi/src/lib/constantsV2.ts b/packages/restapi/src/lib/constantsV2.ts new file mode 100644 index 000000000..16dc768c5 --- /dev/null +++ b/packages/restapi/src/lib/constantsV2.ts @@ -0,0 +1,30 @@ +import { ENV, MessageType } from "./constants"; +import { ChatListType } from "./pushapi/pushAPITypes"; +import { STREAM } from "./pushstream/pushStreamTypes"; +import { ConditionType, GROUP_INVITER_ROLE, GROUP_RULES_CATEGORY, GROUP_RULES_PERMISSION, GROUP_RULES_SUB_CATEGORY } from "./types"; + + + +// TODO: Change this do . type +// TODO: Add Notif type. +// TODO: Add Notif settings, boolean and slider +// TODO: Notification alias chain +const CONSTANTS = { + ENV: ENV, + STREAM: STREAM, + CHAT: { + LIST_TYPE: ChatListType, + MESSAGE_TYPE: MessageType, + GROUP: { + RULES: { + CONDITION_TYPE: ConditionType, + CATEGORY: GROUP_RULES_CATEGORY, + SUBCATEGORY: GROUP_RULES_SUB_CATEGORY, + PERMISSION: GROUP_RULES_PERMISSION, + INVITER_ROLE: GROUP_INVITER_ROLE, + }, + }, + }, +}; + +export default CONSTANTS; diff --git a/packages/restapi/src/lib/index.ts b/packages/restapi/src/lib/index.ts index cbb11f040..5136174e8 100644 --- a/packages/restapi/src/lib/index.ts +++ b/packages/restapi/src/lib/index.ts @@ -6,8 +6,14 @@ import * as payloads from './payloads'; import * as chat from './chat'; import * as space from './space'; import * as video from "./video" +import CONSTANTS from './constantsV2'; export * from './types'; +export * from './pushNotification/PushNotificationTypes'; +export * from './pushstream/pushStreamTypes'; +export * from './pushapi/pushAPITypes'; +export { CONSTANTS }; + export { PushAPI } from './pushapi/PushAPI'; export { alias, diff --git a/packages/restapi/src/lib/pushNotification/notification.ts b/packages/restapi/src/lib/pushNotification/notification.ts index ebd7ade15..962ce5b74 100644 --- a/packages/restapi/src/lib/pushNotification/notification.ts +++ b/packages/restapi/src/lib/pushNotification/notification.ts @@ -15,8 +15,7 @@ import { validateCAIP, getFallbackETHCAIPAddress, } from '../helpers'; -import PROGRESSHOOK from '../progressHook'; -import { ethers } from 'ethers'; + import { PushNotificationBaseClass } from './pushNotificationBase'; // ERROR CONSTANTS diff --git a/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts b/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts index 30a06c6c4..756da351e 100644 --- a/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts +++ b/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts @@ -6,7 +6,7 @@ import { NotificationSettings, UserSetting, } from './PushNotificationTypes'; -import CONFIG, * as config from '../config'; +import * as config from '../config'; import { getAccountAddress } from '../chat/helpers'; import { IDENTITY_TYPE, NOTIFICATION_TYPE } from '../payloads/constants'; import { ethers, Signer, BigNumber } from 'ethers'; diff --git a/packages/restapi/src/lib/pushapi/PushAPI.ts b/packages/restapi/src/lib/pushapi/PushAPI.ts index 429b3aac3..5201b5ef5 100644 --- a/packages/restapi/src/lib/pushapi/PushAPI.ts +++ b/packages/restapi/src/lib/pushapi/PushAPI.ts @@ -11,6 +11,10 @@ import { User } from './user'; import { PushStream } from '../pushstream/PushStream'; import { Channel } from '../pushNotification/channel'; import { Notification } from '../pushNotification/notification'; +import { + PushStreamInitializeProps, + STREAM, +} from '../pushstream/pushStreamTypes'; export class PushAPI { private signer: SignerType; @@ -79,14 +83,9 @@ export class PushAPI { // Default options const defaultOptions: PushAPIInitializeProps = { env: ENV.STAGING, - version: Constants.ENC_TYPE_V3, autoUpgrade: true, - account: null, - streamOptions: { - enabled: true, // Default value - }, }; // Settings object @@ -100,10 +99,6 @@ export class PushAPI { options?.autoUpgrade !== undefined ? options?.autoUpgrade : defaultOptions.autoUpgrade, - streamOptions: { - ...defaultOptions.streamOptions, - ...(options?.streamOptions ?? {}), - }, }; // Get account @@ -161,24 +156,6 @@ export class PushAPI { settings.progressHook ); - if (settings.streamOptions.enabled) { - const streamInstance = await PushStream.initialize( - api.account, - decryptedPGPPrivateKey, - signer, - settings.progressHook, - { - ...settings.streamOptions, - env: settings.env, // Use the env from the top-level PushAPIInitializeProps - } - ); - if (streamInstance) { - api.stream = streamInstance; - } else { - throw new Error('Failed to initialize PushStream.'); - } - } - return api; } catch (error) { console.error('Error initializing PushAPI:', error); @@ -186,6 +163,27 @@ export class PushAPI { } } + async initStream( + listen: STREAM[], + options?: PushStreamInitializeProps + ): Promise { + if (this.stream) { + throw new Error('Stream is already initialized.'); + } + + this.stream = await PushStream.initialize( + this.account, + this.decryptedPgpPvtKey, + this.signer, + listen, + this.env, + this.progressHook, + options + ); + + return this.stream; + } + async info() { return await PUSH_USER.get({ account: this.account, diff --git a/packages/restapi/src/lib/pushapi/pushAPITypes.ts b/packages/restapi/src/lib/pushapi/pushAPITypes.ts index 094b16488..6431800d4 100644 --- a/packages/restapi/src/lib/pushapi/pushAPITypes.ts +++ b/packages/restapi/src/lib/pushapi/pushAPITypes.ts @@ -14,7 +14,6 @@ export interface PushAPIInitializeProps { versionMeta?: { NFTPGP_V1?: { password: string } }; autoUpgrade?: boolean; origin?: string; - streamOptions?: PushStreamInitializeProps; } export interface GroupCreationOptions { diff --git a/packages/restapi/src/lib/pushstream/DataModifier.ts b/packages/restapi/src/lib/pushstream/DataModifier.ts index 949a1ad45..0ff541b9b 100644 --- a/packages/restapi/src/lib/pushstream/DataModifier.ts +++ b/packages/restapi/src/lib/pushstream/DataModifier.ts @@ -6,7 +6,7 @@ import { MessageRawData, MessageEvent, MessageEventType, - Member, + GroupMember, GroupEventType, LeaveGroupEvent, JoinGroupEvent, @@ -16,6 +16,7 @@ import { NotificationEventType, NotificationType, NOTIFICATION, + ProposedEventNames, } from './pushStreamTypes'; export class DataModifier { @@ -317,16 +318,15 @@ export class DataModifier { (key) => NOTIFICATION.TYPE[key] === data.payload.data.type ) || 'BROADCAST'; // Assuming 'BROADCAST' as the default + let recipients: string[]; - let recipients: string[]; - - if (Array.isArray(data.payload.recipients)) { - recipients = data.payload.recipients; - } else if (typeof data.payload.recipients === 'string') { - recipients = [data.payload.recipients]; - } else { - recipients = Object.keys(data.payload.recipients); - } + if (Array.isArray(data.payload.recipients)) { + recipients = data.payload.recipients; + } else if (typeof data.payload.recipients === 'string') { + recipients = [data.payload.recipients]; + } else { + recipients = Object.keys(data.payload.recipients); + } const notificationEvent: NotificationEvent = { event: notificationEventType, @@ -376,4 +376,50 @@ export class DataModifier { return notificationEvent; } + + public static convertToProposedName( + currentEventName: string + ): ProposedEventNames { + switch (currentEventName) { + case 'message': + return ProposedEventNames.Message; + case 'request': + return ProposedEventNames.Request; + case 'accept': + return ProposedEventNames.Accept; + case 'reject': + return ProposedEventNames.Reject; + case 'leaveGroup': + return ProposedEventNames.LeaveGroup; + case 'joinGroup': + return ProposedEventNames.JoinGroup; + case 'createGroup': + return ProposedEventNames.CreateGroup; + case 'updateGroup': + return ProposedEventNames.UpdateGroup; + case 'remove': + return ProposedEventNames.Remove; + default: + throw new Error(`Unknown current event name: ${currentEventName}`); + } + } + + public static handleToField(data: any): void { + switch (data.event) { + case ProposedEventNames.LeaveGroup: + case ProposedEventNames.JoinGroup: + data.to = null; + break; + + case ProposedEventNames.Accept: + case ProposedEventNames.Reject: + if (data.meta?.group) { + data.to = null; + } + break; + + default: + break; + } + } } diff --git a/packages/restapi/src/lib/pushstream/PushStream.ts b/packages/restapi/src/lib/pushstream/PushStream.ts index f7102175e..ecc0b39d2 100644 --- a/packages/restapi/src/lib/pushstream/PushStream.ts +++ b/packages/restapi/src/lib/pushstream/PushStream.ts @@ -5,7 +5,6 @@ import { GroupEventType, MessageEventType, NotificationEventType, - ProposedEventNames, PushStreamInitializeProps, STREAM, } from './pushStreamTypes'; @@ -22,46 +21,23 @@ export class PushStream extends EventEmitter { private raw: boolean; private options: PushStreamInitializeProps; private chatInstance: Chat; + private listen: STREAM[]; constructor( account: string, private decryptedPgpPvtKey: string, private signer: SignerType, + private _listen: STREAM[], options: PushStreamInitializeProps, private progressHook?: (progress: ProgressHookType) => void ) { super(); this.account = account; - this.pushChatSocket = createSocketConnection({ - user: walletToPCAIP10(account), - socketType: 'chat', - socketOptions: { - autoConnect: options.connection?.auto ?? true, - reconnectionAttempts: options.connection?.retries ?? 3, - }, - env: options.env as ENV, - }); - - this.pushNotificationSocket = createSocketConnection({ - user: pCAIP10ToWallet(this.account), - env: options.env as ENV, - socketOptions: { - autoConnect: options.connection?.auto ?? true, - reconnectionAttempts: options.connection?.retries ?? 3, - }, - }); - - if (!this.pushNotificationSocket) { - throw new Error('Push notification socket not connected'); - } - - if (!this.pushChatSocket) { - throw new Error('Push chat socket not connected'); - } this.raw = options.raw ?? false; this.options = options; + this.listen = _listen; this.chatInstance = new Chat( this.account, @@ -76,205 +52,343 @@ export class PushStream extends EventEmitter { account: string, decryptedPgpPvtKey: string, signer: SignerType, + listen: STREAM[], + env: ENV, progressHook?: (progress: ProgressHookType) => void, options?: PushStreamInitializeProps ): Promise { const defaultOptions: PushStreamInitializeProps = { - listen: [], - env: ENV.LOCAL, raw: false, connection: { auto: true, retries: 3, }, + env: env, }; + if (!listen || listen.length === 0) { + throw new Error( + 'The listen property must have at least one STREAM type.' + ); + } + const settings = { ...defaultOptions, ...options, }; + const accountToUse = settings.overrideAccount || account; + const stream = new PushStream( - account, + accountToUse, decryptedPgpPvtKey, signer, + listen, settings, progressHook ); - await stream.init(); return stream; } - private convertToProposedName(currentEventName: string): ProposedEventNames { - switch (currentEventName) { - case 'message': - return ProposedEventNames.Message; - case 'request': - return ProposedEventNames.Request; - case 'accept': - return ProposedEventNames.Accept; - case 'reject': - return ProposedEventNames.Reject; - case 'leaveGroup': - return ProposedEventNames.LeaveGroup; - case 'joinGroup': - return ProposedEventNames.JoinGroup; - case 'createGroup': - return ProposedEventNames.CreateGroup; - case 'updateGroup': - return ProposedEventNames.UpdateGroup; - case 'remove': - return ProposedEventNames.Remove; - default: - throw new Error(`Unknown current event name: ${currentEventName}`); - } - } + public async connect(): Promise { + const shouldInitializeChatSocket = + !this.listen || + this.listen.length === 0 || + this.listen.includes(STREAM.CHAT) || + this.listen.includes(STREAM.CHAT_OPS); + const shouldInitializeNotifSocket = + !this.listen || + this.listen.length === 0 || + this.listen.includes(STREAM.NOTIF) || + this.listen.includes(STREAM.NOTIF_OPS); - private handleToField(data: any): void { - switch (data.event) { - case ProposedEventNames.LeaveGroup: - case ProposedEventNames.JoinGroup: - data.to = null; - break; - - case ProposedEventNames.Accept: - case ProposedEventNames.Reject: - if (data.meta?.group) { - data.to = null; + let isChatSocketConnected = false; + let isNotifSocketConnected = false; + + // Function to check and emit the STREAM.CONNECT event + const checkAndEmitConnectEvent = () => { + if ( + ((shouldInitializeChatSocket && isChatSocketConnected) || + !shouldInitializeChatSocket) && + ((shouldInitializeNotifSocket && isNotifSocketConnected) || + !shouldInitializeNotifSocket) + ) { + this.emit(STREAM.CONNECT); + console.log('Emitted STREAM.CONNECT'); + } + }; + + const handleSocketDisconnection = async (socketType: 'chat' | 'notif') => { + //console.log(`${socketType.toUpperCase()} Socket Disconnected`); + + if (socketType === 'chat') { + isChatSocketConnected = false; + if (isNotifSocketConnected) { + if ( + this.pushNotificationSocket && + this.pushNotificationSocket.connected + ) { + //console.log('Disconnecting Notification Socket...'); + this.pushNotificationSocket.disconnect(); + } + } else { + // Emit STREAM.DISCONNECT only if the notification socket was already disconnected + this.emit(STREAM.DISCONNECT); + console.log('Emitted STREAM.DISCONNECT '); } - break; + } else if (socketType === 'notif') { + isNotifSocketConnected = false; + if (isChatSocketConnected) { + if (this.pushChatSocket && this.pushChatSocket.connected) { + //console.log('Disconnecting Chat Socket...'); + this.pushChatSocket.disconnect(); + } + } else { + // Emit STREAM.DISCONNECT only if the chat socket was already disconnected + this.emit(STREAM.DISCONNECT); + console.log('Emitted STREAM.DISCONNECT'); + } + } + }; - default: - break; - } - } + if (shouldInitializeChatSocket) { + if (!this.pushChatSocket) { + // If pushChatSocket does not exist, create a new socket connection + this.pushChatSocket = createSocketConnection({ + user: walletToPCAIP10(this.account), + socketType: 'chat', + socketOptions: { + autoConnect: this.options?.connection?.auto ?? true, + reconnectionAttempts: this.options?.connection?.retries ?? 3, + }, + env: this.options?.env as ENV, + }); - private shouldEmitChat(dataChatId: string): boolean { - if (!this.options.filter?.chats || this.options.filter.chats.length === 0) { - return true; + if (!this.pushChatSocket) { + throw new Error('Push chat socket not connected'); + } + } else if (!this.pushChatSocket.connected) { + // If pushChatSocket exists but is not connected, attempt to reconnect + console.log('Attempting to reconnect push chat socket...'); + this.pushChatSocket.connect(); // Assuming connect() is the method to re-establish connection + } else { + // If pushChatSocket is already connected + console.log('Push chat socket already connected'); + } } - return this.options.filter.chats.includes(dataChatId); - } - private shouldEmitChannel(dataChannelId: string): boolean { - if ( - !this.options.filter?.channels || - this.options.filter.channels.length === 0 - ) { - return true; + if (shouldInitializeNotifSocket) { + if (!this.pushNotificationSocket) { + // If pushNotificationSocket does not exist, create a new socket connection + this.pushNotificationSocket = createSocketConnection({ + user: pCAIP10ToWallet(this.account), + env: this.options?.env as ENV, + socketOptions: { + autoConnect: this.options?.connection?.auto ?? true, + reconnectionAttempts: this.options?.connection?.retries ?? 3, + }, + }); + + if (!this.pushNotificationSocket) { + throw new Error('Push notification socket not connected'); + } + } else if (!this.pushNotificationSocket.connected) { + // If pushNotificationSocket exists but is not connected, attempt to reconnect + console.log('Attempting to reconnect push notification socket...'); + this.pushNotificationSocket.connect(); // Assuming connect() is the method to re-establish connection + } else { + // If pushNotificationSocket is already connected + console.log('Push notification socket already connected'); + } } - return this.options.filter.channels.includes(dataChannelId); - } - public async init(): Promise { const shouldEmit = (eventType: STREAM): boolean => { - if (!this.options.listen || this.options.listen.length === 0) { + if (!this.listen || this.listen.length === 0) { return true; } - return this.options.listen.includes(eventType); + return this.listen.includes(eventType); }; - this.pushChatSocket.on(EVENTS.CHAT_GROUPS, (data: any) => { - try { - const modifiedData = DataModifier.handleChatGroupEvent(data, this.raw); - modifiedData.event = this.convertToProposedName(modifiedData.event); - this.handleToField(modifiedData); - if (this.shouldEmitChat(data.chatId)) { - if ( - data.eventType === GroupEventType.JoinGroup || - data.eventType === GroupEventType.LeaveGroup || - data.eventType === MessageEventType.Request || - data.eventType === GroupEventType.Remove - ) { - if (shouldEmit(STREAM.CHAT)) { - this.emit(STREAM.CHAT, modifiedData); - } - } else { - if (shouldEmit(STREAM.CHAT_OPS)) { - this.emit(STREAM.CHAT_OPS, modifiedData); + if (this.pushChatSocket) { + this.pushChatSocket.on(EVENTS.CONNECT, async () => { + isChatSocketConnected = true; + checkAndEmitConnectEvent(); + console.log(`Chat Socket Connected (ID: ${this.pushChatSocket.id})`); + }); + + this.pushChatSocket.on(EVENTS.DISCONNECT, async () => { + await handleSocketDisconnection('chat'); + //console.log(`Chat Socket Disconnected`); + }); + + this.pushChatSocket.on(EVENTS.CHAT_GROUPS, (data: any) => { + try { + const modifiedData = DataModifier.handleChatGroupEvent( + data, + this.raw + ); + modifiedData.event = DataModifier.convertToProposedName( + modifiedData.event + ); + DataModifier.handleToField(modifiedData); + if (this.shouldEmitChat(data.chatId)) { + if ( + data.eventType === GroupEventType.JoinGroup || + data.eventType === GroupEventType.LeaveGroup || + data.eventType === MessageEventType.Request || + data.eventType === GroupEventType.Remove + ) { + if (shouldEmit(STREAM.CHAT)) { + this.emit(STREAM.CHAT, modifiedData); + } + } else { + if (shouldEmit(STREAM.CHAT_OPS)) { + this.emit(STREAM.CHAT_OPS, modifiedData); + } } } + } catch (error) { + console.error( + 'Error handling CHAT_GROUPS event:', + error, + 'Data:', + data + ); } - } catch (error) { - console.error( - 'Error handling CHAT_GROUPS event:', - error, - 'Data:', - data - ); - } - }); - - this.pushChatSocket.on(EVENTS.CHAT_RECEIVED_MESSAGE, async (data: any) => { - try { - if ( - data.messageCategory == 'Chat' || - data.messageCategory == 'Request' - ) { - data = await this.chatInstance.decrypt([data]); - data = data[0]; - } + }); - const modifiedData = DataModifier.handleChatEvent(data, this.raw); - modifiedData.event = this.convertToProposedName(modifiedData.event); - this.handleToField(modifiedData); - if (this.shouldEmitChat(data.chatId)) { - if (shouldEmit(STREAM.CHAT)) { - this.emit(STREAM.CHAT, modifiedData); + this.pushChatSocket.on( + EVENTS.CHAT_RECEIVED_MESSAGE, + async (data: any) => { + try { + if ( + data.messageCategory == 'Chat' || + data.messageCategory == 'Request' + ) { + data = await this.chatInstance.decrypt([data]); + data = data[0]; + } + + const modifiedData = DataModifier.handleChatEvent(data, this.raw); + modifiedData.event = DataModifier.convertToProposedName( + modifiedData.event + ); + DataModifier.handleToField(modifiedData); + if (this.shouldEmitChat(data.chatId)) { + if (shouldEmit(STREAM.CHAT)) { + this.emit(STREAM.CHAT, modifiedData); + } + } + } catch (error) { + console.error( + 'Error handling CHAT_RECEIVED_MESSAGE event:', + error, + 'Data:', + data + ); } } - } catch (error) { - console.error( - 'Error handling CHAT_RECEIVED_MESSAGE event:', - error, - 'Data:', - data - ); - } - }); - - this.pushNotificationSocket.on(EVENTS.USER_FEEDS, (data: any) => { - try { - const modifiedData = DataModifier.mapToNotificationEvent( - data, - NotificationEventType.INBOX, - this.account === data.sender ? 'self' : 'other', - this.raw + ); + } + + if (this.pushNotificationSocket) { + this.pushNotificationSocket.on(EVENTS.CONNECT, async () => { + console.log( + `Notification Socket Connected (ID: ${this.pushNotificationSocket.id})` ); + isNotifSocketConnected = true; + checkAndEmitConnectEvent(); + }); + + this.pushNotificationSocket.on(EVENTS.DISCONNECT, async () => { + await handleSocketDisconnection('notif'); + //console.log(`Notification Socket Disconnected`); + }); + + this.pushNotificationSocket.on(EVENTS.USER_FEEDS, (data: any) => { + try { + const modifiedData = DataModifier.mapToNotificationEvent( + data, + NotificationEventType.INBOX, + this.account === data.sender ? 'self' : 'other', + this.raw + ); - if (this.shouldEmitChannel(modifiedData.from)) { - if (shouldEmit(STREAM.NOTIF)) { - this.emit(STREAM.NOTIF, modifiedData); + if (this.shouldEmitChannel(modifiedData.from)) { + if (shouldEmit(STREAM.NOTIF)) { + this.emit(STREAM.NOTIF, modifiedData); + } } + } catch (error) { + console.error( + 'Error handling USER_FEEDS event:', + error, + 'Data:', + data + ); } - } catch (error) { - console.error('Error handling USER_FEEDS event:', error, 'Data:', data); - } - }); - - this.pushNotificationSocket.on(EVENTS.USER_SPAM_FEEDS, (data: any) => { - try { - const modifiedData = DataModifier.mapToNotificationEvent( - data, - NotificationEventType.SPAM, - this.account === data.sender ? 'self' : 'other', - this.raw - ); - modifiedData.origin = - this.account === modifiedData.from ? 'self' : 'other'; - if (this.shouldEmitChannel(modifiedData.from)) { - if (shouldEmit(STREAM.NOTIF)) { - this.emit(STREAM.NOTIF, modifiedData); + }); + + this.pushNotificationSocket.on(EVENTS.USER_SPAM_FEEDS, (data: any) => { + try { + const modifiedData = DataModifier.mapToNotificationEvent( + data, + NotificationEventType.SPAM, + this.account === data.sender ? 'self' : 'other', + this.raw + ); + modifiedData.origin = + this.account === modifiedData.from ? 'self' : 'other'; + if (this.shouldEmitChannel(modifiedData.from)) { + if (shouldEmit(STREAM.NOTIF)) { + this.emit(STREAM.NOTIF, modifiedData); + } } + } catch (error) { + console.error( + 'Error handling USER_SPAM_FEEDS event:', + error, + 'Data:', + data + ); } - } catch (error) { - console.error( - 'Error handling USER_SPAM_FEEDS event:', - error, - 'Data:', - data - ); - } - }); + }); + } + } + + public async disconnect(): Promise { + // Disconnect push chat socket if connected + if (this.pushChatSocket) { + this.pushChatSocket.disconnect(); + //console.log('Push chat socket disconnected.'); + } + + // Disconnect push notification socket if connected + if (this.pushNotificationSocket) { + this.pushNotificationSocket.disconnect(); + //console.log('Push notification socket disconnected.'); + } + } + + private shouldEmitChat(dataChatId: string): boolean { + if ( + !this.options.filter?.chats || + this.options.filter.chats.length === 0 || + this.options.filter.chats.includes('*') + ) { + return true; + } + return this.options.filter.chats.includes(dataChatId); + } + + private shouldEmitChannel(dataChannelId: string): boolean { + if ( + !this.options.filter?.channels || + this.options.filter.channels.length === 0 || + this.options.filter.channels.includes('*') + ) { + return true; + } + return this.options.filter.channels.includes(dataChannelId); } } diff --git a/packages/restapi/src/lib/pushstream/pushStreamTypes.ts b/packages/restapi/src/lib/pushstream/pushStreamTypes.ts index e96496edb..b6c2b8f64 100644 --- a/packages/restapi/src/lib/pushstream/pushStreamTypes.ts +++ b/packages/restapi/src/lib/pushstream/pushStreamTypes.ts @@ -2,7 +2,6 @@ import { Rules } from "../types"; import Constants, { ENV } from '../constants'; export type PushStreamInitializeProps = { - listen?: STREAM[]; filter?: { channels?: string[]; chats?: string[]; @@ -13,7 +12,7 @@ export type PushStreamInitializeProps = { }; raw?: boolean; env?: ENV; - enabled?: boolean; + overrideAccount?: string; }; export enum STREAM { @@ -23,6 +22,8 @@ export enum STREAM { NOTIF_OPS = 'STREAM.NOTIF_OPS', CHAT = 'STREAM.CHAT', CHAT_OPS = 'STREAM.CHAT_OPS', + CONNECT = 'STREAM.CONNECT', + DISCONNECT = 'STREAM.DISCONNECT', } export enum NotificationEventType { @@ -69,14 +70,14 @@ export interface Profile { publicKey: string; } -export interface Member { +export interface GroupMember { address: string; profile: Profile; } export interface Pending { - members: Member[]; - admins: Member[]; + members: GroupMember[]; + admins: GroupMember[]; } export interface GroupMeta { diff --git a/packages/restapi/src/lib/types/index.ts b/packages/restapi/src/lib/types/index.ts index 336175364..7ee6b8940 100644 --- a/packages/restapi/src/lib/types/index.ts +++ b/packages/restapi/src/lib/types/index.ts @@ -312,6 +312,32 @@ export enum ConditionType { GUILD = 'GUILD', } +export enum GROUP_RULES_CATEGORY { + PUSH = 'PUSH', + GUILD = 'GUILD', + ERC721 = 'ERC721', + ERC20 = 'ERC20', + CUSTOM_ENDPOINT = 'CustomEndpoint', + INVITE = 'INVITE', +} + +export enum GROUP_RULES_SUB_CATEGORY { + DEFAULT = 'DEFAULT', + HOLDER = 'holder', + GET = 'GET', +} + + +export enum GROUP_RULES_PERMISSION { + ENTRY = 'Entry', + CHAT = 'Chat', +} + +export enum GROUP_INVITER_ROLE { + ADMIN = 'ADMIN', + OWNER = 'OWNER', +} + export type Data = { contract?: string; amount?: number; diff --git a/packages/restapi/tests/lib/channel/sendNotification.test.ts b/packages/restapi/tests/lib/channel/sendNotification.test.ts index 692e8e740..017a33cdb 100644 --- a/packages/restapi/tests/lib/channel/sendNotification.test.ts +++ b/packages/restapi/tests/lib/channel/sendNotification.test.ts @@ -3,7 +3,6 @@ import * as dotenv from 'dotenv'; dotenv.config({ path: path.resolve(__dirname, '../../.env') }); import * as PUSH_PAYLOAD from '../../../src/lib/payloads'; import { expect } from 'chai'; -import Constants from '../../../src/lib/constants'; import { ethers } from 'ethers'; describe('PUSH_PAYLOAD.sendNotification functionality', () => { diff --git a/packages/restapi/tests/lib/channel/subscribeV2.test.ts b/packages/restapi/tests/lib/channel/subscribeV2.test.ts index b1bd3f0b4..6535b322e 100644 --- a/packages/restapi/tests/lib/channel/subscribeV2.test.ts +++ b/packages/restapi/tests/lib/channel/subscribeV2.test.ts @@ -3,8 +3,8 @@ import * as dotenv from 'dotenv'; dotenv.config({ path: path.resolve(__dirname, '../../.env') }); import * as PUSH_CHANNEL from '../../../src/lib/channels/'; import { expect } from 'chai'; -import Constants from '../../../src/lib/constants'; import { ethers } from 'ethers'; +import CONSTANTS from '../../../src/lib/constantsV2'; describe('PUSH_CHANNEL.subscribeV2 functionality', () => { let signer1: any; @@ -27,7 +27,7 @@ describe('PUSH_CHANNEL.subscribeV2 functionality', () => { signer: signer1, channelAddress: 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681', userAddress: `eip155:5:${account1}`, - env: Constants.ENV.STAGING, + env: CONSTANTS.ENV.STAGING, }); expect(res.status).to.be.equal('success'); }); @@ -37,7 +37,7 @@ describe('PUSH_CHANNEL.subscribeV2 functionality', () => { signer: signer1, channelAddress: 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681', userAddress: `eip155:5:${account1}`, - env: Constants.ENV.STAGING, + env: CONSTANTS.ENV.STAGING, }); console.log(res) expect(res.status).to.be.equal('success'); @@ -48,7 +48,7 @@ describe('PUSH_CHANNEL.subscribeV2 functionality', () => { signer: signer1, channelAddress: 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681', userAddress: `eip155:5:${account1}`, - env: Constants.ENV.STAGING, + env: CONSTANTS.ENV.STAGING, userSetting: '2-1-0+2-1', }); expect(res.status).to.be.equal('success'); diff --git a/packages/restapi/tests/lib/chat/createGroup.test.ts b/packages/restapi/tests/lib/chat/createGroup.test.ts index d9ea55a2e..08dd7cfde 100644 --- a/packages/restapi/tests/lib/chat/createGroup.test.ts +++ b/packages/restapi/tests/lib/chat/createGroup.test.ts @@ -1,8 +1,6 @@ -import * as chai from 'chai'; import { expect } from 'chai'; -import * as chaiAsPromised from 'chai-as-promised'; import { ethers } from 'ethers'; -import Constants from '../../../src/lib/constants'; +import CONSTANTS from '../../../src/lib/constantsV2'; import { createGroup } from '../../../src/lib/chat'; import { GroupDTO } from '../../../src/lib/types'; import { @@ -11,7 +9,7 @@ import { colors, uniqueNamesGenerator, } from 'unique-names-generator'; -const _env = Constants.ENV.DEV; +const _env = CONSTANTS.ENV.DEV; let account: string; let signer: any; let groupName: string; diff --git a/packages/restapi/tests/lib/chat/updateGroup.test.ts b/packages/restapi/tests/lib/chat/updateGroup.test.ts index 5f10b2db5..3ea7b0079 100644 --- a/packages/restapi/tests/lib/chat/updateGroup.test.ts +++ b/packages/restapi/tests/lib/chat/updateGroup.test.ts @@ -1,9 +1,12 @@ -import * as chai from 'chai'; import { expect } from 'chai'; -import * as chaiAsPromised from 'chai-as-promised'; import { ethers } from 'ethers'; -import Constants from '../../../src/lib/constants'; -import { createGroup, updateGroup, removeMembers } from '../../../src/lib/chat'; +import CONSTANTS from '../../../src/lib/constantsV2'; +import { + createGroup, + updateGroup, + removeMembers, + getGroup, +} from '../../../src/lib/chat'; import { GroupDTO } from '../../../src/lib/types'; import { adjectives, @@ -11,7 +14,7 @@ import { colors, uniqueNamesGenerator, } from 'unique-names-generator'; -const _env = Constants.ENV.DEV; +const _env = CONSTANTS.ENV.DEV; let account: string; let signer: any; let account2: string; diff --git a/packages/restapi/tests/lib/progressHook/progressHook.test.ts b/packages/restapi/tests/lib/progressHook/progressHook.test.ts index 4ea5a4155..67eb2fc58 100644 --- a/packages/restapi/tests/lib/progressHook/progressHook.test.ts +++ b/packages/restapi/tests/lib/progressHook/progressHook.test.ts @@ -7,6 +7,8 @@ import * as chaiAsPromised from 'chai-as-promised'; import { create, decryptAuth, get } from '../../../src/lib/user'; import { ethers } from 'ethers'; import Constants, { ENCRYPTION_TYPE } from '../../../src/lib/constants'; +import CONSTANTS from '../../../src/lib/constantsV2'; + import { ProgressHookType, ProgressHookTypeFunction } from '../../../src'; chai.use(chaiAsPromised); import PROGRESSHOOK from './progressHookData'; @@ -15,7 +17,7 @@ import { profileUpdate } from '../../../src/lib/user/profile.updateUser'; import { authUpdate } from '../../../src/lib/user/auth.updateUser'; describe('ProgressHook Tests', () => { - const _env = Constants.ENV.DEV; + const _env = CONSTANTS.ENV.DEV; let provider = ethers.getDefaultProvider(5); let _signer: any; let walletAddress: string; diff --git a/packages/restapi/tests/lib/pushapi/chat.test.ts b/packages/restapi/tests/lib/pushapi/chat.test.ts index c98e3e0ca..10b88c9d1 100644 --- a/packages/restapi/tests/lib/pushapi/chat.test.ts +++ b/packages/restapi/tests/lib/pushapi/chat.test.ts @@ -5,7 +5,7 @@ dotenv.config({ path: path.resolve(__dirname, '../../.env') }); import { PushAPI } from '../../../src/lib/pushapi/PushAPI'; // Ensure correct import path import { expect } from 'chai'; import { ethers } from 'ethers'; -import { MessageType } from '../../../src/lib/constants'; +import CONSTANTS from '../../../src/lib/constantsV2'; describe('PushAPI.chat functionality', () => { let userAlice: PushAPI; @@ -48,14 +48,14 @@ describe('PushAPI.chat functionality', () => { it('Should send message ', async () => { const response = await userAlice.chat.send(account2, { content: 'Hello', - type: MessageType.TEXT, + type: CONSTANTS.CHAT.MESSAGE_TYPE.TEXT, }); expect(response).to.be.an('object'); }); it('Should decrypt message ', async () => { await userAlice.chat.send(account2, { content: 'Hello', - type: MessageType.TEXT, + type: CONSTANTS.CHAT.MESSAGE_TYPE.TEXT, }); const messagePayloads = await userAlice.chat.history(account2); const decryptedMessagePayloads = await userBob.chat.decrypt( diff --git a/packages/restapi/tests/lib/pushstream/initialize.test.ts b/packages/restapi/tests/lib/pushstream/initialize.test.ts index 9ae1527f6..9f761acfc 100644 --- a/packages/restapi/tests/lib/pushstream/initialize.test.ts +++ b/packages/restapi/tests/lib/pushstream/initialize.test.ts @@ -6,11 +6,9 @@ import { ethers } from 'ethers'; import { PushAPI } from '../../../src/lib/pushapi/PushAPI'; import { sendNotification } from '../../../src/lib/payloads/sendNotifications'; import { subscribe, unsubscribe } from '../../../src/lib/channels'; +import CONSTANTS from '../../../src/lib/constantsV2'; -import { ENV } from '../../../src/lib/constants'; -import { STREAM } from '../../../src/lib/pushstream/pushStreamTypes'; import * as util from 'util'; -import { ConditionType } from '../../../src/lib'; describe('PushStream.initialize functionality', () => { it('Should initialize new stream and listen to events', async () => { @@ -21,26 +19,25 @@ describe('PushStream.initialize functionality', () => { const WALLET = ethers.Wallet.createRandom(); const signer = new ethers.Wallet(WALLET.privateKey, provider); const user = await PushAPI.initialize(signer, { - env: ENV.LOCAL, - streamOptions: { raw: true }, + env: CONSTANTS.ENV.LOCAL, }); const WALLET2 = ethers.Wallet.createRandom(); const signer2 = new ethers.Wallet(WALLET2.privateKey, provider); const user2 = await PushAPI.initialize(signer2, { - env: ENV.LOCAL, + env: CONSTANTS.ENV.LOCAL, }); const WALLET3 = ethers.Wallet.createRandom(); const signer3 = new ethers.Wallet(WALLET3.privateKey, provider); const user3 = await PushAPI.initialize(signer3, { - env: ENV.LOCAL, + env: CONSTANTS.ENV.LOCAL, }); const WALLET4 = ethers.Wallet.createRandom(); const signer4 = new ethers.Wallet(WALLET4.privateKey, provider); const user4 = await PushAPI.initialize(signer4, { - env: ENV.LOCAL, + env: CONSTANTS.ENV.LOCAL, }); const GROUP_RULES = { @@ -49,9 +46,9 @@ describe('PushStream.initialize functionality', () => { { any: [ { - type: 'PUSH', - category: 'CustomEndpoint', - subcategory: 'GET', + type: CONSTANTS.CHAT.GROUP.RULES.CONDITION_TYPE.PUSH, + category: CONSTANTS.CHAT.GROUP.RULES.CATEGORY.CUSTOM_ENDPOINT, + subcategory: CONSTANTS.CHAT.GROUP.RULES.SUBCATEGORY.GET, data: { url: 'https://api.ud-staging.com/profile/badges/dead_pixel/validate/{{user_address}}?rule=join', }, @@ -65,9 +62,9 @@ describe('PushStream.initialize functionality', () => { { any: [ { - type: 'PUSH', - category: 'CustomEndpoint', - subcategory: 'GET', + type: CONSTANTS.CHAT.GROUP.RULES.CONDITION_TYPE.PUSH, + category: CONSTANTS.CHAT.GROUP.RULES.CATEGORY.CUSTOM_ENDPOINT, + subcategory: CONSTANTS.CHAT.GROUP.RULES.SUBCATEGORY.GET, data: { url: 'https://api.ud-staging.com/profile/badges/dead_pixel/validate/{{user_address}}?rule=chat', }, @@ -89,9 +86,9 @@ describe('PushStream.initialize functionality', () => { conditions: { any: [ { - type: ConditionType.PUSH, - category: 'ERC20', - subcategory: 'holder', + type: CONSTANTS.CHAT.GROUP.RULES.CONDITION_TYPE.PUSH, + category: CONSTANTS.CHAT.GROUP.RULES.CATEGORY.ERC20, + subcategory: CONSTANTS.CHAT.GROUP.RULES.SUBCATEGORY.HOLDER, data: { contract: 'eip155:1:0xf418588522d5dd018b425E472991E52EBBeEEEEE', @@ -100,11 +97,14 @@ describe('PushStream.initialize functionality', () => { }, }, { - type: ConditionType.PUSH, - category: 'INVITE', - subcategory: 'DEFAULT', + type: CONSTANTS.CHAT.GROUP.RULES.CONDITION_TYPE.PUSH, + category: CONSTANTS.CHAT.GROUP.RULES.CATEGORY.INVITE, + subcategory: CONSTANTS.CHAT.GROUP.RULES.SUBCATEGORY.DEFAULT, data: { - inviterRoles: ['ADMIN', 'OWNER'], + inviterRoles: [ + CONSTANTS.CHAT.GROUP.RULES.INVITER_ROLE.ADMIN, + CONSTANTS.CHAT.GROUP.RULES.INVITER_ROLE.OWNER, + ], }, }, ], @@ -122,7 +122,69 @@ describe('PushStream.initialize functionality', () => { rules: {}, }; - const stream = user.stream; + /*const stream = await user.stream( + [CONSTANTS.STREAM.CHAT, CONSTANTS.STREAM.CHAT_OPS], + { + // stream supports other products as well, such as STREAM.CHAT, STREAM.CHAT_OPS + // more info can be found at push.org/docs/chat + + filter: { + channels: ['*'], + chats: ['*'], + }, + connection: { + auto: false, // should connection be automatic, else need to call stream.connect(); + retries: 3, // number of retries in case of error + }, + raw: true, // enable true to show all data + } + ); + + await stream.connect();*/ + + // Initialize wallet user, pass 'prod' instead of 'staging' for mainnet apps + const userAlice = await PushAPI.initialize(signer, { + env: CONSTANTS.ENV.STAGING, + }); + + // This will be the wallet address of the recipient + const pushAIWalletAddress = '0x99A08ac6254dcf7ccc37CeC662aeba8eFA666666'; + + // Listen for stream + // Checkout all chat stream listen options - https://push.org/docs/chat/build/stream-chats/ + // Alternatively, just initialize userAlice.stream.initialize() without any listen options to listen to all events + const stream = await userAlice.initStream( + [ + CONSTANTS.STREAM.CHAT, + CONSTANTS.STREAM.NOTIF, + CONSTANTS.STREAM.CONNECT, + CONSTANTS.STREAM.DISCONNECT, + ], + {} + ); + + stream.on(CONSTANTS.STREAM.CONNECT, (a) => { + console.log('Stream Connected'); + + // Send a message to Bob after socket connection so that messages as an example + console.log('Sending message to PushAI Bot'); + userAlice.chat.send(pushAIWalletAddress, { + content: "Gm gm! It's a me... Mario", + }); + }); + + await stream.connect(); + + stream.on(CONSTANTS.STREAM.DISCONNECT, () => { + console.log('Stream Disconnected'); + }); + + // React to message payload getting recieved + stream.on(CONSTANTS.STREAM.CHAT, (message) => { + console.log('Encrypted Message Received'); + console.log(message); + stream.disconnect(); + }); const createEventPromise = ( expectedEvent: string, @@ -164,9 +226,21 @@ describe('PushStream.initialize functionality', () => { // leave admin bug // group creator check remove add - const onDataReceived = createEventPromise('CHAT_OPS', STREAM.CHAT_OPS, 5); - const onMessageReceived = createEventPromise('CHAT', STREAM.CHAT, 4); - const onNoitificationsReceived = createEventPromise('NOTIF', STREAM.NOTIF, 4); + const onDataReceived = createEventPromise( + 'CHAT_OPS', + CONSTANTS.STREAM.CHAT_OPS, + 5 + ); + const onMessageReceived = createEventPromise( + 'CHAT', + CONSTANTS.STREAM.CHAT, + 4 + ); + const onNoitificationsReceived = createEventPromise( + 'NOTIF', + CONSTANTS.STREAM.NOTIF, + 4 + ); // Create and update group const createdGroup = await user.chat.group.create( @@ -174,20 +248,16 @@ describe('PushStream.initialize functionality', () => { CREATE_GROUP_REQUEST_2 ); - const updatedGroup = await user.chat.group.update(createdGroup.chatId, { - description: 'Updated Description', - }); - - const updatedGroup2 = await user.chat.group.add(createdGroup.chatId, { - role: 'ADMIN', - accounts: [signer2.address, signer3.address, signer4.address], - }); - - const w2wRejectRequest = await user2.chat.group.join( - createdGroup.chatId - ); + const updatedGroup = await user.chat.group.update(createdGroup.chatId, { + description: 'Updated Description', + }); + const updatedGroup2 = await user.chat.group.add(createdGroup.chatId, { + role: 'ADMIN', + accounts: [signer2.address, signer3.address, signer4.address], + }); + const w2wRejectRequest = await user2.chat.group.join(createdGroup.chatId); /*const w2wMessageResponse = await user2.chat.send(signer.address, { content: MESSAGE, diff --git a/packages/restapi/tests/lib/user/createUser.test.ts b/packages/restapi/tests/lib/user/createUser.test.ts index ade9220be..b9551f9ef 100644 --- a/packages/restapi/tests/lib/user/createUser.test.ts +++ b/packages/restapi/tests/lib/user/createUser.test.ts @@ -7,10 +7,12 @@ import * as chaiAsPromised from 'chai-as-promised'; import { create } from '../../../src/lib/user'; import { ethers } from 'ethers'; import Constants from '../../../src/lib/constants'; +import CONSTANTS from '../../../src/lib/constantsV2'; + chai.use(chaiAsPromised); describe('Create Push Profile', () => { - const _env = Constants.ENV.DEV; + const _env = CONSTANTS.ENV.DEV; let provider = ethers.getDefaultProvider(5); let _signer: any; let walletAddress: string; diff --git a/packages/restapi/tests/lib/user/createUserWithProfile.test.ts b/packages/restapi/tests/lib/user/createUserWithProfile.test.ts index c160cf25f..2ea321e61 100644 --- a/packages/restapi/tests/lib/user/createUserWithProfile.test.ts +++ b/packages/restapi/tests/lib/user/createUserWithProfile.test.ts @@ -7,10 +7,12 @@ import * as chaiAsPromised from 'chai-as-promised'; import { createUserWithProfile } from '../../../src/lib/user'; import { ethers } from 'ethers'; import Constants from '../../../src/lib/constants'; +import CONSTANTS from '../../../src/lib/constantsV2'; + chai.use(chaiAsPromised); describe('Create Push Profile with Profile update', () => { - const _env = Constants.ENV.DEV; + const _env = CONSTANTS.ENV.DEV; let provider = ethers.getDefaultProvider(5); let _signer: any; let walletAddress: string; @@ -29,7 +31,7 @@ describe('Create Push Profile with Profile update', () => { it('Push Profile V3', async () => { const name = 'John'; const desc = 'He is web3 dev' - const picture = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvUlEQVR4AcXBsa3CMBiF0Y+rFNarM0Jqi1EoU2QIj+IxPACTuGYEBnAH7Q+FI/SKe87lflxfGAkzYSbMFr7kMoh6TUTb2ph5PHeiXAZRr4lImAkzYbbkMoh6TUTb2vjFtjaiXneiXAaRMBNmwmzhxN9xI+o1MZPL4ENNzAgzYSbMFk70mohyGcz0mviFMBNmwmzhxLY2Pt2Y2dZG9HjuzAgzYSbMLvfj+mIil8F/9JqYEWbCTJgJM2EmzITZG0wkJb/EapQdAAAAAElFTkSuQmCC', + const picture = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvUlEQVR4AcXBsa3CMBiF0Y+rFNarM0Jqi1EoU2QIj+IxPACTuGYEBnAH7Q+FI/SKe87lflxfGAkzYSbMFr7kMoh6TUTb2ph5PHeiXAZRr4lImAkzYbbkMoh6TUTb2vjFtjaiXneiXAaRMBNmwmzhxN9xI+o1MZPL4ENNzAgzYSbMFk70mohyGcz0mviFMBNmwmzhxLY2Pt2Y2dZG9HjuzAgzYSbMLvfj+mIil8F/9JqYEWbCTJgJM2EmzITZG0wkJb/EapQdAAAAAElFTkSuQmCC' const user = await createUserWithProfile({ account: account, env: _env, diff --git a/packages/restapi/tests/lib/user/getUser.test.ts b/packages/restapi/tests/lib/user/getUser.test.ts index ca8fcbd9a..444c7b8a6 100644 --- a/packages/restapi/tests/lib/user/getUser.test.ts +++ b/packages/restapi/tests/lib/user/getUser.test.ts @@ -2,9 +2,10 @@ import { expect } from 'chai'; import { create, get } from '../../../src/lib/user'; import { ethers } from 'ethers'; import Constants from '../../../src/lib/constants'; +import CONSTANTS from '../../../src/lib/constantsV2'; describe('Get user', () => { - const _env = Constants.ENV.DEV; + const _env = CONSTANTS.ENV.DEV; let provider = ethers.getDefaultProvider(5); let Pkey: string; let _signer: any; diff --git a/packages/restapi/tests/lib/user/upgradeUser.test.ts b/packages/restapi/tests/lib/user/upgradeUser.test.ts index 1648f369d..2d80a191d 100644 --- a/packages/restapi/tests/lib/user/upgradeUser.test.ts +++ b/packages/restapi/tests/lib/user/upgradeUser.test.ts @@ -4,13 +4,15 @@ import * as chaiAsPromised from 'chai-as-promised'; import { create, get } from '../../../src/lib/user'; import { ethers } from 'ethers'; import Constants from '../../../src/lib/constants'; +import CONSTANTS from '../../../src/lib/constantsV2'; + import { upgrade } from '../../../src/lib/user/upgradeUser'; import { decryptPGPKey } from '../../../src/lib/helpers'; chai.use(chaiAsPromised); describe('Upgrade user keys', () => { const upgradationVersion = Constants.ENC_TYPE_V3; - const _env = Constants.ENV.DEV; + const _env = CONSTANTS.ENV.DEV; let provider = ethers.getDefaultProvider(5); let _signer: any; let walletAddress: string;