mirror of
https://github.com/aljazceru/dvmcp.git
synced 2025-12-17 13:24:24 +01:00
refactor: config error handle, dvm-bridge improvements
This commit is contained in:
@@ -1,21 +1,71 @@
|
|||||||
import { config } from 'dotenv';
|
import { config } from 'dotenv';
|
||||||
config();
|
import { join } from 'path';
|
||||||
|
import { existsSync } from 'fs';
|
||||||
|
|
||||||
|
const envPath = join(process.cwd(), '.env');
|
||||||
|
if (!existsSync(envPath)) {
|
||||||
|
throw new Error(
|
||||||
|
'No .env file found. Please create one based on .env.example'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = config();
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
throw new Error(`Error loading .env file: ${result.error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const HEX_KEYS_REGEX = /^(?:[0-9a-fA-F]{64})$/;
|
||||||
|
|
||||||
|
function requireEnvVar(name: string): string {
|
||||||
|
const value = process.env[name];
|
||||||
|
if (!value) {
|
||||||
|
throw new Error(
|
||||||
|
`Missing required environment variable: ${name}. Check your .env file`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEnvVar(name: string, defaultValue: string): string {
|
||||||
|
return process.env[name] || defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
export const CONFIG = {
|
export const CONFIG = {
|
||||||
nostr: {
|
nostr: {
|
||||||
privateKey: process.env.PRIVATE_KEY!,
|
privateKey: requireEnvVar('PRIVATE_KEY'),
|
||||||
relayUrls: process.env.RELAY_URLS!.split(',').map((url) => url.trim()),
|
relayUrls: requireEnvVar('RELAY_URLS')
|
||||||
|
.split(',')
|
||||||
|
.map((url) => url.trim()),
|
||||||
},
|
},
|
||||||
mcp: {
|
mcp: {
|
||||||
// Service info
|
name: getEnvVar('MCP_SERVICE_NAME', 'DVM MCP Bridge'),
|
||||||
name: process.env.MCP_SERVICE_NAME || 'DVM MCP Bridge',
|
about: getEnvVar(
|
||||||
about:
|
'MCP_SERVICE_ABOUT',
|
||||||
process.env.MCP_SERVICE_ABOUT ||
|
'MCP-enabled DVM providing AI and computational tools'
|
||||||
'MCP-enabled DVM providing AI and computational tools',
|
),
|
||||||
// Client connection info
|
clientName: requireEnvVar('MCP_CLIENT_NAME'),
|
||||||
clientName: process.env.MCP_CLIENT_NAME!,
|
clientVersion: requireEnvVar('MCP_CLIENT_VERSION'),
|
||||||
clientVersion: process.env.MCP_CLIENT_VERSION!,
|
serverCommand: requireEnvVar('MCP_SERVER_COMMAND'),
|
||||||
serverCommand: process.env.MCP_SERVER_COMMAND!,
|
serverArgs: requireEnvVar('MCP_SERVER_ARGS').split(','),
|
||||||
serverArgs: process.env.MCP_SERVER_ARGS!.split(','),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!HEX_KEYS_REGEX.test(CONFIG.nostr.privateKey)) {
|
||||||
|
throw new Error('PRIVATE_KEY must be a 32-byte hex string');
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG.nostr.relayUrls.forEach((url) => {
|
||||||
|
try {
|
||||||
|
new URL(url);
|
||||||
|
if (!url.startsWith('ws://') && !url.startsWith('wss://')) {
|
||||||
|
throw new Error(`Relay URL must start with ws:// or wss://: ${url}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Invalid relay URL: ${url}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (CONFIG.nostr.relayUrls.length === 0) {
|
||||||
|
throw new Error('At least one relay URL must be provided in RELAY_URLS');
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,22 +9,58 @@ export class DVMBridge {
|
|||||||
private mcpClient: MCPClientHandler;
|
private mcpClient: MCPClientHandler;
|
||||||
private nostrAnnouncer: NostrAnnouncer;
|
private nostrAnnouncer: NostrAnnouncer;
|
||||||
private relayHandler: RelayHandler;
|
private relayHandler: RelayHandler;
|
||||||
|
private isRunning: boolean = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
console.log('Initializing DVM Bridge...');
|
||||||
this.mcpClient = new MCPClientHandler();
|
this.mcpClient = new MCPClientHandler();
|
||||||
this.nostrAnnouncer = new NostrAnnouncer();
|
this.nostrAnnouncer = new NostrAnnouncer();
|
||||||
this.relayHandler = new RelayHandler(CONFIG.nostr.relayUrls);
|
this.relayHandler = new RelayHandler(CONFIG.nostr.relayUrls);
|
||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
await this.mcpClient.connect();
|
if (this.isRunning) {
|
||||||
|
console.log('Bridge is already running');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const tools = await this.mcpClient.listTools();
|
console.log('Starting DVM Bridge...');
|
||||||
console.log('Available MCP tools:', tools);
|
try {
|
||||||
|
console.log('Connecting to MCP server...');
|
||||||
|
await this.mcpClient.connect();
|
||||||
|
|
||||||
await this.nostrAnnouncer.announceService();
|
const tools = await this.mcpClient.listTools();
|
||||||
|
console.log('Available MCP tools:', tools);
|
||||||
|
|
||||||
this.relayHandler.subscribeToRequests(this.handleRequest.bind(this));
|
console.log('Announcing service to Nostr network...');
|
||||||
|
await this.nostrAnnouncer.announceService();
|
||||||
|
|
||||||
|
console.log('Setting up request handlers...');
|
||||||
|
this.relayHandler.subscribeToRequests(this.handleRequest.bind(this));
|
||||||
|
|
||||||
|
this.isRunning = true;
|
||||||
|
console.log('DVM Bridge is now running and ready to handle requests');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to start DVM Bridge:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async stop() {
|
||||||
|
if (!this.isRunning) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Stopping DVM Bridge...');
|
||||||
|
try {
|
||||||
|
await this.mcpClient.disconnect();
|
||||||
|
this.relayHandler.cleanup();
|
||||||
|
this.isRunning = false;
|
||||||
|
console.log('DVM Bridge stopped successfully');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error stopping DVM Bridge:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleRequest(event: Event) {
|
private async handleRequest(event: Event) {
|
||||||
@@ -100,9 +136,32 @@ export class DVMBridge {
|
|||||||
console.error('Error handling request:', error);
|
console.error('Error handling request:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async stop() {
|
if (import.meta.main) {
|
||||||
await this.mcpClient.disconnect();
|
console.log('Starting DVM-MCP Bridge service...');
|
||||||
this.relayHandler.cleanup();
|
const bridge = new DVMBridge();
|
||||||
|
|
||||||
|
const shutdown = async () => {
|
||||||
|
console.log('Shutting down...');
|
||||||
|
try {
|
||||||
|
await bridge.stop();
|
||||||
|
process.exit(0);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during shutdown:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle termination signals
|
||||||
|
process.on('SIGINT', shutdown);
|
||||||
|
process.on('SIGTERM', shutdown);
|
||||||
|
|
||||||
|
// Start the bridge
|
||||||
|
try {
|
||||||
|
await bridge.start();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to start service:', error);
|
||||||
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user