Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add notification token callback to use en addMessage Method #35

Merged
merged 9 commits into from
Nov 13, 2024
13 changes: 13 additions & 0 deletions docs/message-pickup-repository-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@ Registers a callback to handle `messagesReceived` events from the WebSocket serv

---

### `setConnectionInfo(callback)`

Registers a callback function to retrieve connection-specific information based on a given `connectionId`. This callback provides the `ConnectionInfo` object, which contains details such as the FCM notification token and maximum bytes allowed for receiving messages. This function is useful for dynamically fetching connection-related information whenever it is required by the client.

- **Parameters**:

- `callback`: A function that takes a `connectionId` (string) and returns a `Promise` resolving to a `ConnectionInfo` object or `undefined` if no information is available for the given `connectionId`.
- `connectionId` (string): The ID of the connection for which to retrieve information.

- **Returns**: `Promise<ConnectionInfo | undefined>`: The connection information, including: - `fcmNotificationToken` (optional, string): The FCM notification token for the specified connection. - `maxReceiveBytes` (optional, number): The maximum allowed bytes for receiving messages for this connection.

---

### `takeFromQueue(params)`

Retrieves messages from the queue.
Expand Down
95 changes: 73 additions & 22 deletions packages/client/src/MessagePickupRepositoryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
AddLiveSessionOptions,
MessagesReceivedCallbackParams,
ExtendedTakeFromQueueOptions,
ExtendedAddMessageOptions,
ConnectionInfo,
} from './interfaces'
import {
AddMessageOptions,
Expand All @@ -21,12 +23,11 @@ export class MessagePickupRepositoryClient implements MessagePickupRepository {
private client?: Client
private readonly logger = log
private messagesReceivedCallback: ((data: MessagesReceivedCallbackParams) => void) | null = null
private setConnectionInfoCallback?: (connectionId: string) => Promise<ConnectionInfo | undefined>
gabrielmatau79 marked this conversation as resolved.
Show resolved Hide resolved
private readonly url: string
private readonly maxReceiveBytes?: number

constructor(options: { url: string; maxReceiveBytes?: number }) {
constructor(options: { url: string }) {
this.url = options.url
this.maxReceiveBytes = options.maxReceiveBytes
}

/**
Expand Down Expand Up @@ -62,6 +63,14 @@ export class MessagePickupRepositoryClient implements MessagePickupRepository {
})
}

/**
* Checks if the WebSocket client is initialized and returns it.
* If the client is not initialized, throws an error instructing to call `connect()` first.
*
* @private
* @throws {Error} Will throw an error if the client is not initialized.
* @returns {Client} The initialized WebSocket client instance.
*/
private checkClient(): Client {
if (!this.client) {
throw new Error('Client is not initialized. Call connect() first.')
Expand Down Expand Up @@ -94,6 +103,32 @@ export class MessagePickupRepositoryClient implements MessagePickupRepository {
this.messagesReceivedCallback = callback
}

/**
* Sets the callback function to retrieve connection-specific information.
* This callback provides the `ConnectionInfo` object, containing details like
* the FCM notification token and max receive bytes, based on the given `connectionId`.
*
* @param {function} callback - A function that takes a `connectionId` as a parameter and returns
* a `Promise` that resolves to a `ConnectionInfo` object or `undefined` if no information is available.
*
* @example
* // Example of setting the callback to retrieve connection-specific information
* const client = new MessagePickupRepositoryClient({ url: 'wss://example.com' });
*
* const getConnectionInfo = async (connectionId: string) => {
* const connectionRecord = await agent.connections.findById(connectionId);
* return {
* fcmNotificationToken: connectionRecord?.getTag('device_token') as string | undefined,
* maxReceiveBytes: config.messagePickupMaxReceiveBytes,
* };
* };
*
* client.setConnectionInfo(getConnectionInfo);
*/
setConnectionInfo(callback: (connectionId: string) => Promise<ConnectionInfo | undefined>): void {
this.setConnectionInfoCallback = callback
}

/**
* Calls the 'takeFromQueue' RPC method on the WebSocket server.
* This method sends a request to retrieve messages from the queue for the specified connection.
Expand All @@ -116,9 +151,15 @@ export class MessagePickupRepositoryClient implements MessagePickupRepository {
try {
const client = this.checkClient()

const connectionInfoCallback = this.setConnectionInfoCallback
? await this.setConnectionInfoCallback(params.connectionId)
: undefined

const maxReceiveBytes = connectionInfoCallback?.maxReceiveBytes
gabrielmatau79 marked this conversation as resolved.
Show resolved Hide resolved

// Add limitBytes to params if maxReceiveBytes is set
if (this.maxReceiveBytes) {
params = { ...params, limitBytes: this.maxReceiveBytes }
if (maxReceiveBytes) {
params = { ...params, limitBytes: maxReceiveBytes }
}

// Call the RPC method and store the result as 'unknown' type initially
Expand Down Expand Up @@ -164,33 +205,43 @@ export class MessagePickupRepositoryClient implements MessagePickupRepository {
}

/**
* Call the 'addMessage' RPC method.
* This method sends a request to the WebSocket server to add a message to the queue.
* It expects the response to be a string or null.
* Calls the 'addMessage' RPC method.
* This function sends a request to the WebSocket server to add a message to the queue.
* It retrieves the device token (if available) and includes it in the parameters.
* Expects the response from the server to be a JSON string or an empty string if null.
*
* @param {AddMessageOptions} params - The parameters to pass to the 'addMessage' method, including:
* @param {ExtendedAddMessageOptions} params - Parameters for the 'addMessage' method, including:
* @property {string} connectionId - The ID of the connection to which the message will be added.
* @property {string[]} recipientDids - An array of DIDs of the recipients for whom the message is intended.
* @property {string[]} recipientDids - Array of DIDs for the intended recipients of the message.
* @property {EncryptedMessage} payload - The encrypted message content to be queued.
* @returns {Promise<string|null>} - The result from the WebSocket server, expected to be a string or null.
* @throws Will throw an error if the result is not an object, null, or if there's any issue with the WebSocket call.
* @property {string} [token] - (Optional) A token associated with the device; will be populated if available.
* @returns {Promise<string>} - The server response, expected as a JSON string or an empty string if the response is null.
* @throws {Error} Will throw an error if the result is neither an object nor null, or if any issue occurs during the WebSocket call.
*/
async addMessage(params: AddMessageOptions): Promise<string> {
async addMessage(params: ExtendedAddMessageOptions): Promise<string> {
try {
const client = this.checkClient()
// Call the RPC method and store the result as 'unknown' type initially

// Retrieve connection information using the callback, if set
const connectionInfoCallback = this.setConnectionInfoCallback
? await this.setConnectionInfoCallback(params.connectionId)
: undefined

// Set the token and max bytes from the connection info, if available
params.token = connectionInfoCallback?.fcmNotificationToken
gabrielmatau79 marked this conversation as resolved.
Show resolved Hide resolved

// Call the 'addMessage' RPC method on the WebSocket server
const result: unknown = await client.call('addMessage', params, 2000)

// Log the result and handle the response format
this.logger.debug(`**** result: ${JSON.stringify(result, null, 2)} ***`)

// Check if the result is a string and cast it
if (result && typeof result === 'object') {
return JSON.stringify(result)
} else if (result === null) {
return ''
} else {
throw new Error('Unexpected result: Expected an object or null')
}
// Return JSON stringified result if it's an object, or an empty string if result is null
if (result === null) return ''
if (typeof result === 'object') return JSON.stringify(result)

// If result is neither an object nor null, throw an error
throw new Error('Unexpected result: Expected an object or null')
} catch (error) {
// Log the error and rethrow it for further handling
this.logger.error('Error calling addMessage:', error)
Expand Down
11 changes: 10 additions & 1 deletion packages/client/src/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { QueuedMessage, TakeFromQueueOptions } from '@credo-ts/core'
import { AddMessageOptions, QueuedMessage, TakeFromQueueOptions } from '@credo-ts/core'

export interface RemoveAllMessagesOptions {
connectionId: string
Expand All @@ -22,3 +22,12 @@ export interface MessagesReceivedCallbackParams {
export interface ExtendedTakeFromQueueOptions extends TakeFromQueueOptions {
limitBytes?: number
}

export interface ExtendedAddMessageOptions extends AddMessageOptions {
token?: string
}

export interface ConnectionInfo {
fcmNotificationToken?: string
maxReceiveBytes?: number
}
Loading