deleted logs and WebRTC issue

Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2025-06-15 14:04:28 +02:00
padre 7c3921cdd3
commit e238b4b307
Se han modificado 7 ficheros con 335 adiciones y 114 borrados

Ver fichero

@@ -136,6 +136,7 @@ Once a node is running, you can use these commands:
- `send <message>` - Send a message through the ring
- `info` - Show network information
- `peers` - List connected peers
- `connections` - Show persistent connection status
- `help` - Show available commands
- `quit` - Exit the node
@@ -319,3 +320,35 @@ MIT License - see LICENSE file for details.
- [Distributed Systems](https://en.wikipedia.org/wiki/Distributed_computing)
- [WebRTC Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API)
- [Consensus Algorithms](https://en.wikipedia.org/wiki/Consensus_(computer_science))
### Connection Persistence
The Ring Network now includes connection persistence features:
#### Persistent Connection Management
- **Automatic Connection Maintenance**: Nodes automatically maintain persistent WebRTC connections with other nodes
- **Heartbeat System**: Regular heartbeat messages keep connections alive and detect failures
- **Connection Monitoring**: Built-in monitoring of connection health and status
- **Automatic Reconnection**: Failed connections are automatically retried with exponential backoff
#### Connection Status
Use the `connections` command to view:
- Total active connections
- Persistent connection count
- Connection health status
- Last seen timestamps for each peer
- Reconnection attempt counts
#### Bootstrap Connections
When joining via a bootstrap node:
- Initial WebSocket connection for joining the network
- Automatic establishment of persistent WebRTC connection
- Bootstrap node maintains connection with new nodes
- Connection health monitoring and automatic recovery
#### Features
-**Heartbeat Messages**: 30-second intervals to maintain connections
-**Connection Health Checks**: Monitor connection state every 30 seconds
-**Automatic Reconnection**: Up to 3 attempts before giving up
-**Connection Status Monitoring**: Real-time connection status display
-**Graceful Shutdown**: Proper cleanup of connections and intervals

Ver fichero

@@ -61,15 +61,15 @@ class NetworkExample {
const nodeColor = node.isOracle ? chalk.yellow : chalk.blue;
node.on('peerConnected', (peerId) => {
console.log(nodeColor(`${nodeType} ${index}: Connected to ${peerId.substring(0, 8)}`));
// Peer connected
});
node.on('peerDisconnected', (peerId) => {
console.log(nodeColor(`${nodeType} ${index}: Disconnected from ${peerId.substring(0, 8)}`));
// Peer disconnected
});
node.on('ringMessage', ({ from, payload }) => {
console.log(nodeColor(`${nodeType} ${index}: Received message from ${from.substring(0, 8)}: ${JSON.stringify(payload)}`));
// Message received
});
});
}

46
node.js
Ver fichero

