Skip to content

Commit

Permalink
feat: add standalone MPR postgres module (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielmatau79 authored Dec 24, 2024
1 parent 1f30fa6 commit d499b7d
Show file tree
Hide file tree
Showing 14 changed files with 2,466 additions and 1,318 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CHANGELOG.md
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ Service designed for the management and storage of messaging for the Message Pic

## Environment Variables

| Variable | Description | Default Value |
| ---------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `APP_PORT` | The port number on which the application will run. | `3500` |
| `WS_PORT` | The port number on which the WebSocket server runs. | `3100` |
| `FCM_SERVICE_BASE_URL` | The base URL for the push notification service. | _Not set by default_ |
| `MONGODB_URI` | The MongoDB URI for connecting to the database. | `mongodb://user:password@localhost:27017/MessagePickupRepository` |
| `REDIS_TYPE` | Allows set redis type works `single` or `cluster` | `single` |
| `REDIS_NODES` | A comma-separated list of Redis nodes' `host:port` for cluster mode. Only required if `REDIS_TYPE` is set to `cluster`. Ignored in single mode. | `redis-node1:6379,redis-node2:6379,redis-node3:6379` |
| `REDIS_NATMAP` | The NAT mapping for Redis nodes in `externalAddress:host:port` format. Required for Redis cluster configurations where external IPs or ports are mapped to internal Redis node addresses. | `10.0.0.1:6379:redis-node1:6379,10.0.0.2:6379:redis-node2:6379` |
| `REDIS_URL` | The Redis database URL for connecting to the server.(only single mode) | `redis://localhost:6379` |
| `THRESHOLD_TIMESTAMP` | Allows set threshold time to execute message persist module on milisecond | `60000` |
| Variable | Description | Default Value |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `APP_PORT` | The port number on which the application will run. | `3500` |
| `WS_PORT` | The port number on which the WebSocket server runs. | `3100` |
| `FCM_SERVICE_BASE_URL` | The base URL for the push notification service. | _Not set by default_ |
| `MONGODB_URI` | The MongoDB URI for connecting to the database. | `mongodb://user:password@localhost:27017/MessagePickupRepository` |
| `REDIS_TYPE` | Allows set redis type works `single` or `cluster` | `single` |
| `REDIS_NODES` | A comma-separated list of Redis nodes' `host:port` for cluster mode. Only required if `REDIS_TYPE` is set to `cluster`. Ignored in single mode. | `redis-node1:6379,redis-node2:6379,redis-node3:6379` |
| `REDIS_NATMAP` | The NAT mapping for Redis nodes in `externalAddress:host:port` format. Required for Redis cluster configurations where external IPs or ports are mapped to internal Redis node addresses. | `10.0.0.1:6379:redis-node1:6379,10.0.0.2:6379:redis-node2:6379` |
| `REDIS_URL` | The Redis database URL for connecting to the server.(only single mode) | `redis://localhost:6379` |
| `THRESHOLD_TIMESTAMP` | Allows set threshold time to execute message persist module on milisecond | `60000` |

## Installation

Expand Down
3 changes: 3 additions & 0 deletions packages/postgres/.release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"packages/postgres": "0.0.1"
}
105 changes: 105 additions & 0 deletions packages/postgres/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# credo-ts-message-pickup-repository-pg API Usage Documentation

## Overview

The `PostgresMessagePickupRepository` implements the MessagePickupRepository interface from @credo-ts to manage messaging in live mode. It uses PostgreSQL as the storage backend for all messaging operations and introduces a publish/subscribe system to support multiple instances sharing the same database that need .

This approach centralizes all database operations for a DIDComm Mediator, simplifying its implementation and ensuring seamless scalability across multiple instances.

## Features

- Message storage and retrieval: Save and fetch messages from a PostgreSQL database.

- Pub/Sub integration: Notify other services of new messages using Pub/Sub channels.

- Live session management: Handle live sessions for efficient message delivery.

- Database initialization: Automatically set up the database structure required for message operations.

## Installation

To use this module, install package in your Didcomm Mediator App:

```bash
npm i @2060.io/credo-ts-message-pickup-repository-pg
```

## Usage

Instance `PostgresMessagePickupRepository` with requires explicit configuration defined in `PostgresMessagePickupRepositoryConfig` type through its constructor to set up the PostgreSQL connection and Logger. Ensure to provide the necessary database credentials when creating an instance of the repository.

### Example Configuration

```javascript
const messageRepository = new PostgresMessagePickupRepository({
logger: yourLoggerInstance,
postgresUser: 'your_postgres_user',
postgresPassword: 'your_postgres_password',
postgresHost: 'your_postgres_host',
postgresDatabaseName: 'your_database_name',
})
```

### Initializing the Repository

To start using the `PostgresMessagePickupRepository`, initialize it with an agent and a callback function for retrieving connection information.

Note that in this example, notification token is stored as a tag in connection records, so it is used to determine whether to create a Push notification callback or not for a given DIDComm connection.

