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

Enhancement/event based form integration #251

Merged
merged 45 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
f1cbf1a
feat: add voting options in event based vote function
JosephRana11 Nov 20, 2024
88639a0
chore: add event type options to voting cron params meta
JosephRana11 Nov 20, 2024
dee4c69
chore: update form validation function
JosephRana11 Nov 20, 2024
22ff4c8
chore: remove log function
JosephRana11 Nov 20, 2024
4e677a5
Merge remote-tracking branch 'origin/dev' into enhancment/event-votin…
JosephRana11 Nov 21, 2024
09dd9dc
Add vote options in agent-node
Sital999 Nov 21, 2024
2394685
fix: Support voting option for all trigger types
Sital999 Nov 28, 2024
79e01dc
Add EventTriggerHandler class
Sital999 Nov 6, 2024
22535ab
Add util fn for bech32 conversion
Sital999 Nov 6, 2024
0873f3f
Add util fn for eventHandler
Sital999 Nov 6, 2024
19b154d
Support advance event trigger filter
mesudip Nov 19, 2024
c3738c4
Update operation for buffer type to support any type
Sital999 Dec 6, 2024
f1a136c
chore : add event trigger interface
JosephRana11 Nov 18, 2024
ebbce27
feat: add event trigger tab
JosephRana11 Nov 18, 2024
3f4a15f
chore: reorganize function form components
JosephRana11 Nov 18, 2024
3913aee
chore: fix build issues / lint
JosephRana11 Nov 18, 2024
1e2ac33
chore: handle event trigger post req
JosephRana11 Nov 19, 2024
67a4966
chore: persist event trigger config between trigger toggle
JosephRana11 Nov 19, 2024
b22b19c
feat: add event trigger edit function
JosephRana11 Nov 19, 2024
dd4adf1
chore: handle event trigger post req
JosephRana11 Nov 19, 2024
e599e6f
feat: handle event trigger edit for agent function content
JosephRana11 Nov 19, 2024
834c977
feat: add custom editor
JosephRana11 Nov 19, 2024
30a63c6
feat: add new event trigger model
JosephRana11 Nov 12, 2024
ff6b504
Make eventTriggerDto optional
Sital999 Dec 16, 2024
5c57ec2
Enhancement: Add support for output property as event filter
Sital999 Dec 18, 2024
25fa716
enhancement: Add support for libcardano txSchema for filterType
Sital999 Dec 23, 2024
d837a50
enhancement: Add customCombox for search field
Sital999 Dec 25, 2024
751b043
Enhancement: Add Switch btn for different UI to display event-filter
Dec 25, 2024
4806764
fix: Add support for deleting eventFilter
Dec 25, 2024
ec2f921
enhacement: Add support for contains operator
Dec 27, 2024
d981cc0
enhacement: Refactor EventTab component
Dec 27, 2024
ce95299
enhacement:Add event context for each event-based fn invocation
Dec 30, 2024
86a47ee
fix: Add proper err Msg and add debounce in input field
Dec 30, 2024
5745a4f
enhancement: Add support for 'exists' operator
Sital999 Dec 30, 2024
0222fd8
feat: Add support for auto fill of params for event-filter
Sital999 Dec 31, 2024
cc44d92
feat: Add kafka health check in manager
Sital999 Jan 2, 2025
34cdd46
feat: Add health endpoint for different services
Sital999 Jan 2, 2025
c5ae5a3
fix: Update prettier.json and fix PR changes
Sital999 Jan 3, 2025
a3725a0
fix: Add support for `Address` and `Value`
Sital999 Jan 3, 2025
ebe865c
fix: Resolve merge conflict
Sital999 Jan 3, 2025
04945b9
fix: Add index of filtered proposals for voting
Sital999 Jan 3, 2025
df61228
fix: Update libcardano library
Sital999 Jan 3, 2025
d651a8c
fix: Add voting options
Sital999 Jan 6, 2025
c54c14c
fix: Support voting options for event type
Sital999 Jan 6, 2025
0fde493
fix: Add latest libcardano version in node to support filter type
Sital999 Jan 6, 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
2 changes: 1 addition & 1 deletion agent-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"express": "^4.19.2",
"kafkajs": "^2.2.4",
"kuber-client": "^3.0.3",
"libcardano": "1.4.3",
"libcardano": "1.4.11",
"luxon": "^3.4.4",
"prisma": "^5.13.0",
"swagger-jsdoc": "^6.2.8",
Expand Down
16 changes: 16 additions & 0 deletions agent-manager/src/controller/health.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Router, Request, Response } from 'express'
import { handlerWrapper } from '../utils/asyncWrapper'
import { checkKafkaStatus } from '../service/healthCheck/kafka'

