Skip to content

Commit

Permalink
Merge pull request #28 from credebl/refactor/mediator
Browse files Browse the repository at this point in the history
feat: push notifications
  • Loading branch information
TimoGlastra authored Jan 8, 2025
2 parents 7488ce7 + b3aee8e commit ad37209
Show file tree
Hide file tree
Showing 39 changed files with 2,304 additions and 501 deletions.
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ POSTGRES_PASSWORD=
POSTGRES_HOST=
POSTGRES_ADMIN_USER=
POSTGRES_ADMIN_PASSWORD=

USE_PUSH_NOTIFICATIONS='true'
NOTIFICATION_WEBHOOK_URL=

# We need NGROK Auth token in development and you can get one from here https://dashboard.ngrok.com/get-started/your-authtoken
NGROK_AUTH_TOKEN=
2 changes: 1 addition & 1 deletion .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: 18.x
node-version: 20.x
cache: yarn

# Installing the project dependencies
Expand Down
18 changes: 12 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ FROM ubuntu:20.04 as base
ENV DEBIAN_FRONTEND noninteractive

RUN apt-get update -y && apt-get install -y \
apt-transport-https \
curl \
make \
gcc \
g++
apt-transport-https \
curl \
make \
gcc \
g++

# nodejs
RUN curl -sL https://deb.nodesource.com/setup_18.x | bash
RUN curl -sL https://deb.nodesource.com/setup_20.x | bash

# install depdencies and enable corepack
RUN apt-get update -y && apt-get install -y --allow-unauthenticated nodejs
Expand All @@ -28,6 +28,9 @@ WORKDIR /www
COPY package.json /www/package.json
COPY yarn.lock /www/yarn.lock

# Copy patches folder
COPY patches /www/patches

# Run yarn install
RUN yarn install

Expand All @@ -47,6 +50,9 @@ COPY --from=setup /tmp/yarn-cache /tmp/yarn-cache
COPY package.json /www/package.json
COPY yarn.lock /www/yarn.lock

# Copy patches folder
COPY patches /www/patches

WORKDIR /www

# Run yarn install
Expand Down
13 changes: 9 additions & 4 deletions dev.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { config } from 'dotenv'
import { connect } from 'ngrok'
import { connect } from '@ngrok/ngrok'

config()