```javascript
const connectionInfoCallback = async (connectionId) => {
const connectionRecord = await this.agent.connections.findById(connectionId)
const token = connectionRecord?.getTag('device_token') as string | null
return {
sendPushNotification: token ? (messageId) => { this.notificationSender.send(token, messageId }: undefined,
}
}
await messagePickupRepository.initialize({ agent, connectionInfoCallback })
```
### Using with a Credo-based DIDComm Mediator
This full example shows how `PostgresMessagePickupRepository` is created an initialized alongside an `Agent` instance:
```javascript
import { Agent, MediatorModule, MessagePickupModule } from '@credo-ts/core'
import { agentDependencies } from '@credo-ts/node'
import { MessageForwardingStrategy } from '@credo-ts/core/build/modules/routing/MessageForwardingStrategy'
import { PostgresMessagePickupRepository } from './PostgresMessagePickupRepository'

const messagePickupRepository = new PostgresMessagePickupRepository({
postgresHost: 'postgres',
postgresUser: 'user',
postgresPassword: 'pass',
})
const agent = new Agent({
dependencies: agentDependencies,
config: { label: 'Test' },
modules: {
mediator: new MediatorModule({ messageForwardingStrategy: MessageForwardingStrategy.QueueOnly }),
messagePickup: new MessagePickupModule({
messagePickupRepository,
}),
},
})

const notificationSender = // { your implementation of a Push notification service }
const connectionInfoCallback = async (connectionId: string) => {
const connectionRecord = await agent.connections.findById(connectionId)

const token = connectionRecord?.getTag('device_token') as string | null

return {
sendPushNotification: token
? (messageId: string) => {
notificationSender.send(token, messageId)
}
: undefined,
}
}

await messagePickupRepository.initialize({ agent, connectionInfoCallback })
await agent.initialize()
```
With these steps, you can now use the `PostgresMessagePickupRepository` with your Credo-based DIDComm mediator. Have fun!
28 changes: 28 additions & 0 deletions packages/postgres/config/dbCollections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const messagesTableName = 'queuedmessage'

export const createTableMessage = `
CREATE TABLE IF NOT EXISTS ${messagesTableName} (
id VARCHAR(20) DEFAULT substr(md5(random()::text), 1, 20) PRIMARY KEY,
connectionId VARCHAR(255),
recipientKeys TEXT[],
encryptedMessage JSONB,
state VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
`

export const liveSessionTableName = 'livesession'

export const createTableLive = `
CREATE TABLE IF NOT EXISTS ${liveSessionTableName} (
sessionid VARCHAR(255) PRIMARY KEY,
connectionid VARCHAR(50),
protocolVersion VARCHAR(50),
role VARCHAR(50),
instance VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);`

export const messageTableIndex = `CREATE INDEX IF NOT EXISTS "${messagesTableName}_connectionId_index" ON "${messagesTableName}" (connectionId);`

export const liveSessionTableIndex = `CREATE INDEX IF NOT EXISTS "${liveSessionTableName}_connectionid" ON "${liveSessionTableName}" USING btree ("connectionid");`
21 changes: 21 additions & 0 deletions packages/postgres/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Config } from '@jest/types'

const config: Config.InitialOptions = {
preset: 'ts-jest',
testEnvironment: 'node',
coveragePathIgnorePatterns: ['/build/', '/node_modules/', '/__tests__/', 'tests'],
coverageDirectory: '<rootDir>/coverage/',
testMatch: ['**/?(*.)+(spec|test).[tj]s?(x)'],
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{
isolatedModules: true,
},
],
'^.+\\.jsx?$': require.resolve('babel-jest'),
},
moduleNameMapper: { '^uuid$': 'uuid' },
}

export default config
46 changes: 46 additions & 0 deletions packages/postgres/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@2060.io/credo-ts-message-pickup-repository-pg",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
"version": "0.0.1",
"files": [
"build"
],
"publishConfig": {
"access": "public"
},
"description": "Message Pickup Repository Postgres module",
"license": "Apache-2.0",
"homepage": "https://github.com/2060-io/message-pickup-repository/tree/main/packages/postgres",
"repository": {
"type": "git",
"url": "https://github.com/2060-io/message-pickup-repository",
"directory": "packages/postgres"
},
"scripts": {
"build": "yarn run clean && yarn run compile",
"clean": "rimraf -rf ./build",
"compile": "tsc -p tsconfig.build.json",
"prepublishOnly": "yarn run build",
"test": "jest"
},
"dependencies": {
"@credo-ts/core": "^0.5.11",
"loglevel": "^1.8.0",
"pg": "^8.11.3",
"pg-pubsub": "^0.8.1",
"typescript": "^4.0.0"
},
"devDependencies": {
"@types/node": "^16.0.0",
"@types/pg": "^8.11.10",
"jest": "^27.0.0",
"ts-jest": "^27.0.0",
"ts-loader": "^9.0.0",
"webpack": "^5.0.0",
"webpack-cli": "^4.0.0"
},
"peerDependencies": {
"@credo-ts/core": "^0.5.11"
}
}
5 changes: 5 additions & 0 deletions packages/postgres/release-please-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"packages/postgres": {
"release-type": "node"
}
}
Loading

0 comments on commit d499b7d

Please sign in to comment.