const router = Router()

function healthCheck(req: Request, res: Response) {
checkKafkaStatus()
.then((a) => console.log('Success : ', a))
.catch((err) => console.log('Error: ', err))
return res.status(200).send({ Msg: 'OK ' })
}

router.get('/', handlerWrapper(healthCheck))

export default router
6 changes: 5 additions & 1 deletion agent-manager/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import { createBlockchainInstance } from './service/Listeners/BlockchainService'
import { ManagerWalletService } from './service/Manager/ManagerWallet'
import { TxListener } from './service/Listeners/TxListener'
import { parseRawBlockBody } from 'libcardano/cardano/ledger-serialization/transaction'
import environments from "./config/environments";
import environments from './config/environments'
import healthCheck from './controller/health'

const app = express()
const port = environments.serverPort

app.use('/health', healthCheck)

const server = app.listen(port, async () => {
console.log(`Server is running on http://localhost:${port}`)

Expand All @@ -35,6 +38,7 @@ const server = app.listen(port, async () => {
})
await initKafkaConsumers(manager)
})

server.on('error', (e) => {
console.error('Server error:', e)
process.exit(1)
Expand Down
4 changes: 2 additions & 2 deletions agent-manager/src/service/Listeners/KafkaMessageConsumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import environments from '../../config/environments'
const config = environments.kafka
const configTopic = `${config.topicPrefix || config.prefix || 'agent'}-updates`
const triggerTopic = `${config.topicPrefix || config.prefix || 'agent'}-triggers`
const topicList = [configTopic, triggerTopic]
export const topicList = [configTopic, triggerTopic]
const brokers = config.brokers
.split(',')
.map((x) => x.trim())
.filter((x) => x && x.length > 0)
const groupId = config.consumerGroup || `${config.prefix || 'agent'}-manager`

const kafka = new Kafka({
export const kafka = new Kafka({
clientId: config.clientId ? config.clientId : `${config.prefix || 'agent'}-manager`,
brokers, // Update with your Kafka broker address
})
Expand Down
34 changes: 34 additions & 0 deletions agent-manager/src/service/healthCheck/kafka.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { kafka, topicList } from '../Listeners/KafkaMessageConsumer'

export async function checkKafkaStatus() {
const admin = kafka.admin()
try {
// Connect to Kafka
await admin.connect()

// Fetch metadata
const metadata = await admin.fetchTopicMetadata({ topics: [] })
console.log('Metadata:', metadata)

const clusterInfo = await admin.describeCluster()
console.log('ClusterInfo : ', clusterInfo)

// Optionally check for specific topics
const missingTopics = topicList.filter((topic) => !metadata.topics.find((t: any) => t.name === topic))

if (missingTopics.length > 0) {
console.error('Missing topics:', missingTopics)
return { status: 'error', message: `Missing topics: ${missingTopics.join(', ')}` }
}

return { status: 'ok', message: 'Kafka is in sync and working.' }
} catch (error: any) {
console.error('Error connecting to Kafka:', error)
return { status: 'error', message: `Error: ${error.message}` }
} finally {
await admin.disconnect()
}
}

// Example usage
checkKafkaStatus().then((status) => console.log('Kafka Status:', status))
15 changes: 15 additions & 0 deletions agent-manager/src/utils/asyncWrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {NextFunction, Request, Response} from "express";

export const handlerWrapper = (fn: any) => (req: Request, res: Response, next: NextFunction) => {
try {
const result = fn(req, res, next)
if (result instanceof Promise) {
result.catch((e) => {
next(e)
})
}
} catch (error) {
// Handle sync errors
next(error)
}
}
8 changes: 4 additions & 4 deletions agent-manager/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2684,10 +2684,10 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"

[email protected].3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/libcardano/-/libcardano-1.4.3.tgz#a3dc20452e1520b65fa32621337de62413a3cd5c"
integrity sha512-5R5aE+WHwC1wxFLH4fVjXeQh0WbOLCBZKcFmbVYvGwWy2TMaqspncy8QMclqD03x8GtdK7yWEFTp9buGP9/eTw==
[email protected].11:
version "1.4.11"
resolved "https://registry.yarnpkg.com/libcardano/-/libcardano-1.4.11.tgz#ffe0f1f63a4a9bb940e87a5b5b68284cbbbaa1a7"
integrity sha512-rl/okJH27NBGwOx7VTgBkOJe4q6vBbBE4FbPrXXDhgLgI55004K0ODK0R4+3HCHAL8TtnXPqPRJXE5vvO++lIQ==
dependencies:
"@cardano-sdk/crypto" "^0.1.30"
"@emurgo/cardano-serialization-lib-nodejs" "^11.5.0"
Expand Down
2 changes: 1 addition & 1 deletion agent-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"bech32": "^2.0.0",
"dotenv": "^16.4.5",
"kuber-client": "^2.0.0",
"libcardano": "1.4.2",
"libcardano": "1.4.11",
"luxon": "^3.4.4",
"node-cron": "^3.0.3",
"ws": "^8.18.0"
Expand Down
9 changes: 3 additions & 6 deletions agent-node/src/constants/global.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { EventTriggerTypeDetails } from '../types/types'
import { IEventBasedAction } from '../types/eventTriger'

export const globalState: {
eventTriggerTypeDetails: EventTriggerTypeDetails
eventTypeDetails: IEventBasedAction[]
agentName: string
} = {
eventTriggerTypeDetails: {
eventType: false,
function_name: '',
},
eventTypeDetails: [],
agentName: '',
}

Expand Down
7 changes: 7 additions & 0 deletions agent-node/src/executor/AgentFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface FunctionHolder {
export interface FunctionGroup {
functions: FunctionHolder
builtins: FunctionHolder
filters: FunctionHolder
}
// Helper function to require modules with extensions automatically
function requireModule(filePath: string) {
Expand All @@ -27,6 +28,7 @@ function requireModule(filePath: string) {
function loadHandlersSync(directory: string): FunctionGroup {
const handlers: FunctionHolder = {}
const builtins: FunctionHolder = {}
const filters: FunctionHolder = {}

// Get the list of files in the directory
const files = fs.readdirSync(directory)
Expand All @@ -44,12 +46,16 @@ function loadHandlersSync(directory: string): FunctionGroup {
const module: any = requireModule(filePath)
// Check if the module exports a `handler` function
const handler = module.handler || module.default
const filter = module.filter
if (typeof handler === 'function') {
handlers[baseFileName] = handler
}
if (module.builtin || handler.name == 'builtin') {
builtins[baseFileName] = module.builtin || module.default
}
if (filter && typeof filter == "function"){
filters[baseFileName] = filter
}
} catch (error) {
console.error(
`Failed to load handler from file ${filePath}:`,
Expand All @@ -62,6 +68,7 @@ function loadHandlersSync(directory: string): FunctionGroup {
return {
functions: handlers,
builtins: builtins,
filters: filters
}
}

Expand Down
32 changes: 32 additions & 0 deletions agent-node/src/executor/AgentRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import { loadRootKeyFromBuffer } from '../utils/cardano'
import { HdWallet } from 'libcardano'
import { AgentWalletDetails } from '../types/types'
import { globalState } from '../constants/global'
import { EventContext } from './BaseFunction'

export class AgentRunner {
executor: Executor
managerInterface: ManagerInterface

constructor(managerInterface: ManagerInterface, txListener: TxListener) {
this.managerInterface = managerInterface
this.executor = new Executor(null, managerInterface, txListener)
Expand All @@ -27,6 +29,36 @@ export class AgentRunner {
})
}

async invokeFunctionWithEventContext(
eventFilterContext: any,
context: EventContext,
triggerType: TriggerType,
instanceIndex: number,
method: string,
...args: any[]
) {
const eventContext = {
event: context,
filter: eventFilterContext,
}
const params = await this.executor
.filterFunctionParams(method, eventContext)
.catch((err) => console.error('Function Invocation Error: ', err))

if (params) {
this.executor
.invokeFunctionWithContext(eventContext, method, ...params)
.then((result) => {
saveTxLog(
result,
this.managerInterface,
triggerType,
instanceIndex
)
})
}
}

async remakeContext(index: number) {
const rootKey = loadRootKeyFromBuffer()
const hdWallet = HdWallet.fromHdKey(rootKey)
Expand Down
13 changes: 12 additions & 1 deletion agent-node/src/executor/BaseFunction.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import {Transaction} from "libcardano/cardano/ledger-serialization/transaction";
import {DecodedBlock} from "./TxListener";

export interface Key {
private: string
public: string
Expand Down Expand Up @@ -75,12 +78,20 @@ export interface Helpers {
generateVoteMetadataContent: () => string
}

export interface EventContext{
tx: Transaction;
block: DecodedBlock;
confirmation: number
}

export interface FunctionContext {
wallet: Wallet
kuber: KuberApi
builtins: Builtins
agentName: string
helpers: Helpers
helpers: Helpers,
event ?: EventContext,
filter?: any
}

// Create a restricted execution environment
Expand Down
30 changes: 28 additions & 2 deletions agent-node/src/executor/Executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ export interface CallLog {
return?: any
error?: Error | string
}

export class Executor {
wallet: any
readonly rpcInterface: ManagerInterface
readonly functions: FunctionGroup
readonly functionContext: FunctionContext
txListener: TxListener

constructor(
wallet: any,
rpcInterface: ManagerInterface,
Expand Down Expand Up @@ -122,6 +124,7 @@ export class Executor {
processQueue(this.rpcInterface, this.txListener)
}
})

async function processQueue(
rpcInterface: ManagerInterface,
txListener: TxListener
Expand Down Expand Up @@ -285,7 +288,29 @@ export class Executor {
} as Builtins
}

invokeFunction(name: string, ...args: any): Promise<CallLog[]> {
async invokeFunction(name: string, ...args: any): Promise<CallLog[]> {
return await this.invokeFunctionWithContext({}, name, ...args)
}

filterFunctionParams(name: string, context: any): Promise<any> {
const f: any | undefined = this.functions.filters[name]
if (f === undefined) {
return Promise.reject(new Error('Filter not defined'))
}
const newContext = { ...this.functionContext, ...context }
try {
const result: any = f(newContext)
return Promise.resolve(result)
} catch (err) {
return Promise.reject(err)
}
}

invokeFunctionWithContext(
context: any,
name: string,
...args: any
): Promise<CallLog[]> {
const f: any | undefined = this.functions.functions[name]
const log: CallLog = {
function: name,
Expand All @@ -296,7 +321,7 @@ export class Executor {
return Promise.resolve([log])
}

const newContext = { ...this.functionContext }
const newContext = { ...this.functionContext, ...context }
const builtinsProxy = this.makeProxy(newContext.builtins)
newContext.builtins = builtinsProxy.proxy
builtinsProxy.callLog.push(log)
Expand Down Expand Up @@ -327,5 +352,6 @@ export class Executor {
}
return Promise.resolve(builtinsProxy.callLog)
}

// newBlock(block) {}
}
2 changes: 2 additions & 0 deletions agent-node/src/functions/transferADA.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ export default async function handler(
throw err
})
}


18 changes: 18 additions & 0 deletions agent-node/src/functions/voteOnProposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default async function handler(
anchor: anchorData,
},
}

return await context.wallet
.buildAndSubmit(req, true)
.then((v) => v)
Expand All @@ -38,3 +39,20 @@ export default async function handler(
}
})
}

export function filter(context: FunctionContext) {
if (!context.filter || !context.event) return null
const tx = context.event.tx
try {
const filters = context.filter['proposalProcedures']
const matchedFilterIndexes = filters.map((i: any) => !!i.matchedIndex)
return matchedFilterIndexes.length
? matchedFilterIndexes.map((p: any, index: number) => ({
name: 'proposalId',
value: `${tx.hash.toString('hex')}#${index}`,
}))
: null
} catch (err) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log error with warning so that it can be debugged later.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log added

return null
}
}
Loading