47
README.md
47
README.md
@@ -78,6 +78,53 @@ npm run start:node -- --port 8083 --bootstrap localhost:8080
|
|||||||
--id <id> # Node ID (default: auto-generated UUID)
|
--id <id> # Node ID (default: auto-generated UUID)
|
||||||
--bootstrap <addr> # Bootstrap node address (host:port)
|
--bootstrap <addr> # Bootstrap node address (host:port)
|
||||||
--position <pos> # Initial ring position (default: 0)
|
--position <pos> # Initial ring position (default: 0)
|
||||||
|
--ice-servers <json> # ICE servers configuration (JSON array)
|
||||||
|
--config <file> # Load configuration from JSON file
|
||||||
|
--help # Show help message
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebRTC ICE Servers Configuration
|
||||||
|
|
||||||
|
The Ring Network uses WebRTC for peer-to-peer connections. You can configure custom ICE servers (STUN/TURN) for better connectivity:
|
||||||
|
|
||||||
|
#### Using Command Line
|
||||||
|
```bash
|
||||||
|
# With custom STUN servers
|
||||||
|
node node.js --ice-servers '[{"urls":"stun:your-stun-server.com:19302"}]'
|
||||||
|
|
||||||
|
# With TURN server for NAT traversal
|
||||||
|
node node.js --ice-servers '[{"urls":"stun:stun.l.google.com:19302"},{"urls":"turn:your-turn-server.com:3478","username":"user","credential":"pass"}]'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using Configuration Files
|
||||||
|
```bash
|
||||||
|
# Load from config file
|
||||||
|
node node.js --config config/ice-servers-with-turn.json
|
||||||
|
|
||||||
|
# For Oracle nodes
|
||||||
|
node oracle.js --config config/ice-servers-public-turn.json
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Available Configuration Examples
|
||||||
|
- `config/ice-servers-default.json` - Default Google STUN servers
|
||||||
|
- `config/ice-servers-with-turn.json` - Template with TURN server
|
||||||
|
- `config/ice-servers-public-turn.json` - Public TURN servers for testing
|
||||||
|
|
||||||
|
#### ICE Server Configuration Format
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"iceServers": [
|
||||||
|
{
|
||||||
|
"urls": "stun:stun.l.google.com:19302"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"urls": "turn:turnserver.example.com:3478",
|
||||||
|
"username": "your_username",
|
||||||
|
"credential": "your_password"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
--help # Show help message
|
--help # Show help message
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
10
config/ice-servers-default.json
Archivo normal
10
config/ice-servers-default.json
Archivo normal
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"iceServers": [
|
||||||
|
{
|
||||||
|
"urls": "stun:stun.l.google.com:19302"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"urls": "stun:stun1.l.google.com:19302"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
21
config/ice-servers-public-turn.json
Archivo normal
21
config/ice-servers-public-turn.json
Archivo normal
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"iceServers": [
|
||||||
|
{
|
||||||
|
"urls": [
|
||||||
|
"stun:stun.l.google.com:19302",
|
||||||
|
"stun:stun1.l.google.com:19302",
|
||||||
|
"stun:stun2.l.google.com:19302"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"urls": "turn:openrelay.metered.ca:80",
|
||||||
|
"username": "openrelayproject",
|
||||||
|
"credential": "openrelayproject"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"urls": "turn:openrelay.metered.ca:443",
|
||||||
|
"username": "openrelayproject",
|
||||||
|
"credential": "openrelayproject"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
15
config/ice-servers-with-turn.json
Archivo normal
15
config/ice-servers-with-turn.json
Archivo normal
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"iceServers": [
|
||||||
|
{
|
||||||
|
"urls": "stun:stun.l.google.com:19302"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"urls": "stun:stun1.l.google.com:19302"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"urls": "turn:turnserver.example.com:3478",
|
||||||
|
"username": "your_username",
|
||||||
|
"credential": "your_password"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
32
node.js
32
node.js
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { RingNode } from './src/ring-node.js';
|
import { RingNode } from './src/ring-node.js';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
import { readFileSync } from 'fs';
|
||||||
|
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const options = {};
|
const options = {};
|
||||||
@@ -21,6 +22,26 @@ for (let i = 0; i < args.length; i++) {
|
|||||||
case '--position':
|
case '--position':
|
||||||
options.ringPosition = parseInt(args[++i]);
|
options.ringPosition = parseInt(args[++i]);
|
||||||
break;
|
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':
|
case '--help':
|
||||||
console.log(`
|
console.log(`
|
||||||
${chalk.blue('Ring Network Node')}
|
${chalk.blue('Ring Network Node')}
|
||||||
@@ -32,12 +53,23 @@ Options:
|
|||||||
--id <id> Node ID (default: auto-generated)
|
--id <id> Node ID (default: auto-generated)
|
||||||
--bootstrap <addr> Bootstrap node address (host:port)
|
--bootstrap <addr> Bootstrap node address (host:port)
|
||||||
--position <pos> Initial ring position (default: 0)
|
--position <pos> Initial ring position (default: 0)
|
||||||
|
--ice-servers <json> ICE servers configuration (JSON array)
|
||||||
|
--config <file> Load configuration from JSON file
|
||||||
--help Show this help message
|
--help Show this help message
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
node node.js --port 8080
|
node node.js --port 8080
|
||||||
node node.js --port 8081 --bootstrap localhost:8080
|
node node.js --port 8081 --bootstrap localhost:8080
|
||||||
node node.js --id mynode --port 8082 --bootstrap localhost:8080
|
node node.js --id mynode --port 8082 --bootstrap localhost:8080
|
||||||
|
node node.js --config config/ice-servers-with-turn.json --port 8080
|
||||||
|
|
||||||
|
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
|
||||||
`);
|
`);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
break;
|
break;
|
||||||
|
|||||||
32
oracle.js
32
oracle.js
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { OracleNode } from './src/oracle-node.js';
|
import { OracleNode } from './src/oracle-node.js';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
import { readFileSync } from 'fs';
|
||||||
|
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const options = {};
|
const options = {};
|
||||||
@@ -21,6 +22,26 @@ for (let i = 0; i < args.length; i++) {
|
|||||||
case '--position':
|
case '--position':
|
||||||
options.ringPosition = parseInt(args[++i]);
|
options.ringPosition = parseInt(args[++i]);
|
||||||
break;
|
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':
|
case '--help':
|
||||||
console.log(`
|
console.log(`
|
||||||
${chalk.yellow('Ring Network Oracle Node')}
|
${chalk.yellow('Ring Network Oracle Node')}
|
||||||
@@ -32,12 +53,23 @@ Options:
|
|||||||
--id <id> Node ID (default: auto-generated)
|
--id <id> Node ID (default: auto-generated)
|
||||||
--bootstrap <addr> Bootstrap node address (host:port)
|
--bootstrap <addr> Bootstrap node address (host:port)
|
||||||
--position <pos> Initial ring position (default: 0)
|
--position <pos> Initial ring position (default: 0)
|
||||||
|
--ice-servers <json> ICE servers configuration (JSON array)
|
||||||
|
--config <file> Load configuration from JSON file
|
||||||
--help Show this help message
|
--help Show this help message
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
node oracle.js --port 8080
|
node oracle.js --port 8080
|
||||||
node oracle.js --port 8081 --bootstrap localhost:8080
|
node oracle.js --port 8081 --bootstrap localhost:8080
|
||||||
node oracle.js --id oracle1 --port 8082 --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
|
||||||
|
|
||||||
|
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:
|
Oracle Services:
|
||||||
- network-analysis: Analyze network topology and health
|
- network-analysis: Analyze network topology and health
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ export class RingNode extends EventEmitter {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.webrtc = new WebRTCManager(this.id);
|
this.webrtc = new WebRTCManager(this.id, {
|
||||||
|
iceServers: options.iceServers
|
||||||
|
});
|
||||||
this.discoveryServer = null;
|
this.discoveryServer = null;
|
||||||
this.knownNodes = new Map();
|
this.knownNodes = new Map();
|
||||||
this.messageHistory = new Set();
|
this.messageHistory = new Set();
|
||||||
|
|||||||
@@ -4,11 +4,26 @@ import { v4 as uuidv4 } from 'uuid';
|
|||||||
import wrtc from '@koush/wrtc';
|
import wrtc from '@koush/wrtc';
|
||||||
|
|
||||||
export class WebRTCManager extends EventEmitter {
|
export class WebRTCManager extends EventEmitter {
|
||||||
constructor(nodeId) {
|
constructor(nodeId, options = {}) {
|
||||||
super();
|
super();
|
||||||
this.nodeId = nodeId;
|
this.nodeId = nodeId;
|
||||||
this.connections = new Map();
|
this.connections = new Map();
|
||||||
this.pendingConnections = new Map();
|
this.pendingConnections = new Map();
|
||||||
|
|
||||||
|
// Configure ICE servers with defaults
|
||||||
|
this.iceServers = options.iceServers || [
|
||||||
|
{ urls: 'stun:stun.l.google.com:19302' },
|
||||||
|
{ urls: 'stun:stun1.l.google.com:19302' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async createConnection(peerId, isInitiator = false) {
|
async createConnection(peerId, isInitiator = false) {
|
||||||
@@ -23,10 +38,7 @@ export class WebRTCManager extends EventEmitter {
|
|||||||
trickle: false,
|
trickle: false,
|
||||||
wrtc: wrtc,
|
wrtc: wrtc,
|
||||||
config: {
|
config: {
|
||||||
iceServers: [
|
iceServers: this.iceServers
|
||||||
{ urls: 'stun:stun.l.google.com:19302' },
|
|
||||||
{ urls: 'stun:stun1.l.google.com:19302' }
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -159,4 +171,32 @@ export class WebRTCManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
this.connections.clear();
|
this.connections.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static validateIceServers(iceServers) {
|
||||||
|
if (!Array.isArray(iceServers)) {
|
||||||
|
throw new Error('ICE servers must be an array');
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const server of iceServers) {
|
||||||
|
if (!server.urls) {
|
||||||
|
throw new Error('Each ICE server must have a "urls" property');
|
||||||
|
}
|
||||||
|
|
||||||
|
const urls = Array.isArray(server.urls) ? server.urls : [server.urls];
|
||||||
|
for (const url of urls) {
|
||||||
|
if (!url.startsWith('stun:') && !url.startsWith('turn:') && !url.startsWith('turns:')) {
|
||||||
|
throw new Error(`Invalid ICE server URL: ${url}. Must start with stun:, turn:, or turns:`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user