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: socketdock implementation #29

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ddbba3d
added coonect message disconnect endpoints
pallavighule Nov 25, 2024
e8fbc1e
feat:added socketdock routes and socketdock session
pallavighule Dec 3, 2024
cb2730c
fix:changes in dev.ts
pallavighule Dec 3, 2024
e63bf2b
fix:removed axios dependancy
pallavighule Dec 3, 2024
fd82c8a
fix:removed unused variables
pallavighule Dec 3, 2024
5e3ead1
chore:install dependancies
pallavighule Dec 3, 2024
537deaf
fix:format the file
pallavighule Dec 3, 2024
1a33da3
fix:deleted setting.json
pallavighule Dec 3, 2024
40cac71
fix:resolved comments
pallavighule Dec 4, 2024
fc3b2d8
fix:resolved comments
pallavighule Dec 4, 2024
85c8c6b
fix:resolved comments
pallavighule Dec 4, 2024
8b221d1
fix:resolved comments
pallavighule Dec 4, 2024
650b6e2
fix:add some checks
pallavighule Dec 4, 2024
d8eba9d
fix:add some checks
pallavighule Dec 4, 2024
063ac8e
fix:add event listeners
pallavighule Dec 5, 2024
becbc31
made skipLibCheck true
pallavighule Dec 5, 2024
64ab6a6
removed transport session if socket is disconnected
RinkalBhojani Dec 17, 2024
d7db235
resolved prettier issue
RinkalBhojani Dec 17, 2024
c28cf55
chore:changed debug message
pallavighule Dec 18, 2024
46bfeda
fix:resolved merged conflicts
pallavighule Jan 13, 2025
e1e4f45
fix: improve logic to treat USE_SOCKETDOCK as a boolean
pallavighule Jan 13, 2025
6e68a9d
fix:add formating
pallavighule Jan 15, 2025
a587ef4
fix:changed request mime type from any to didcomm mime type
pallavighule Jan 15, 2025
6813a84
fix:added constant in config file
pallavighule Jan 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ POSTGRES_ADMIN_USER=
POSTGRES_ADMIN_PASSWORD=

USE_PUSH_NOTIFICATIONS='true'
NOTIFICATION_WEBHOOK_URL=
NOTIFICATION_WEBHOOK_URL=
USE_SOCKETDOCK='false'
3 changes: 0 additions & 3 deletions .vscode/settings.json

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@
"@credo-ts/core": "patches/@credo-ts__core.patch"
}
}
}
}
25 changes: 20 additions & 5 deletions src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,18 @@ import { ariesAskar } from '@hyperledger/aries-askar-nodejs'

import express from 'express'
import { Server } from 'ws'
import { SocketDockInboundTransport } from './transport/SocketDockInboundTransport'