Expand All @@ -9,13 +9,18 @@ const port = 3000
* Connect to ngrok and then set the port and url on the environment before importing
* the index file.
*/
void connect(port).then((url) => {
// TODO: have to add auth token now to use ngrok check this later
void connect({
port,
authtoken: process.env.NGROK_AUTH_TOKEN,
}).then((app) => {
// eslint-disable-next-line no-console
console.log('Got ngrok url:', url)
console.log('Got ngrok url:', app.url())
const url = app.url()

process.env.NODE_ENV = 'development'
process.env.AGENT_PORT = `${port}`
process.env.AGENT_ENDPOINTS = `${url},${url.replace('http', 'ws')}`
process.env.AGENT_ENDPOINTS = `${url},${url?.replace('http', 'ws')}`
process.env.SHORTENER_BASE_URL = `${url}/s`

require('./src/index')
Expand Down
34 changes: 16 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
"type": "git",
"url": "https://github.com/animo/animo-mediator"
},
"engines": {
"node": "^18.0.0"
},
"packageManager": "[email protected]",
"scripts": {
"test": "jest",
Expand All @@ -28,32 +25,33 @@
"prepublishOnly": "yarn run build",
"dev": "ts-node dev",
"start": "NODE_ENV=production node build/index.js",
"validate": "yarn build && yarn check-format"
"validate": "yarn build && yarn check-format",
"postinstall": "npx patch-package"
},
"dependencies": {
"@aries-framework/askar": "^0.4.1",
"@aries-framework/core": "^0.4.1",
"@aries-framework/node": "^0.4.1",
"@hyperledger/aries-askar-nodejs": "^0.1.0",
"express": "^4.18.1",
"prettier": "^2.8.4",
"@credo-ts/askar": "^0.5.0",
"@credo-ts/core": "^0.5.0",
"@credo-ts/node": "^0.5.0",
"@hyperledger/aries-askar-nodejs": "^0.2.0",
"dotenv": "^16.4.5",
"express": "^4.21.2",
"tslog": "^3.3.3",
"tsyringe": "^4.7.0",
"ws": "^8.8.1"
"tsyringe": "^4.8.0",
"ws": "^8.17.1"
},
"devDependencies": {
"@ngrok/ngrok": "^1.2.0",
"@types/express": "^4.17.13",
"@types/jest": "^29.2.0",
"@types/node": "^16",
"@types/node-fetch": "^2.6.4",
"dotenv": "^16.0.1",
"@types/node": "^20.14.9",
"@types/node-fetch": "^2.6.11",
"jest": "^29.2.2",
"ngrok": "^4.3.1",
"prettier": "^2.8.4",
"ts-jest": "^29.0.3",
"ts-node": "^10.9.1",
"typescript": "^4.8.4"
},
"resolutions": {
"ref-napi": "npm:@2060.io/ref-napi"
"engines": {
"node": ">=18"
}
}
45 changes: 45 additions & 0 deletions patches/@credo-ts+core+0.5.3.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
diff --git a/node_modules/@credo-ts/core/build/agent/MessageSender.js b/node_modules/@credo-ts/core/build/agent/MessageSender.js
index 689b024..656a3b5 100644
--- a/node_modules/@credo-ts/core/build/agent/MessageSender.js
+++ b/node_modules/@credo-ts/core/build/agent/MessageSender.js
@@ -75,7 +75,7 @@ let MessageSender = class MessageSender {
this.logger.debug('Sending message');
await session.send(agentContext, encryptedMessage);
}
- async sendPackage(agentContext, { connection, encryptedMessage, recipientKey, options, }) {
+ async sendPackage(agentContext, { connection, encryptedMessage, recipientKey, options, messageType, }) {
var _a, e_1, _b, _c;
var _d;
const errors = [];
@@ -145,6 +145,7 @@ let MessageSender = class MessageSender {
connectionId: connection.id,
recipientDids: [(0, helpers_1.verkeyToDidKey)(recipientKey)],
payload: encryptedMessage,
+ messageType,
});
return;
}
diff --git a/node_modules/@credo-ts/core/build/modules/message-pickup/storage/MessagePickupRepositoryOptions.d.ts b/node_modules/@credo-ts/core/build/modules/message-pickup/storage/MessagePickupRepositoryOptions.d.ts
index decb61a..b0c4342 100644
--- a/node_modules/@credo-ts/core/build/modules/message-pickup/storage/MessagePickupRepositoryOptions.d.ts
+++ b/node_modules/@credo-ts/core/build/modules/message-pickup/storage/MessagePickupRepositoryOptions.d.ts
@@ -13,6 +13,7 @@ export interface AddMessageOptions {
connectionId: string;
recipientDids: string[];
payload: EncryptedMessage;
+ messageType?: string;
}
export interface RemoveMessagesOptions {
connectionId: string;
diff --git a/node_modules/@credo-ts/core/build/modules/routing/services/MediatorService.js b/node_modules/@credo-ts/core/build/modules/routing/services/MediatorService.js
index 6818a3b..6474136 100644
--- a/node_modules/@credo-ts/core/build/modules/routing/services/MediatorService.js
+++ b/node_modules/@credo-ts/core/build/modules/routing/services/MediatorService.js
@@ -99,6 +99,7 @@ let MediatorService = class MediatorService {
connection,
recipientKey: (0, helpers_1.verkeyToDidKey)(message.to),
encryptedMessage: message.message,
+ messageType: message.messageType,
});
}
}
25 changes: 13 additions & 12 deletions src/agent.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { AskarModule, AskarMultiWalletDatabaseScheme } from '@aries-framework/askar'
import { AskarModule, AskarMultiWalletDatabaseScheme } from '@credo-ts/askar'
import {
Agent,
CacheModule,
ConnectionsModule,
DidCommMimeType,
HttpOutboundTransport,
InMemoryLruCache,
MediatorModule,
OutOfBandRole,
OutOfBandState,
WalletConfig,
WsOutboundTransport,
} from '@aries-framework/core'
import { HttpInboundTransport, WsInboundTransport, agentDependencies } from '@aries-framework/node'
} from '@credo-ts/core'
import { HttpInboundTransport, WsInboundTransport, agentDependencies } from '@credo-ts/node'
import { ariesAskar } from '@hyperledger/aries-askar-nodejs'
import type { Socket } from 'net'

