Files
ringnet/oracle.js
ale d59980046b dashboard
Signed-off-by: ale <ale@manalejandro.com>
2025-06-17 00:29:01 +02:00

310 líneas
11 KiB
JavaScript

#!/usr/bin/env node
import { OracleNode } from './src/oracle-node.js';
import chalk from 'chalk';
import { readFileSync } from 'fs';
const args = process.argv.slice(2);
const options = {};
// Parse command line arguments
for (let i = 0; i < args.length; i++) {
switch (args[i]) {
case '--port':
options.port = parseInt(args[++i]);
break;
case '--id':
options.id = args[++i];
break;
case '--bootstrap':
options.bootstrap = args[++i];
break;
case '--dashboard':
options.dashboardUrl = args[++i];
break;
case '--ice-servers':
try {
options.iceServers = JSON.parse(args[++i]);
} catch (error) {
console.error(chalk.red('Error parsing ICE servers JSON:'), error.message);
process.exit(1);
}
break;
case '--config':
try {
const configPath = args[++i];
const configData = JSON.parse(readFileSync(configPath, 'utf8'));
if (configData.iceServers) {
options.iceServers = configData.iceServers;
}
} catch (error) {
console.error(chalk.red('Error loading config file:'), error.message);
process.exit(1);
}
break;
case '--help':
console.log(`
${chalk.yellow('Ring Network Oracle Node')}
Usage: node oracle.js [options]
Options:
--port <port> Port to listen on (default: random)
--id <id> Node ID (default: auto-generated)
--bootstrap <addr> Bootstrap node address (host:port)
--dashboard <url> Dashboard server URL (default: http://localhost:3000)
--ice-servers <json> ICE servers configuration (JSON array)
--config <file> Load configuration from JSON file
--help Show this help message
Examples:
node oracle.js --port 8080
node oracle.js --port 8081 --bootstrap localhost:8080
node oracle.js --id oracle1 --port 8082 --bootstrap localhost:8080
node oracle.js --config config/ice-servers-with-turn.json --port 8080
Note: Ring positions are now assigned automatically for optimal network topology.
ICE Servers Example:
--ice-servers '[{"urls":"stun:stun.l.google.com:19302"},{"urls":"turn:turn.example.com:3478","username":"user","credential":"pass"}]'
Config File Example:
config/ice-servers-default.json - Default STUN servers
config/ice-servers-with-turn.json - With TURN server
config/ice-servers-public-turn.json - Public TURN servers
Oracle Services:
- network-analysis: Analyze network topology and health
- data-storage: Distributed data storage with replication
- consensus: Consensus mechanisms for network decisions
- routing: Advanced routing strategies
- health-check: Network health monitoring
- network-metrics: Collect and provide network metrics
`);
process.exit(0);
break;
}
}
const oracle = new OracleNode(options);
// Handle graceful shutdown
process.on('SIGINT', async () => {
console.log(chalk.yellow('\n🛑 Received shutdown signal...'));
await oracle.destroy();
process.exit(0);
});
process.on('SIGTERM', async () => {
console.log(chalk.yellow('\n🛑 Received termination signal...'));
await oracle.destroy();
process.exit(0);
});
// Connect to bootstrap node if specified
if (options.bootstrap) {
setTimeout(async () => {
try {
await oracle.joinRing(options.bootstrap);
} catch (error) {
// Connection failed
}
}, 2000);
}
// Set up event handlers
oracle.on('peerConnected', (peerId) => {
// Peer connected
});
oracle.on('peerDisconnected', (peerId) => {
// Peer disconnected
});
oracle.on('ringMessage', ({ from, payload }) => {
// Ring message received
});
oracle.on('oracleResponse', ({ from, payload }) => {
// Oracle response received
});
// Interactive commands
process.stdin.setEncoding('utf8');
process.stdin.on('readable', () => {
const chunk = process.stdin.read();
if (chunk !== null) {
const command = chunk.trim();
handleCommand(command);
}
});
async function handleCommand(command) {
const [cmd, ...args] = command.split(' ');
switch (cmd) {
case 'send':
if (args.length > 0) {
const message = args.join(' ');
oracle.sendRingMessage({ type: 'chat', content: message });
console.log(chalk.green(`📤 Sent: ${message}`));
}
break;
case 'info':
const info = oracle.getOracleInfo();
console.log(chalk.yellow('\n🔮 Oracle Info:'));
console.log(JSON.stringify(info, null, 2));
break;
case 'peers':
const peers = oracle.webrtc.getConnectedPeers();
console.log(chalk.blue(`\n👥 Connected Peers (${peers.length}):`));
peers.forEach(peer => {
console.log(` - ${peer.substring(0, 8)}...`);
});
break;
case 'health':
const health = oracle.performHealthCheck();
console.log(chalk.green('\n🏥 Health Check:'));
console.log(JSON.stringify(health, null, 2));
break;
case 'metrics':
const metrics = oracle.getNetworkMetrics();
console.log(chalk.cyan('\n📊 Network Metrics:'));
console.log(JSON.stringify(metrics, null, 2));
break;
case 'analyze':
const analysis = oracle.analyzeNetwork();
console.log(chalk.magenta('\n🔍 Network Analysis:'));
console.log(JSON.stringify(analysis, null, 2));
break;
case 'store':
if (args.length >= 2) {
const [key, ...valueParts] = args;
const value = valueParts.join(' ');
const result = oracle.handleDataStorage({
operation: 'set',
key,
value
});
console.log(chalk.green(`💾 Stored: ${key} = ${value}`));
console.log(JSON.stringify(result, null, 2));
} else {
console.log(chalk.red('Usage: store <key> <value>'));
}
break;
case 'get':
if (args.length >= 1) {
const key = args[0];
const result = oracle.handleDataStorage({
operation: 'get',
key
});
console.log(chalk.blue(`📥 Retrieved: ${key}`));
console.log(JSON.stringify(result, null, 2));
} else {
console.log(chalk.red('Usage: get <key>'));
}
break;
case 'propose':
if (args.length >= 1) {
const proposal = args.join(' ');
const proposalId = `proposal-${Date.now()}`;
const result = oracle.handleConsensus({
proposalId,
proposal
});
console.log(chalk.yellow(`📋 Created proposal: ${proposalId}`));
console.log(JSON.stringify(result, null, 2));
} else {
console.log(chalk.red('Usage: propose <proposal text>'));
}
break;
case 'vote':
if (args.length >= 2) {
const [proposalId, vote] = args;
const result = oracle.handleConsensus({
proposalId,
vote
});
console.log(chalk.yellow(`🗳️ Voted ${vote} on ${proposalId}`));
console.log(JSON.stringify(result, null, 2));
} else {
console.log(chalk.red('Usage: vote <proposalId> <yes|no>'));
}
break;
case 'topology':
const topology = oracle.getRingTopology();
console.log(chalk.blue('\n🔄 Ring Topology:'));
console.log(` Ring Size: ${topology.ringSize}`);
console.log(` Total Nodes: ${topology.totalNodes}`);
console.log(` My Position: ${oracle.ringPosition}`);
if (topology.nodes.length > 0) {
console.log(chalk.yellow('\n📍 Node Positions:'));
topology.nodes.forEach(nodeInfo => {
const indicators = [];
if (nodeInfo.isThisNode) indicators.push(chalk.green('ME'));
if (nodeInfo.isOracle) indicators.push(chalk.yellow('🔮'));
if (nodeInfo.isConnected) indicators.push(chalk.green('✓'));
const indicatorStr = indicators.length > 0 ? ` [${indicators.join(' ')}]` : '';
console.log(` ${nodeInfo.position.toString().padStart(4)}: ${nodeInfo.nodeId}...${indicatorStr}`);
});
console.log(chalk.cyan('\n🔄 Ring Connections:'));
console.log(` Inner Ring: ${topology.innerRing.left}... ← ME → ${topology.innerRing.right}...`);
console.log(` Outer Ring: ${topology.outerRing.left}... ← ME → ${topology.outerRing.right}...`);
}
break;
case 'help':
console.log(chalk.yellow(`
🔮 Oracle Commands:
send <msg> - Send a message through the ring
info - Show oracle information
peers - List connected peers
health - Perform health check
metrics - Show network metrics
analyze - Analyze network topology
store <key> <value> - Store data in distributed storage
get <key> - Retrieve data from storage
propose <text> - Create a consensus proposal
vote <id> <yes|no> - Vote on a proposal
topology - Show ring topology and positions
help - Show this help
quit - Exit the oracle
`));
break;
case 'quit':
case 'exit':
console.log(chalk.yellow('👋 Oracle shutting down...'));
process.exit(0);
break;
default:
if (command.length > 0) {
console.log(chalk.red(`❓ Unknown command: ${cmd}. Type 'help' for available commands.`));
}
}
}
console.log(chalk.yellow(`
🔮 Ring Network Oracle Node Started!
Oracle ID: ${oracle.id.substring(0, 8)}...
Port: ${oracle.port}
Services: ${Array.from(oracle.oracleServices.keys()).join(', ')}
Type 'help' for available commands.
`));