import { AGENT_ENDPOINTS, AGENT_NAME, AGENT_PORT, LOG_LEVEL, POSTGRES_HOST, WALLET_KEY, WALLET_NAME } from './constants'
import {
AGENT_ENDPOINTS,
AGENT_NAME,
AGENT_PORT,
LOG_LEVEL,
POSTGRES_HOST,
USE_SOCKETDOCK,
WALLET_KEY,
WALLET_NAME,
} from './constants'
import { askarPostgresConfig } from './database'
import { Logger } from './logger'
import { PushNotificationsFcmModule } from './push-notifications/fcm'
Expand Down Expand Up @@ -90,14 +100,19 @@ export async function createAgent() {
// Create all transports
const httpInboundTransport = new HttpInboundTransport({ app, port: AGENT_PORT })
const httpOutboundTransport = new HttpOutboundTransport()
const wsInboundTransport = new WsInboundTransport({ server: socketServer })
const wsOutboundTransport = new WsOutboundTransport()

// Register all Transports
agent.registerInboundTransport(httpInboundTransport)
agent.registerOutboundTransport(httpOutboundTransport)
agent.registerInboundTransport(wsInboundTransport)
agent.registerOutboundTransport(wsOutboundTransport)

if (USE_SOCKETDOCK === 'false') {
pallavighule marked this conversation as resolved.
Show resolved Hide resolved
const wsInboundTransport = new WsInboundTransport({ server: socketServer })
const wsOutboundTransport = new WsOutboundTransport()
agent.registerInboundTransport(wsInboundTransport)
agent.registerOutboundTransport(wsOutboundTransport)
} else {
agent.registerInboundTransport(new SocketDockInboundTransport({ app }))
}

// Added health check endpoint
httpInboundTransport.app.get('/health', async (_req, res) => {
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export const POSTGRES_ADMIN_PASSWORD = process.env.POSTGRES_ADMIN_PASSWORD

export const INVITATION_URL = process.env.INVITATION_URL

export const USE_SOCKETDOCK = process.env.USE_SOCKETDOCK || 'false'
pallavighule marked this conversation as resolved.
Show resolved Hide resolved

export const LOG_LEVEL = LogLevel.debug

export const IS_DEV = process.env.NODE_ENV === 'development'
Expand Down
91 changes: 91 additions & 0 deletions src/transport/SocketDockInboundTransport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import type { Express } from 'express'
import { Agent, AgentEventTypes, AgentMessageReceivedEvent, InboundTransport, TransportService } from '@credo-ts/core'
import { SocketDockTransportSession } from './SocketDockTransportSession'
import express from 'express'

export class SocketDockInboundTransport implements InboundTransport {
private app: Express
private activeConnections: Record<string, string> = {}

public constructor({ app }: { app: Express }) {
this.app = app

this.app.use(express.json())
}

public async start(agent: Agent) {
this.app.post('/connect', async (req, res) => {
pallavighule marked this conversation as resolved.
Show resolved Hide resolved
agent.config.logger.info('SocketDockInboundTransport.connect')
const { connection_id: connectionId } = req.body.meta
if (!connectionId) {
throw new Error('ConnectionId is not sent from socketDock server')
}

const socketId = this.activeConnections[connectionId]
if (!socketId) {
this.activeConnections[connectionId] = connectionId
agent.config.logger.debug(`Saving new socketId : ${connectionId}`)
}

try {
res.status(200).send(`connection with socketId : ${connectionId} added successfully`)
} catch (error) {
res.status(500).send('Error sending response to send URL')
}
})

this.app.post('/message', async (req, res) => {
agent.config.logger.info('SocketDockInboundTransport.message')

const { connection_id: connectionId } = req.body.meta
if (!connectionId) {
throw new Error('ConnectionId is not sent from socketDock server')
}

try {
const socketId = this.activeConnections[connectionId]
agent.config.logger.debug(`activeConnections transport session : ${socketId} ${connectionId}`)
const sendUrl = req.body.meta.send
const requestMimeType = req.headers['content-type'] as string
const session = new SocketDockTransportSession(socketId, res, sendUrl, requestMimeType)
const message = req.body.message
const encryptedMessage = JSON.parse(message)

agent.config.logger.debug(`Session value for transport session : ${session.id}`)

agent.events.emit<AgentMessageReceivedEvent>(agent.context, {
type: AgentEventTypes.AgentMessageReceived,
payload: {
message: encryptedMessage,
session: session,
},
})
} catch (error) {
if (!res.headersSent) {
res.status(500).send('Error processing message')
}
}
})

this.app.post('/disconnect', async (req, res) => {
agent.config.logger.info('SocketDockInboundTransport.disconnect')
const transportService = agent.dependencyManager.resolve(TransportService)
const { connection_id } = req.body
if (!connection_id) {
throw new Error('ConnectionId is not sent from socketDock server')
}

delete this.activeConnections[connection_id]
const session = transportService.findSessionById(connection_id)
agent.config.logger.debug(`Got session from transportService ${session?.id}`)
if (session) {
transportService.removeSession(session)
}

agent.config.logger.debug(`removed mapping of socketId : ${connection_id}`)
res.status(200).send(`Mapping with socketId : ${connection_id} removed successfully`)
})
}

public async stop(): Promise<void> {}
}
50 changes: 50 additions & 0 deletions src/transport/SocketDockTransportSession.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { AgentContext, DidCommMimeType, EncryptedMessage, TransportSession } from '@credo-ts/core'
import type { Response } from 'express'
import { CredoError } from '@credo-ts/core'

import { agentDependencies } from '@credo-ts/node'

export const supportedContentTypes: string[] = [DidCommMimeType.V0, DidCommMimeType.V1]

export class SocketDockTransportSession implements TransportSession {
public id: string
public readonly type = 'socketdock'
public res: Response
public sendUrl: string
public requestMimeType: any

public constructor(id: string, res: Response, sendUrl: string, requestMimeType: string) {
this.id = id
this.res = res
this.sendUrl = sendUrl
this.requestMimeType = requestMimeType
}

public async close() {
if (!this.res.headersSent) {
this.res.status(200).end()
}
}

public async send(agentContext: AgentContext, encryptedMessage: EncryptedMessage): Promise<void> {
if (this.res.headersSent) {
throw new CredoError(`${this.type} transport session has been closed.`)
}

// By default we take the agent config's default DIDComm content-type
let responseMimeType = agentContext.config.didCommMimeType

if (this.requestMimeType && supportedContentTypes.includes(this.requestMimeType)) {
responseMimeType = this.requestMimeType
}

const requestOptions = {
method: 'POST',
headers: {
'Content-Type': responseMimeType,
},
body: JSON.stringify(encryptedMessage),
}
await agentDependencies.fetch(this.sendUrl, requestOptions)
}
}