Expand All @@ -23,13 +21,11 @@ import { AGENT_ENDPOINTS, AGENT_NAME, AGENT_PORT, LOG_LEVEL, POSTGRES_HOST, WALL
import { askarPostgresConfig } from './database'
import { Logger } from './logger'
import { StorageMessageQueueModule } from './storage/StorageMessageQueueModule'
import { PushNotificationsFcmModule } from './push-notifications/fcm'

function createModules() {
const modules = {
StorageModule: new StorageMessageQueueModule(),
cache: new CacheModule({
cache: new InMemoryLruCache({ limit: 500 }),
}),
storageModule: new StorageMessageQueueModule(),
connections: new ConnectionsModule({
autoAcceptConnections: true,
}),
Expand All @@ -40,6 +36,7 @@ function createModules() {
ariesAskar,
multiWalletDatabaseScheme: AskarMultiWalletDatabaseScheme.ProfilePerWallet,
}),
pushNotificationsFcm: new PushNotificationsFcmModule(),
}

return modules
Expand Down Expand Up @@ -80,9 +77,8 @@ export async function createAgent() {
walletConfig: walletConfig,
useDidSovPrefixWhereAllowed: true,
logger: logger,
// FIXME: We should probably remove this at some point, but it will require custom logic
// Also, doesn't work with multi-tenancy yet
autoUpdateStorageOnStartup: true,
backupBeforeStorageUpdate: false,
didCommMimeType: DidCommMimeType.V0,
},
dependencies: agentDependencies,
Expand All @@ -103,6 +99,11 @@ export async function createAgent() {
agent.registerInboundTransport(wsInboundTransport)
agent.registerOutboundTransport(wsOutboundTransport)

// Added health check endpoint
httpInboundTransport.app.get('/health', async (_req, res) => {
res.status(200).send('Ok')
})

// eslint-disable-next-line @typescript-eslint/no-misused-promises
httpInboundTransport.app.get('/invite', async (req, res) => {
if (!req.query._oobid || typeof req.query._oobid !== 'string') {
Expand Down Expand Up @@ -134,4 +135,4 @@ export async function createAgent() {
return agent
}

export type MediatorAgent = ReturnType<typeof createAgent>
export type MediatorAgent = Agent<ReturnType<typeof createModules>>
14 changes: 10 additions & 4 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { LogLevel } from '@aries-framework/core'
import { LogLevel } from '@credo-ts/core'
import * as dotenv from 'dotenv'
dotenv.config()

export const AGENT_PORT = process.env.AGENT_PORT ? Number(process.env.AGENT_PORT) : 3000
export const AGENT_NAME = process.env.AGENT_NAME || 'Animo Mediator'
export const WALLET_NAME = process.env.WALLET_NAME || 'animo-mediator-dev'
export const WALLET_KEY = process.env.WALLET_KEY || 'animo-mediator-dev'
export const AGENT_NAME = process.env.AGENT_NAME || 'CREDEBL Mediator'
export const WALLET_NAME = process.env.WALLET_NAME || 'credebl-mediator-dev'
export const WALLET_KEY = process.env.WALLET_KEY || 'credebl-mediator-dev'
export const AGENT_ENDPOINTS = process.env.AGENT_ENDPOINTS?.split(',') ?? [
`http://localhost:${AGENT_PORT}`,
`ws://localhost:${AGENT_PORT}`,
Expand All @@ -20,3 +22,7 @@ export const INVITATION_URL = process.env.INVITATION_URL
export const LOG_LEVEL = LogLevel.debug

export const IS_DEV = process.env.NODE_ENV === 'development'

export const USE_PUSH_NOTIFICATIONS = process.env.USE_PUSH_NOTIFICATIONS === 'true'

export const NOTIFICATION_WEBHOOK_URL = process.env.NOTIFICATION_WEBHOOK_URL || 'http://localhost:5000'
2 changes: 1 addition & 1 deletion src/database.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AskarWalletPostgresStorageConfig } from '@aries-framework/askar/build/wallet'
import type { AskarWalletPostgresStorageConfig } from '@credo-ts/askar/build/wallet'

import { POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_HOST } from './constants'

Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OutOfBandRepository, OutOfBandRole, OutOfBandState } from '@aries-framework/core'
import { OutOfBandRepository, OutOfBandRole, OutOfBandState } from '@credo-ts/core'

import { createAgent } from './agent'
import { INVITATION_URL } from './constants'
Expand Down
4 changes: 2 additions & 2 deletions src/logger/Logger.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */

import { LogLevel, BaseLogger } from '@aries-framework/core'
import { LogLevel, BaseLogger } from '@credo-ts/core'
import { Logger as TSLogger } from 'tslog'

import { replaceError } from './replaceError'
Expand All @@ -23,7 +23,7 @@ export class Logger extends BaseLogger {
super(logLevel)

this.logger = new TSLogger({
name: 'DIDComm Chat',
name: 'Mediator Agent',
minLevel: this.logLevel == LogLevel.off ? 'fatal' : this.tsLogLevelMap[this.logLevel],
ignoreStackLevels: 5,
})
Expand Down
59 changes: 59 additions & 0 deletions src/push-notifications/fcm/PushNotificationsFcmApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { FcmDeviceInfo } from './models'

import { OutboundMessageContext, AgentContext, ConnectionService, injectable, MessageSender } from '@credo-ts/core'

import { PushNotificationsFcmService } from './services/PushNotificationsFcmService'
import {
PushNotificationsFcmDeviceInfoHandler,
PushNotificationsFcmProblemReportHandler,
PushNotificationsFcmSetDeviceInfoHandler,
} from './handlers'

@injectable()
export class PushNotificationsFcmApi {
private messageSender: MessageSender
private pushNotificationsService: PushNotificationsFcmService
private connectionService: ConnectionService
private agentContext: AgentContext

public constructor(
messageSender: MessageSender,
pushNotificationsService: PushNotificationsFcmService,
connectionService: ConnectionService,
agentContext: AgentContext
) {
this.messageSender = messageSender
this.pushNotificationsService = pushNotificationsService
this.connectionService = connectionService
this.agentContext = agentContext

this.agentContext.dependencyManager.registerMessageHandlers([
new PushNotificationsFcmSetDeviceInfoHandler(this.pushNotificationsService),
new PushNotificationsFcmDeviceInfoHandler(),
new PushNotificationsFcmProblemReportHandler(this.pushNotificationsService),
])
}

/**
* Sends the requested fcm device info (token) to another agent via a `connectionId`
* Response for `push-notifications-fcm/get-device-info`
*
* @param connectionId The connection ID string
* @param threadId get-device-info message ID
* @param deviceInfo The FCM device info
* @returns Promise<void>
*/
public async deviceInfo(options: { connectionId: string; threadId: string; deviceInfo: FcmDeviceInfo }) {
const { connectionId, threadId, deviceInfo } = options
const connection = await this.connectionService.getById(this.agentContext, connectionId)
connection.assertReady()

const message = this.pushNotificationsService.createDeviceInfo({ threadId, deviceInfo })

const outbound = new OutboundMessageContext(message, {
agentContext: this.agentContext,
connection: connection,
})
await this.messageSender.sendMessage(outbound)
}
}
Loading

0 comments on commit ad37209

Please sign in to comment.