@@ -76,8 +76,6 @@ Config File Example:
}
}
console.log(chalk.green('🚀 Starting Ring Network Node...'));
const node = new RingNode(options);
// Handle graceful shutdown
@@ -95,37 +93,30 @@ process.on('SIGTERM', async () => {
// Connect to bootstrap node if specified
if (options.bootstrap) {
console.log(chalk.cyan(`🔗 Connecting to bootstrap node: ${options.bootstrap}`));
setTimeout(async () => {
try {
const success = await node.joinRing(options.bootstrap);
if (success) {
console.log(chalk.green('✅ Successfully joined the ring network!'));
} else {
console.log(chalk.red('❌ Failed to join the ring network'));
}
await node.joinRing(options.bootstrap);
} catch (error) {
console.error(chalk.red('Error joining network:'), error.message);
// Connection failed
}
}, 2000);
}
// Set up event handlers for demonstration
// Set up event handlers
node.on('peerConnected', (peerId) => {
console.log(chalk.blue(`👋 New peer connected: ${peerId.substring(0, 8)}`));
// Peer connected
});
node.on('peerDisconnected', (peerId) => {
console.log(chalk.red(`👋 Peer disconnected: ${peerId.substring(0, 8)}`));
// Peer disconnected
});
node.on('ringMessage', ({ from, payload }) => {
console.log(chalk.magenta(`📨 Ring message from ${from.substring(0, 8)}: ${JSON.stringify(payload)}`));
// Ring message received
});
node.on('networkUpdate', ({ from, payload }) => {
console.log(chalk.cyan(`🔄 Network update from ${from.substring(0, 8)}`));
// Network update received
});
// Interactive commands
@@ -146,7 +137,6 @@ function handleCommand(command) {
if (args.length > 0) {
const message = args.join(' ');
node.sendRingMessage({ type: 'chat', content: message });
console.log(chalk.green(`📤 Sent: ${message}`));
}
break;
@@ -164,12 +154,34 @@ function handleCommand(command) {
});
break;
case 'connections':
const status = node.getConnectionStatus();
const persistentConns = node.getPersistentConnections();
console.log(chalk.blue('\n🔗 Connection Status:'));
console.log(` Total Connections: ${status.totalConnections}`);
console.log(` Persistent Connections: ${status.persistentConnections}`);
console.log(` Active Connections: ${status.activeConnections}`);
console.log(` Known Nodes: ${status.knownNodes}`);
console.log(` Oracle Nodes: ${status.oracleNodes}`);
if (persistentConns.length > 0) {
console.log(chalk.blue('\n🔄 Persistent Connections:'));
persistentConns.forEach(conn => {
const timeSince = conn.lastSeen ? `${Math.floor((Date.now() - conn.lastSeen) / 1000)}s ago` : 'never';
const statusColor = conn.connectionState === 'connected' ? chalk.green : chalk.red;
console.log(` - ${conn.nodeId.substring(0, 8)}... [${statusColor(conn.connectionState)}] ${conn.isOracle ? '🔮' : '💾'} (${timeSince})`);
});
}
break;
case 'help':
console.log(chalk.blue(`
📚 Available Commands:
send <message> - Send a message through the ring
info - Show network information
peers - List connected peers
connections - Show persistent connection status
help - Show this help
quit - Exit the node
`));

Ver fichero

@@ -84,8 +84,6 @@ Oracle Services:
}
}
console.log(chalk.yellow('🚀 Starting Ring Network Oracle Node...'));
const oracle = new OracleNode(options);
// Handle graceful shutdown
@@ -103,37 +101,30 @@ process.on('SIGTERM', async () => {
// Connect to bootstrap node if specified
if (options.bootstrap) {
console.log(chalk.cyan(`🔗 Connecting to bootstrap node: ${options.bootstrap}`));
setTimeout(async () => {
try {
const success = await oracle.joinRing(options.bootstrap);
if (success) {
console.log(chalk.green('✅ Successfully joined the ring network as Oracle!'));
} else {
console.log(chalk.red('❌ Failed to join the ring network'));
}
await oracle.joinRing(options.bootstrap);
} catch (error) {
console.error(chalk.red('Error joining network:'), error.message);
// Connection failed
}
}, 2000);
}
// Set up event handlers
oracle.on('peerConnected', (peerId) => {
console.log(chalk.blue(`👋 New peer connected: ${peerId.substring(0, 8)}`));
// Peer connected
});
oracle.on('peerDisconnected', (peerId) => {
console.log(chalk.red(`👋 Peer disconnected: ${peerId.substring(0, 8)}`));
// Peer disconnected
});
oracle.on('ringMessage', ({ from, payload }) => {
console.log(chalk.magenta(`📨 Ring message from ${from.substring(0, 8)}: ${JSON.stringify(payload)}`));
// Ring message received
});
oracle.on('oracleResponse', ({ from, payload }) => {
console.log(chalk.cyan(`🔮 Oracle response from ${from.substring(0, 8)}: ${JSON.stringify(payload)}`));
// Oracle response received
});
// Interactive commands

Ver fichero

@@ -20,7 +20,6 @@ export class OracleNode extends RingNode {
};
this.initializeOracleServices();
console.log(chalk.yellow(`🔮✨ Oracle Node ${this.id.substring(0, 8)} initialized with enhanced capabilities`));
}
initializeOracleServices() {
@@ -57,8 +56,6 @@ export class OracleNode extends RingNode {
const { query, data, service } = payload;
this.networkMetrics.queriesAnswered++;
console.log(chalk.cyan(`🔮 Processing oracle query: ${service || query}`));
if (service && this.oracleServices.has(service)) {
return this.oracleServices.get(service)(data);
}
@@ -429,7 +426,6 @@ export class OracleNode extends RingNode {
});
if (!health.healthy) {
console.log(chalk.red(`⚠️ Network health issue detected`));
this.handleNetworkHealthIssue(health);
}
}
@@ -437,7 +433,6 @@ export class OracleNode extends RingNode {
handleNetworkHealthIssue(health) {
// Attempt to reconnect to peers
if (!health.checks.webrtc) {
console.log(chalk.yellow('🔄 Attempting to reconnect to network...'));
// Implement reconnection logic
}
@@ -485,7 +480,7 @@ export class OracleNode extends RingNode {
}
}
console.log(chalk.blue(`🧹 Cleaned up old data. DataStore: ${this.dataStore.size}, Consensus: ${this.consensusData.size}`));
// Cleaned up old data
}
// Handle additional message types specific to Oracle
@@ -518,10 +513,8 @@ export class OracleNode extends RingNode {
if (operation === 'set') {
this.dataStore.set(key, entry);
console.log(chalk.blue(`📥 Replicated data: ${key}`));
} else if (operation === 'delete') {
this.dataStore.delete(key);
console.log(chalk.blue(`🗑️ Deleted replicated data: ${key}`));
}
}
@@ -535,8 +528,6 @@ export class OracleNode extends RingNode {
status: 'active',
proposer: from
});
console.log(chalk.cyan(`📋 New consensus proposal ${proposalId} from ${from.substring(0, 8)}`));
}
handleConsensusVote(from, payload) {
@@ -546,13 +537,10 @@ export class OracleNode extends RingNode {
if (consensusItem) {
consensusItem.votes.set(voterId, vote);
const result = this.checkConsensus(proposalId);
console.log(chalk.cyan(`🗳️ Vote received for ${proposalId}: ${vote} (${result.status})`));
}
}
handleHealthAlert(from, payload) {
console.log(chalk.red(`🚨 Health alert from ${from.substring(0, 8)}`));
this.networkMetrics.networkEvents.push({
type: 'health-alert',
timestamp: Date.now(),
@@ -565,11 +553,7 @@ export class OracleNode extends RingNode {
const { destination, message } = payload;
// Attempt to route the message to the destination
if (this.webrtc.sendMessage(destination, message)) {
console.log(chalk.green(`📬 Routed message to ${destination.substring(0, 8)}`));
} else {
console.log(chalk.yellow(`📪 Unable to route message to ${destination.substring(0, 8)}`));
}
this.webrtc.sendMessage(destination, message);
}
getOracleInfo() {

Ver fichero

@@ -31,14 +31,14 @@ export class RingNode extends EventEmitter {
this.knownNodes = new Map();
this.messageHistory = new Set();
this.oracleNodes = new Set();
this.activeSignalingConnections = new Map(); // Store active WebSocket connections for signaling
this.setupWebRTCHandlers();
this.setupDiscoveryServer();
console.log(chalk.green(`🔗 Ring Node ${this.id.substring(0, 8)} initialized on port ${this.port}`));
if (this.isOracle) {
console.log(chalk.yellow(`🔮 Oracle mode enabled`));
}
// Start connection management
this.startConnectionManager();
this.startHeartbeat();
}
getRandomPort() {
@@ -47,12 +47,10 @@ export class RingNode extends EventEmitter {
setupWebRTCHandlers() {
this.webrtc.on('peerConnected', (peerId) => {
console.log(chalk.blue(`✅ Connected to peer: ${peerId.substring(0, 8)}`));
this.emit('peerConnected', peerId);
});
this.webrtc.on('peerDisconnected', (peerId) => {
console.log(chalk.red(`❌ Disconnected from peer: ${peerId.substring(0, 8)}`));
this.handlePeerDisconnection(peerId);
this.emit('peerDisconnected', peerId);
});
@@ -62,10 +60,22 @@ export class RingNode extends EventEmitter {
});
this.webrtc.on('signal', ({ peerId, signal }) => {
this.sendSignalingMessage(peerId, {
type: 'signal',
signal
});
// Try to send signal through stored WebSocket connection
const signalingWs = this.activeSignalingConnections.get(peerId);
if (signalingWs && signalingWs.readyState === signalingWs.OPEN) {
signalingWs.send(JSON.stringify({
type: 'signal',
from: this.id,
to: peerId,
payload: signal
}));
} else {
// Fallback to old method
this.sendSignalingMessage(peerId, {
type: 'signal',
signal
});
}
});
}
@@ -78,12 +88,21 @@ export class RingNode extends EventEmitter {
const message = JSON.parse(data.toString());
await this.handleSignalingMessage(ws, message);
} catch (error) {
console.error('Error handling signaling message:', error);
// Silently handle signaling errors
}
});
// Clean up signaling connections when WebSocket closes
ws.on('close', () => {
// Find and remove this WebSocket from active signaling connections
for (const [peerId, storedWs] of this.activeSignalingConnections.entries()) {
if (storedWs === ws) {
this.activeSignalingConnections.delete(peerId);
break;
}
}
});
});
console.log(chalk.cyan(`🌐 Discovery server listening on port ${this.port}`));
}
async handleSignalingMessage(ws, message) {
@@ -105,6 +124,34 @@ export class RingNode extends EventEmitter {
await this.webrtc.handleSignal(from, payload);
break;
case 'webrtc-connect':
// Handle WebRTC connection request
console.log(chalk.cyan(`<EFBFBD> Received WebRTC connection request from ${from.substring(0, 8)}`));
// Check if we already have a connection with this peer
const existingConnection = this.webrtc.connections.get(`${this.id}-${from}`);
if (existingConnection && existingConnection.peer && existingConnection.peer.connected) {
ws.send(JSON.stringify({
type: 'webrtc-connect-response',
success: false,
reason: 'Already connected'
}));
return;
}
// Store the WebSocket connection for signaling
this.activeSignalingConnections.set(from, ws);
// Accept the connection request
ws.send(JSON.stringify({
type: 'webrtc-connect-response',
success: true
}));
// Create connection as receiver (non-initiator)
const newConnection = await this.webrtc.createConnection(from, false);
break;
case 'discovery':
ws.send(JSON.stringify({
type: 'discovery-response',
@@ -124,21 +171,27 @@ export class RingNode extends EventEmitter {
async connectToPeer(nodeId, address) {
try {
const ws = new WebSocket(`ws://${address}`);
return new Promise((resolve, reject) => {
let connection = null;
let timeoutId;
let signalHandler, connectHandler;
ws.on('open', async () => {
// Send discovery message
// Send connection request
ws.send(JSON.stringify({
type: 'discovery',
from: this.id
type: 'webrtc-connect',
from: this.id,
to: nodeId
}));
// Create WebRTC connection as initiator
const connection = await this.webrtc.createConnection(nodeId, true);
connection = await this.webrtc.createConnection(nodeId, true);
// Listen for signaling data from our peer
const signalHandler = ({ peerId, signal }) => {
signalHandler = ({ peerId, signal }) => {
if (peerId === nodeId) {
ws.send(JSON.stringify({
type: 'signal',
@@ -152,11 +205,9 @@ export class RingNode extends EventEmitter {
this.webrtc.on('signal', signalHandler);
// Listen for connection success
const connectHandler = (peerId) => {
connectHandler = (peerId) => {
if (peerId === nodeId) {
this.webrtc.removeListener('signal', signalHandler);
this.webrtc.removeListener('peerConnected', connectHandler);
ws.close();
cleanup();
resolve(true);
}
};
@@ -165,19 +216,45 @@ export class RingNode extends EventEmitter {
});
ws.on('message', async (data) => {
const message = JSON.parse(data.toString());
if (message.type === 'signal' && message.from === nodeId) {
await this.webrtc.handleSignal(nodeId, message.payload);
try {
const message = JSON.parse(data.toString());
if (message.type === 'signal' && message.from === nodeId) {
await this.webrtc.handleSignal(nodeId, message.payload);
} else if (message.type === 'webrtc-connect-response') {
if (!message.success) {
cleanup();
resolve(false);
}
}
} catch (error) {
// Silently handle parsing errors
}
});
ws.on('error', reject);
ws.on('error', (error) => {
cleanup();
reject(error);
});
ws.on('close', () => {
// WebSocket connection closed
});
const cleanup = () => {
if (timeoutId) clearTimeout(timeoutId);
if (signalHandler) this.webrtc.removeListener('signal', signalHandler);
if (connectHandler) this.webrtc.removeListener('peerConnected', connectHandler);
if (ws.readyState === ws.OPEN) ws.close();
};
setTimeout(() => reject(new Error('Connection timeout')), 15000);
// Set timeout for connection process
timeoutId = setTimeout(() => {
cleanup();
reject(new Error('Connection timeout'));
}, 20000); // Increased timeout to 20 seconds
});
} catch (error) {
console.error(`Failed to connect to peer ${nodeId}:`, error);
return false;
}
}
@@ -202,9 +279,17 @@ export class RingNode extends EventEmitter {
oldMessages.forEach(id => this.messageHistory.delete(id));
}
console.log(chalk.magenta(`📨 Received ${type} from ${from.substring(0, 8)}`));
// Update last seen timestamp for the sender
const senderInfo = this.knownNodes.get(from);
if (senderInfo) {
senderInfo.lastSeen = Date.now();
this.knownNodes.set(from, senderInfo);
}
switch (type) {
case 'heartbeat':
// Heartbeat message - just update lastSeen (already done above)
break;
case 'ring-message':
this.handleRingMessage(from, payload, route, messageId);
break;
@@ -276,21 +361,20 @@ export class RingNode extends EventEmitter {
}
}
console.log(chalk.green(`📤 Sent ring message to ${sent} peers`));
return sent > 0;
}
async joinRing(bootstrapNode) {
try {
console.log(chalk.yellow(`🔄 Attempting to join ring via ${bootstrapNode}`));
const [host, port] = bootstrapNode.split(':');
const bootstrapAddress = `${host}:${port}`;
return new Promise((resolve, reject) => {
const ws = new WebSocket(`ws://${bootstrapNode}`);
const ws = new WebSocket(`ws://${bootstrapAddress}`);
let timeoutId;
let bootstrapNodeId = null;
ws.on('open', () => {
console.log(chalk.cyan('🔗 Connected to bootstrap node, sending join request...'));
// Send join ring request directly through WebSocket
ws.send(JSON.stringify({
type: 'join-ring',
@@ -303,29 +387,34 @@ export class RingNode extends EventEmitter {
}));
});
ws.on('message', (data) => {
ws.on('message', async (data) => {
try {
const message = JSON.parse(data.toString());
if (message.type === 'join-response') {
if (message.success) {
console.log(chalk.green('✅ Successfully joined the ring network!'));
bootstrapNodeId = message.bootstrapNodeId;
clearTimeout(timeoutId);
ws.close();
resolve(true);
} else {
console.log(chalk.red('❌ Join request was rejected'));
clearTimeout(timeoutId);
ws.close();
resolve(false);
}
}
// Handle signaling for WebRTC connection establishment
if (message.type === 'signal' && message.from === bootstrapNodeId) {
await this.webrtc.handleSignal(bootstrapNodeId, message.payload);
}
} catch (error) {
console.error('Error parsing join response:', error);
// Silently handle parsing errors
}
});
ws.on('error', (error) => {
console.error('WebSocket error:', error);
clearTimeout(timeoutId);
reject(error);
});
@@ -341,7 +430,6 @@ export class RingNode extends EventEmitter {
}, 15000); // Increased timeout to 15 seconds
});
} catch (error) {
console.error('Failed to join ring:', error);
return false;
}
}
@@ -349,11 +437,14 @@ export class RingNode extends EventEmitter {
async handleJoinRingRequest(ws, payload) {
const { nodeId, port, isOracle } = payload;
console.log(chalk.cyan(`🔗 New node ${nodeId.substring(0, 8)} wants to join the ring`));
try {
// Add to known nodes
this.knownNodes.set(nodeId, { port, isOracle });
this.knownNodes.set(nodeId, {
port,
isOracle,
persistent: false,
lastSeen: Date.now()
});
if (isOracle) {
this.oracleNodes.add(nodeId);
@@ -362,17 +453,36 @@ export class RingNode extends EventEmitter {
// Find optimal position in rings for the new node
await this.integrateNewNode(nodeId);
// Send success response
// Send success response with bootstrap node info
ws.send(JSON.stringify({
type: 'join-response',
success: true,
message: 'Successfully integrated into ring network'
message: 'Successfully integrated into ring network',
bootstrapNodeId: this.id,
isOracle: this.isOracle
}));
console.log(chalk.green(`✅ Node ${nodeId.substring(0, 8)} successfully joined the ring`));
} catch (error) {
console.error(`Error handling join request from ${nodeId}:`, error);
// After successful join, try to establish WebRTC connection
setTimeout(async () => {
try {
const nodeAddress = `localhost:${port}`; // Assuming localhost for now
const connection = await this.connectToPeer(nodeId, nodeAddress);
if (connection) {
// Update known node info to mark as persistent
const nodeInfo = this.knownNodes.get(nodeId);
if (nodeInfo) {
nodeInfo.persistent = true;
nodeInfo.address = nodeAddress;
this.knownNodes.set(nodeId, nodeInfo);
}
// Connection established
}
} catch (connectionError) {
// Connection failed
}
}, 3000); // Give the joining node more time to set up
} catch (error) {
// Send failure response
ws.send(JSON.stringify({
type: 'join-response',
@@ -395,8 +505,6 @@ export class RingNode extends EventEmitter {
// Notify the network of topology change
this.broadcastNetworkUpdate();
console.log(chalk.green(`✅ Integrated node ${nodeId.substring(0, 8)} into rings`));
}
handlePeerDisconnection(peerId) {
@@ -454,8 +562,6 @@ export class RingNode extends EventEmitter {
// Oracle-specific methods
handleOracleQuery(from, payload, messageId) {
console.log(chalk.yellow(`🔮 Oracle query from ${from.substring(0, 8)}: ${payload.query}`));
// Process oracle query and send response
const response = this.processOracleQuery(payload);
@@ -543,7 +649,13 @@ export class RingNode extends EventEmitter {
}
async destroy() {
console.log(chalk.red(`🛑 Shutting down node ${this.id.substring(0, 8)}`));
// Clean up intervals
if (this.connectionCheckInterval) {
clearInterval(this.connectionCheckInterval);
}
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
}
// Notify peers of shutdown
this.webrtc.broadcast({
@@ -561,4 +673,96 @@ export class RingNode extends EventEmitter {
this.removeAllListeners();
}
startConnectionManager() {
// Start periodic connection health check and maintenance
this.connectionCheckInterval = setInterval(() => {
this.maintainPersistentConnections();
}, 30000); // Check every 30 seconds
}
async maintainPersistentConnections() {
const now = Date.now();
const staleThreshold = 120000; // 2 minutes
// Check each known node
for (const [nodeId, nodeInfo] of this.knownNodes.entries()) {
if (nodeInfo.persistent) {
const connectionState = this.webrtc.getConnectionState(nodeId);
const lastSeen = nodeInfo.lastSeen || 0;
// If connection is lost or stale, try to reconnect
if (connectionState !== 'connected' || (now - lastSeen) > staleThreshold) {
try {
const connection = await this.connectToPeer(nodeId, nodeInfo.address);
if (connection) {
nodeInfo.lastSeen = now;
this.knownNodes.set(nodeId, nodeInfo);
}
} catch (error) {
// If we can't reconnect after multiple attempts, mark as non-persistent
if (!nodeInfo.reconnectAttempts) nodeInfo.reconnectAttempts = 0;
nodeInfo.reconnectAttempts++;
if (nodeInfo.reconnectAttempts >= 3) {
nodeInfo.persistent = false;
}
}
}
}
}
}
sendHeartbeat() {
// Send heartbeat to all connected peers
const heartbeatMessage = {
id: uuidv4(),
type: 'heartbeat',
from: this.id,
timestamp: Date.now()
};
const connectedPeers = this.webrtc.getConnectedPeers();
if (connectedPeers.length > 0) {
this.webrtc.broadcast(heartbeatMessage);
}
}
startHeartbeat() {
// Send heartbeat every 30 seconds
this.heartbeatInterval = setInterval(() => {
this.sendHeartbeat();
}, 30000);
}
getPersistentConnections() {
const persistentConnections = [];
for (const [nodeId, nodeInfo] of this.knownNodes.entries()) {
if (nodeInfo.persistent) {
const connectionState = this.webrtc.getConnectionState(nodeId);
persistentConnections.push({
nodeId: nodeId,
address: nodeInfo.address,
isOracle: nodeInfo.isOracle,
connectionState: connectionState,
lastSeen: nodeInfo.lastSeen,
reconnectAttempts: nodeInfo.reconnectAttempts || 0
});
}
}
return persistentConnections;
}
getConnectionStatus() {
const connectedPeers = this.webrtc.getConnectedPeers();
const persistentConnections = this.getPersistentConnections();
return {
totalConnections: connectedPeers.length,
persistentConnections: persistentConnections.length,
activeConnections: persistentConnections.filter(conn => conn.connectionState === 'connected').length,
knownNodes: this.knownNodes.size,
oracleNodes: this.oracleNodes.size
};
}
}

Ver fichero

@@ -19,7 +19,6 @@ export class WebRTCManager extends EventEmitter {
// Validate ICE servers configuration
try {
WebRTCManager.validateIceServers(this.iceServers);
console.log(`🌐 Using ${this.iceServers.length} ICE server(s) for WebRTC connections`);
} catch (error) {
console.error('Invalid ICE servers configuration:', error.message);
throw error;
@@ -61,7 +60,6 @@ export class WebRTCManager extends EventEmitter {
// Handle connection
peer.on('connect', () => {
connection.state = 'connected';
console.log(`WebRTC connection established with ${peerId.substring(0, 8)}`);
this.emit('peerConnected', peerId);
});
@@ -80,14 +78,13 @@ export class WebRTCManager extends EventEmitter {
// Handle errors
peer.on('error', (error) => {
console.error(`WebRTC error with ${peerId}:`, error.message);
console.error(`WebRTC error with ${peerId.substring(0, 8)}:`, error.message);
connection.state = 'failed';
this.removePeer(peerId);
});
// Handle close
peer.on('close', () => {
console.log(`WebRTC connection closed with ${peerId.substring(0, 8)}`);
connection.state = 'disconnected';
this.removePeer(peerId);
});
@@ -114,7 +111,7 @@ export class WebRTCManager extends EventEmitter {
connection.peer.send(JSON.stringify(message));
return true;
} catch (error) {
console.error(`Error sending message to ${peerId}:`, error);
// Silently handle send errors
return false;
}
}
@@ -131,7 +128,7 @@ export class WebRTCManager extends EventEmitter {
connection.peer.send(JSON.stringify(message));
sent++;
} catch (error) {
console.error(`Error broadcasting to ${connection.peerId}:`, error);
// Silently handle broadcast errors
}
}
}
@@ -192,7 +189,7 @@ export class WebRTCManager extends EventEmitter {
// If it's a TURN server, it should have credentials
if (urls.some(url => url.startsWith('turn:') || url.startsWith('turns:'))) {
if (!server.username || !server.credential) {
console.warn(`Warning: TURN server ${server.urls} missing username/credential`);
// TURN server missing credentials - validation only
}
}
}