@soulcraft/brainy 2.15.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +249 -152
- package/dist/api/ConfigAPI.d.ts +67 -0
- package/dist/api/ConfigAPI.js +166 -0
- package/dist/api/DataAPI.d.ts +123 -0
- package/dist/api/DataAPI.js +391 -0
- package/dist/api/SecurityAPI.d.ts +50 -0
- package/dist/api/SecurityAPI.js +139 -0
- package/dist/api/UniversalImportAPI.d.ts +134 -0
- package/dist/api/UniversalImportAPI.js +615 -0
- package/dist/augmentationManager.js +12 -7
- package/dist/augmentationPipeline.d.ts +0 -61
- package/dist/augmentationPipeline.js +0 -87
- package/dist/augmentationRegistry.d.ts +1 -1
- package/dist/augmentationRegistry.js +1 -1
- package/dist/augmentations/apiServerAugmentation.d.ts +27 -1
- package/dist/augmentations/apiServerAugmentation.js +288 -7
- package/dist/augmentations/auditLogAugmentation.d.ts +109 -0
- package/dist/augmentations/auditLogAugmentation.js +358 -0
- package/dist/augmentations/batchProcessingAugmentation.d.ts +3 -2
- package/dist/augmentations/batchProcessingAugmentation.js +123 -22
- package/dist/augmentations/brainyAugmentation.d.ts +87 -8
- package/dist/augmentations/brainyAugmentation.js +159 -2
- package/dist/augmentations/cacheAugmentation.d.ts +6 -5
- package/dist/augmentations/cacheAugmentation.js +113 -17
- package/dist/augmentations/conduitAugmentations.d.ts +2 -2
- package/dist/augmentations/conduitAugmentations.js +2 -2
- package/dist/augmentations/configResolver.d.ts +122 -0
- package/dist/augmentations/configResolver.js +440 -0
- package/dist/augmentations/connectionPoolAugmentation.d.ts +3 -1
- package/dist/augmentations/connectionPoolAugmentation.js +37 -12
- package/dist/augmentations/defaultAugmentations.d.ts +9 -11
- package/dist/augmentations/defaultAugmentations.js +4 -11
- package/dist/augmentations/discovery/catalogDiscovery.d.ts +142 -0
- package/dist/augmentations/discovery/catalogDiscovery.js +249 -0
- package/dist/augmentations/discovery/localDiscovery.d.ts +84 -0
- package/dist/augmentations/discovery/localDiscovery.js +246 -0
- package/dist/augmentations/discovery/runtimeLoader.d.ts +97 -0
- package/dist/augmentations/discovery/runtimeLoader.js +337 -0
- package/dist/augmentations/discovery.d.ts +152 -0
- package/dist/augmentations/discovery.js +441 -0
- package/dist/augmentations/display/intelligentComputation.d.ts +1 -1
- package/dist/augmentations/display/intelligentComputation.js +4 -4
- package/dist/augmentations/entityRegistryAugmentation.d.ts +3 -1
- package/dist/augmentations/entityRegistryAugmentation.js +5 -1
- package/dist/augmentations/indexAugmentation.d.ts +3 -3
- package/dist/augmentations/indexAugmentation.js +2 -2
- package/dist/augmentations/intelligentVerbScoringAugmentation.d.ts +22 -6
- package/dist/augmentations/intelligentVerbScoringAugmentation.js +106 -23
- package/dist/augmentations/manifest.d.ts +176 -0
- package/dist/augmentations/manifest.js +8 -0
- package/dist/augmentations/marketplace/AugmentationMarketplace.d.ts +168 -0
- package/dist/augmentations/marketplace/AugmentationMarketplace.js +329 -0
- package/dist/augmentations/marketplace/cli.d.ts +47 -0
- package/dist/augmentations/marketplace/cli.js +265 -0
- package/dist/augmentations/metricsAugmentation.d.ts +3 -3
- package/dist/augmentations/metricsAugmentation.js +2 -2
- package/dist/augmentations/monitoringAugmentation.d.ts +3 -3
- package/dist/augmentations/monitoringAugmentation.js +2 -2
- package/dist/augmentations/neuralImport.d.ts +1 -1
- package/dist/augmentations/rateLimitAugmentation.d.ts +82 -0
- package/dist/augmentations/rateLimitAugmentation.js +321 -0
- package/dist/augmentations/requestDeduplicatorAugmentation.d.ts +2 -2
- package/dist/augmentations/requestDeduplicatorAugmentation.js +1 -1
- package/dist/augmentations/storageAugmentation.d.ts +1 -1
- package/dist/augmentations/storageAugmentation.js +2 -2
- package/dist/augmentations/storageAugmentations.d.ts +37 -8
- package/dist/augmentations/storageAugmentations.js +204 -15
- package/dist/augmentations/synapseAugmentation.d.ts +1 -1
- package/dist/augmentations/synapseAugmentation.js +35 -16
- package/dist/augmentations/typeMatching/intelligentTypeMatcher.d.ts +39 -59
- package/dist/augmentations/typeMatching/intelligentTypeMatcher.js +103 -389
- package/dist/augmentations/universalDisplayAugmentation.d.ts +2 -2
- package/dist/augmentations/universalDisplayAugmentation.js +2 -2
- package/dist/brainy-unified.d.ts +106 -0
- package/dist/brainy-unified.js +327 -0
- package/dist/brainy.d.ts +273 -0
- package/dist/brainy.js +1181 -0
- package/dist/brainyData.d.ts +29 -72
- package/dist/brainyData.js +350 -304
- package/dist/brainyDataV3.d.ts +186 -0
- package/dist/brainyDataV3.js +337 -0
- package/dist/browserFramework.d.ts +6 -6
- package/dist/browserFramework.js +11 -8
- package/dist/browserFramework.minimal.d.ts +5 -5
- package/dist/browserFramework.minimal.js +11 -8
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.js +3 -3
- package/dist/config/modelAutoConfig.d.ts +6 -7
- package/dist/config/modelAutoConfig.js +17 -76
- package/dist/cortex/backupRestore.d.ts +2 -2
- package/dist/cortex/backupRestore.js +85 -27
- package/dist/cortex/healthCheck.d.ts +2 -2
- package/dist/cortex/neuralImport.d.ts +2 -2
- package/dist/cortex/neuralImport.js +18 -13
- package/dist/cortex/performanceMonitor.d.ts +2 -2
- package/dist/critical/model-guardian.d.ts +4 -0
- package/dist/critical/model-guardian.js +31 -11
- package/dist/demo.d.ts +4 -4
- package/dist/demo.js +7 -7
- package/dist/distributed/cacheSync.d.ts +112 -0
- package/dist/distributed/cacheSync.js +265 -0
- package/dist/distributed/coordinator.d.ts +193 -0
- package/dist/distributed/coordinator.js +548 -0
- package/dist/distributed/httpTransport.d.ts +120 -0
- package/dist/distributed/httpTransport.js +446 -0
- package/dist/distributed/index.d.ts +8 -0
- package/dist/distributed/index.js +5 -0
- package/dist/distributed/networkTransport.d.ts +132 -0
- package/dist/distributed/networkTransport.js +633 -0
- package/dist/distributed/queryPlanner.d.ts +104 -0
- package/dist/distributed/queryPlanner.js +327 -0
- package/dist/distributed/readWriteSeparation.d.ts +134 -0
- package/dist/distributed/readWriteSeparation.js +350 -0
- package/dist/distributed/shardManager.d.ts +114 -0
- package/dist/distributed/shardManager.js +357 -0
- package/dist/distributed/shardMigration.d.ts +110 -0
- package/dist/distributed/shardMigration.js +289 -0
- package/dist/distributed/storageDiscovery.d.ts +160 -0
- package/dist/distributed/storageDiscovery.js +551 -0
- package/dist/embeddings/EmbeddingManager.d.ts +0 -4
- package/dist/embeddings/EmbeddingManager.js +21 -26
- package/dist/errors/brainyError.d.ts +5 -1
- package/dist/errors/brainyError.js +12 -0
- package/dist/examples/basicUsage.js +3 -3
- package/dist/graph/graphAdjacencyIndex.d.ts +96 -0
- package/dist/graph/graphAdjacencyIndex.js +288 -0
- package/dist/graph/pathfinding.js +4 -2
- package/dist/hnsw/scaledHNSWSystem.js +11 -2
- package/dist/importManager.js +6 -3
- package/dist/index.d.ts +12 -21
- package/dist/index.js +14 -22
- package/dist/mcp/brainyMCPAdapter.d.ts +4 -4
- package/dist/mcp/brainyMCPAdapter.js +5 -5
- package/dist/mcp/brainyMCPService.d.ts +3 -3
- package/dist/mcp/brainyMCPService.js +3 -11
- package/dist/mcp/mcpAugmentationToolset.js +20 -30
- package/dist/neural/embeddedPatterns.d.ts +1 -1
- package/dist/neural/embeddedPatterns.js +2 -2
- package/dist/neural/entityExtractor.d.ts +65 -0
- package/dist/neural/entityExtractor.js +316 -0
- package/dist/neural/improvedNeuralAPI.js +90 -79
- package/dist/neural/naturalLanguageProcessor.d.ts +155 -10
- package/dist/neural/naturalLanguageProcessor.js +941 -66
- package/dist/neural/naturalLanguageProcessorStatic.d.ts +2 -2
- package/dist/neural/naturalLanguageProcessorStatic.js +3 -3
- package/dist/neural/neuralAPI.js +8 -2
- package/dist/neural/patternLibrary.d.ts +57 -3
- package/dist/neural/patternLibrary.js +348 -13
- package/dist/neural/staticPatternMatcher.d.ts +2 -2
- package/dist/neural/staticPatternMatcher.js +2 -2
- package/dist/shared/default-augmentations.d.ts +3 -3
- package/dist/shared/default-augmentations.js +5 -5
- package/dist/storage/adapters/fileSystemStorage.d.ts +4 -0
- package/dist/storage/adapters/fileSystemStorage.js +54 -1
- package/dist/storage/adapters/memoryStorage.js +13 -8
- package/dist/storage/backwardCompatibility.d.ts +10 -78
- package/dist/storage/backwardCompatibility.js +17 -132
- package/dist/storage/baseStorage.d.ts +6 -0
- package/dist/storage/baseStorage.js +17 -0
- package/dist/storage/cacheManager.js +2 -2
- package/dist/storage/readOnlyOptimizations.js +8 -3
- package/dist/streaming/pipeline.d.ts +154 -0
- package/dist/streaming/pipeline.js +551 -0
- package/dist/triple/TripleIntelligence.d.ts +25 -110
- package/dist/triple/TripleIntelligence.js +4 -574
- package/dist/triple/TripleIntelligenceSystem.d.ts +159 -0
- package/dist/triple/TripleIntelligenceSystem.js +519 -0
- package/dist/types/apiTypes.d.ts +278 -0
- package/dist/types/apiTypes.js +33 -0
- package/dist/types/brainy.types.d.ts +308 -0
- package/dist/types/brainy.types.js +8 -0
- package/dist/types/brainyDataInterface.d.ts +3 -3
- package/dist/types/brainyDataInterface.js +2 -2
- package/dist/types/graphTypes.js +2 -2
- package/dist/utils/cacheAutoConfig.d.ts +3 -3
- package/dist/utils/embedding.js +8 -14
- package/dist/utils/enhancedLogger.d.ts +104 -0
- package/dist/utils/enhancedLogger.js +232 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/intelligentTypeMapper.d.ts +60 -0
- package/dist/utils/intelligentTypeMapper.js +349 -0
- package/dist/utils/metadataIndex.d.ts +118 -1
- package/dist/utils/metadataIndex.js +539 -16
- package/dist/utils/paramValidation.d.ts +39 -0
- package/dist/utils/paramValidation.js +192 -0
- package/dist/utils/rateLimiter.d.ts +160 -0
- package/dist/utils/rateLimiter.js +271 -0
- package/dist/utils/statistics.d.ts +4 -4
- package/dist/utils/statistics.js +3 -3
- package/dist/utils/structuredLogger.d.ts +146 -0
- package/dist/utils/structuredLogger.js +394 -0
- package/dist/utils/textEncoding.js +2 -1
- package/dist/utils/typeValidation.d.ts +34 -0
- package/dist/utils/typeValidation.js +247 -0
- package/package.json +14 -6
- package/scripts/download-models.cjs +6 -15
- package/dist/augmentations/walAugmentation.d.ts +0 -111
- package/dist/augmentations/walAugmentation.js +0 -519
- package/dist/chat/BrainyChat.d.ts +0 -121
- package/dist/chat/BrainyChat.js +0 -396
- package/dist/chat/ChatCLI.d.ts +0 -61
- package/dist/chat/ChatCLI.js +0 -351
|
@@ -0,0 +1,633 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network Transport Layer for Distributed Brainy
|
|
3
|
+
* Uses WebSocket + HTTP for maximum compatibility
|
|
4
|
+
*/
|
|
5
|
+
import * as http from 'http';
|
|
6
|
+
import { EventEmitter } from 'events';
|
|
7
|
+
import { WebSocket } from 'ws';
|
|
8
|
+
// Use dynamic imports for Node.js specific modules
|
|
9
|
+
let WebSocketServer;
|
|
10
|
+
// Default ports
|
|
11
|
+
const HTTP_PORT = process.env.BRAINY_HTTP_PORT || 7947;
|
|
12
|
+
const WS_PORT = process.env.BRAINY_WS_PORT || 7948;
|
|
13
|
+
/**
|
|
14
|
+
* Production-ready network transport
|
|
15
|
+
*/
|
|
16
|
+
export class NetworkTransport extends EventEmitter {
|
|
17
|
+
constructor(config) {
|
|
18
|
+
super();
|
|
19
|
+
this.peers = new Map();
|
|
20
|
+
this.connections = new Map();
|
|
21
|
+
this.messageHandlers = new Map();
|
|
22
|
+
this.responseHandlers = new Map();
|
|
23
|
+
this.isRunning = false;
|
|
24
|
+
this.nodeId = config.nodeId || this.generateNodeId();
|
|
25
|
+
this.config = {
|
|
26
|
+
host: '0.0.0.0',
|
|
27
|
+
httpPort: Number(HTTP_PORT),
|
|
28
|
+
wsPort: Number(WS_PORT),
|
|
29
|
+
discoveryMethod: 'auto',
|
|
30
|
+
enableUDP: false, // Disabled by default for cloud compatibility
|
|
31
|
+
...config
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Start network transport
|
|
36
|
+
*/
|
|
37
|
+
async start() {
|
|
38
|
+
if (this.isRunning)
|
|
39
|
+
return;
|
|
40
|
+
// Dynamic import for Node.js environment
|
|
41
|
+
if (typeof window === 'undefined') {
|
|
42
|
+
const ws = await import('ws');
|
|
43
|
+
WebSocketServer = ws.WebSocketServer || ws.Server || ws.default;
|
|
44
|
+
}
|
|
45
|
+
await this.startHTTPServer();
|
|
46
|
+
await this.startWebSocketServer();
|
|
47
|
+
await this.discoverPeers();
|
|
48
|
+
this.isRunning = true;
|
|
49
|
+
this.emit('started', { nodeId: this.nodeId });
|
|
50
|
+
// Start heartbeat
|
|
51
|
+
this.startHeartbeat();
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Stop network transport
|
|
55
|
+
*/
|
|
56
|
+
async stop() {
|
|
57
|
+
if (!this.isRunning)
|
|
58
|
+
return;
|
|
59
|
+
this.isRunning = false;
|
|
60
|
+
// Close all connections
|
|
61
|
+
for (const ws of this.connections.values()) {
|
|
62
|
+
ws.close();
|
|
63
|
+
}
|
|
64
|
+
this.connections.clear();
|
|
65
|
+
// Stop servers
|
|
66
|
+
if (this.httpServer) {
|
|
67
|
+
await new Promise((resolve) => {
|
|
68
|
+
this.httpServer.close(() => resolve());
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (this.wsServer) {
|
|
72
|
+
await new Promise((resolve) => {
|
|
73
|
+
this.wsServer.close(() => resolve());
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
this.emit('stopped');
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Start HTTP server for REST API and health checks
|
|
80
|
+
*/
|
|
81
|
+
async startHTTPServer() {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
this.httpServer = http.createServer(async (req, res) => {
|
|
84
|
+
// Enable CORS
|
|
85
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
86
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
87
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
88
|
+
if (req.method === 'OPTIONS') {
|
|
89
|
+
res.writeHead(200);
|
|
90
|
+
res.end();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (req.url === '/health') {
|
|
94
|
+
// Health check endpoint
|
|
95
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
96
|
+
res.end(JSON.stringify({
|
|
97
|
+
status: 'healthy',
|
|
98
|
+
nodeId: this.nodeId,
|
|
99
|
+
peers: Array.from(this.peers.keys()),
|
|
100
|
+
connections: Array.from(this.connections.keys())
|
|
101
|
+
}));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (req.url === '/peers') {
|
|
105
|
+
// Peer discovery endpoint
|
|
106
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
107
|
+
res.end(JSON.stringify({
|
|
108
|
+
nodeId: this.nodeId,
|
|
109
|
+
endpoint: {
|
|
110
|
+
host: this.config.host,
|
|
111
|
+
httpPort: this.config.httpPort,
|
|
112
|
+
wsPort: this.config.wsPort
|
|
113
|
+
},
|
|
114
|
+
peers: Array.from(this.peers.values())
|
|
115
|
+
}));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (req.method === 'POST' && req.url === '/message') {
|
|
119
|
+
// Message handling endpoint
|
|
120
|
+
let body = '';
|
|
121
|
+
req.on('data', (chunk) => {
|
|
122
|
+
body += chunk.toString();
|
|
123
|
+
});
|
|
124
|
+
req.on('end', async () => {
|
|
125
|
+
try {
|
|
126
|
+
const message = JSON.parse(body);
|
|
127
|
+
// Handle message
|
|
128
|
+
const handler = this.messageHandlers.get(message.type);
|
|
129
|
+
if (handler) {
|
|
130
|
+
const response = await handler(message);
|
|
131
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
132
|
+
res.end(JSON.stringify({ success: true, data: response }));
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
res.writeHead(404);
|
|
136
|
+
res.end(JSON.stringify({ success: false, error: 'Unknown message type' }));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
res.writeHead(500);
|
|
141
|
+
res.end(JSON.stringify({ success: false, error: err.message }));
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
res.writeHead(404);
|
|
147
|
+
res.end(JSON.stringify({ error: 'Not found' }));
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
this.httpServer.listen(this.config.httpPort, '0.0.0.0', () => {
|
|
151
|
+
console.log(`[Network] HTTP server listening on :${this.config.httpPort}`);
|
|
152
|
+
resolve();
|
|
153
|
+
});
|
|
154
|
+
this.httpServer.on('error', reject);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Start WebSocket server for real-time communication
|
|
159
|
+
*/
|
|
160
|
+
async startWebSocketServer() {
|
|
161
|
+
if (!WebSocketServer) {
|
|
162
|
+
console.warn('[Network] WebSocket not available in this environment');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
this.wsServer = new WebSocketServer({ port: this.config.wsPort });
|
|
166
|
+
this.wsServer.on('connection', (ws) => {
|
|
167
|
+
let peerId = null;
|
|
168
|
+
ws.on('message', async (data) => {
|
|
169
|
+
try {
|
|
170
|
+
const message = JSON.parse(data.toString());
|
|
171
|
+
// Handle handshake
|
|
172
|
+
if (message.type === 'HANDSHAKE') {
|
|
173
|
+
peerId = message.from;
|
|
174
|
+
this.connections.set(peerId, ws);
|
|
175
|
+
// Add to peers
|
|
176
|
+
const endpoint = {
|
|
177
|
+
nodeId: peerId,
|
|
178
|
+
host: message.data.host || 'unknown',
|
|
179
|
+
httpPort: message.data.httpPort || 0,
|
|
180
|
+
wsPort: message.data.wsPort || 0,
|
|
181
|
+
lastSeen: Date.now()
|
|
182
|
+
};
|
|
183
|
+
this.peers.set(peerId, endpoint);
|
|
184
|
+
// Send handshake response
|
|
185
|
+
ws.send(JSON.stringify({
|
|
186
|
+
type: 'HANDSHAKE_ACK',
|
|
187
|
+
from: this.nodeId,
|
|
188
|
+
to: peerId,
|
|
189
|
+
data: {
|
|
190
|
+
nodeId: this.nodeId,
|
|
191
|
+
host: this.config.host,
|
|
192
|
+
httpPort: this.config.httpPort,
|
|
193
|
+
wsPort: this.config.wsPort
|
|
194
|
+
},
|
|
195
|
+
timestamp: Date.now(),
|
|
196
|
+
id: this.generateMessageId()
|
|
197
|
+
}));
|
|
198
|
+
this.emit('peerConnected', peerId);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
// Handle response messages
|
|
202
|
+
if (message.type.endsWith('_RESPONSE')) {
|
|
203
|
+
const handler = this.responseHandlers.get(message.id);
|
|
204
|
+
if (handler) {
|
|
205
|
+
handler(message.data);
|
|
206
|
+
this.responseHandlers.delete(message.id);
|
|
207
|
+
}
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// Handle regular messages
|
|
211
|
+
const handler = this.messageHandlers.get(message.type);
|
|
212
|
+
if (handler) {
|
|
213
|
+
const response = await handler(message);
|
|
214
|
+
if (response !== undefined) {
|
|
215
|
+
ws.send(JSON.stringify({
|
|
216
|
+
type: `${message.type}_RESPONSE`,
|
|
217
|
+
from: this.nodeId,
|
|
218
|
+
to: message.from,
|
|
219
|
+
data: response,
|
|
220
|
+
timestamp: Date.now(),
|
|
221
|
+
id: message.id
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
console.error('[Network] WebSocket message error:', err);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
ws.on('close', () => {
|
|
231
|
+
if (peerId) {
|
|
232
|
+
this.connections.delete(peerId);
|
|
233
|
+
this.emit('peerDisconnected', peerId);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
ws.on('error', (err) => {
|
|
237
|
+
console.error(`[Network] WebSocket error:`, err.message);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
console.log(`[Network] WebSocket server listening on :${this.config.wsPort}`);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Discover peers based on configuration
|
|
244
|
+
*/
|
|
245
|
+
async discoverPeers() {
|
|
246
|
+
const method = this.config.discoveryMethod;
|
|
247
|
+
if (method === 'seeds' || (method === 'auto' && this.config.seeds)) {
|
|
248
|
+
// Use seed nodes
|
|
249
|
+
await this.connectToSeeds();
|
|
250
|
+
}
|
|
251
|
+
else if (method === 'dns' || (method === 'auto' && process.env.BRAINY_DNS)) {
|
|
252
|
+
// Use DNS discovery
|
|
253
|
+
await this.discoverViaDNS();
|
|
254
|
+
}
|
|
255
|
+
else if (method === 'kubernetes' || (method === 'auto' && process.env.KUBERNETES_SERVICE_HOST)) {
|
|
256
|
+
// Use Kubernetes service discovery
|
|
257
|
+
await this.discoverViaKubernetes();
|
|
258
|
+
}
|
|
259
|
+
// Fallback: try localhost for development
|
|
260
|
+
if (this.peers.size === 0 && process.env.NODE_ENV !== 'production') {
|
|
261
|
+
await this.connectToNode('localhost', this.config.httpPort);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Connect to seed nodes
|
|
266
|
+
*/
|
|
267
|
+
async connectToSeeds() {
|
|
268
|
+
if (!this.config.seeds)
|
|
269
|
+
return;
|
|
270
|
+
for (const seed of this.config.seeds) {
|
|
271
|
+
try {
|
|
272
|
+
// Parse seed address (host:port or just host)
|
|
273
|
+
const [host, port] = seed.split(':');
|
|
274
|
+
await this.connectToNode(host, Number(port) || this.config.httpPort);
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
console.error(`[Network] Failed to connect to seed ${seed}:`, err);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Discover peers via DNS
|
|
283
|
+
*/
|
|
284
|
+
async discoverViaDNS() {
|
|
285
|
+
const dnsName = process.env.BRAINY_DNS || 'brainy-cluster.local';
|
|
286
|
+
try {
|
|
287
|
+
const dns = await import('dns');
|
|
288
|
+
const addresses = await new Promise((resolve, reject) => {
|
|
289
|
+
dns.resolve4(dnsName, (err, addresses) => {
|
|
290
|
+
if (err)
|
|
291
|
+
reject(err);
|
|
292
|
+
else
|
|
293
|
+
resolve(addresses || []);
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
for (const address of addresses) {
|
|
297
|
+
await this.connectToNode(address, this.config.httpPort);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
console.log(`[Network] DNS discovery failed for ${dnsName}:`, err);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Discover peers via Kubernetes
|
|
306
|
+
*/
|
|
307
|
+
async discoverViaKubernetes() {
|
|
308
|
+
const serviceName = process.env.BRAINY_SERVICE || 'brainy';
|
|
309
|
+
const namespace = process.env.BRAINY_NAMESPACE || 'default';
|
|
310
|
+
const apiServer = 'https://kubernetes.default.svc';
|
|
311
|
+
const token = process.env.KUBERNETES_TOKEN || '';
|
|
312
|
+
try {
|
|
313
|
+
// Query Kubernetes API for pod endpoints
|
|
314
|
+
const https = await import('https');
|
|
315
|
+
const response = await new Promise((resolve, reject) => {
|
|
316
|
+
https.get(`${apiServer}/api/v1/namespaces/${namespace}/endpoints/${serviceName}`, {
|
|
317
|
+
headers: {
|
|
318
|
+
'Authorization': `Bearer ${token}`
|
|
319
|
+
}
|
|
320
|
+
}, (res) => {
|
|
321
|
+
let data = '';
|
|
322
|
+
res.on('data', (chunk) => data += chunk);
|
|
323
|
+
res.on('end', () => resolve(JSON.parse(data)));
|
|
324
|
+
}).on('error', reject);
|
|
325
|
+
});
|
|
326
|
+
// Connect to each pod
|
|
327
|
+
if (response.subsets) {
|
|
328
|
+
for (const subset of response.subsets) {
|
|
329
|
+
for (const address of subset.addresses || []) {
|
|
330
|
+
await this.connectToNode(address.ip, this.config.httpPort);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
catch (err) {
|
|
336
|
+
console.log('[Network] Kubernetes discovery failed:', err);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Connect to a specific node
|
|
341
|
+
*/
|
|
342
|
+
async connectToNode(host, httpPort) {
|
|
343
|
+
try {
|
|
344
|
+
// First, get node info via HTTP
|
|
345
|
+
const nodeInfo = await this.getNodeInfo(host, httpPort);
|
|
346
|
+
if (nodeInfo.nodeId === this.nodeId) {
|
|
347
|
+
return; // Don't connect to self
|
|
348
|
+
}
|
|
349
|
+
// Add to peers
|
|
350
|
+
const endpoint = {
|
|
351
|
+
nodeId: nodeInfo.nodeId,
|
|
352
|
+
host,
|
|
353
|
+
httpPort,
|
|
354
|
+
wsPort: nodeInfo.endpoint.wsPort,
|
|
355
|
+
lastSeen: Date.now()
|
|
356
|
+
};
|
|
357
|
+
this.peers.set(nodeInfo.nodeId, endpoint);
|
|
358
|
+
// Connect via WebSocket
|
|
359
|
+
await this.connectWebSocket(endpoint);
|
|
360
|
+
// Get their peer list
|
|
361
|
+
for (const peer of nodeInfo.peers || []) {
|
|
362
|
+
if (!this.peers.has(peer.nodeId) && peer.nodeId !== this.nodeId) {
|
|
363
|
+
this.peers.set(peer.nodeId, peer);
|
|
364
|
+
// Optionally connect to them too
|
|
365
|
+
if (this.peers.size < 10) { // Limit connections
|
|
366
|
+
await this.connectWebSocket(peer);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
catch (err) {
|
|
372
|
+
// Node might be down or not ready
|
|
373
|
+
console.debug(`[Network] Could not connect to ${host}:${httpPort}`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Get node information via HTTP
|
|
378
|
+
*/
|
|
379
|
+
async getNodeInfo(host, port) {
|
|
380
|
+
return new Promise((resolve, reject) => {
|
|
381
|
+
const req = http.get(`http://${host}:${port}/peers`, (res) => {
|
|
382
|
+
let data = '';
|
|
383
|
+
res.on('data', (chunk) => data += chunk);
|
|
384
|
+
res.on('end', () => {
|
|
385
|
+
try {
|
|
386
|
+
resolve(JSON.parse(data));
|
|
387
|
+
}
|
|
388
|
+
catch (err) {
|
|
389
|
+
reject(err);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
req.on('error', reject);
|
|
394
|
+
req.setTimeout(2000, () => {
|
|
395
|
+
req.destroy();
|
|
396
|
+
reject(new Error('Timeout'));
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Connect to peer via WebSocket
|
|
402
|
+
*/
|
|
403
|
+
async connectWebSocket(endpoint) {
|
|
404
|
+
if (this.connections.has(endpoint.nodeId))
|
|
405
|
+
return;
|
|
406
|
+
try {
|
|
407
|
+
const ws = new WebSocket(`ws://${endpoint.host}:${endpoint.wsPort}`);
|
|
408
|
+
ws.on('open', () => {
|
|
409
|
+
// Send handshake
|
|
410
|
+
ws.send(JSON.stringify({
|
|
411
|
+
type: 'HANDSHAKE',
|
|
412
|
+
from: this.nodeId,
|
|
413
|
+
data: {
|
|
414
|
+
nodeId: this.nodeId,
|
|
415
|
+
host: this.config.host,
|
|
416
|
+
httpPort: this.config.httpPort,
|
|
417
|
+
wsPort: this.config.wsPort
|
|
418
|
+
},
|
|
419
|
+
timestamp: Date.now(),
|
|
420
|
+
id: this.generateMessageId()
|
|
421
|
+
}));
|
|
422
|
+
this.connections.set(endpoint.nodeId, ws);
|
|
423
|
+
});
|
|
424
|
+
ws.on('message', async (data) => {
|
|
425
|
+
try {
|
|
426
|
+
const message = JSON.parse(data.toString());
|
|
427
|
+
// Handle responses
|
|
428
|
+
if (message.type.endsWith('_RESPONSE')) {
|
|
429
|
+
const handler = this.responseHandlers.get(message.id);
|
|
430
|
+
if (handler) {
|
|
431
|
+
handler(message.data);
|
|
432
|
+
this.responseHandlers.delete(message.id);
|
|
433
|
+
}
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
// Handle messages
|
|
437
|
+
const handler = this.messageHandlers.get(message.type);
|
|
438
|
+
if (handler) {
|
|
439
|
+
await handler(message);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
catch (err) {
|
|
443
|
+
console.error('[Network] Message handling error:', err);
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
ws.on('close', () => {
|
|
447
|
+
this.connections.delete(endpoint.nodeId);
|
|
448
|
+
});
|
|
449
|
+
ws.on('error', (err) => {
|
|
450
|
+
console.debug(`[Network] WebSocket error with ${endpoint.nodeId}:`, err.message);
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
catch (err) {
|
|
454
|
+
console.debug(`[Network] Failed to connect to ${endpoint.nodeId}`);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Start heartbeat to maintain connections
|
|
459
|
+
*/
|
|
460
|
+
startHeartbeat() {
|
|
461
|
+
setInterval(() => {
|
|
462
|
+
if (!this.isRunning)
|
|
463
|
+
return;
|
|
464
|
+
// Send heartbeat to all connected peers
|
|
465
|
+
for (const [nodeId, ws] of this.connections.entries()) {
|
|
466
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
467
|
+
ws.send(JSON.stringify({
|
|
468
|
+
type: 'HEARTBEAT',
|
|
469
|
+
from: this.nodeId,
|
|
470
|
+
to: nodeId,
|
|
471
|
+
timestamp: Date.now(),
|
|
472
|
+
id: this.generateMessageId()
|
|
473
|
+
}));
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
// Connection lost, remove it
|
|
477
|
+
this.connections.delete(nodeId);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
// Clean up stale peers
|
|
481
|
+
const now = Date.now();
|
|
482
|
+
for (const [nodeId, peer] of this.peers.entries()) {
|
|
483
|
+
if (now - peer.lastSeen > 60000) { // 60 seconds
|
|
484
|
+
this.peers.delete(nodeId);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}, 10000); // Every 10 seconds
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Send message to specific node
|
|
491
|
+
*/
|
|
492
|
+
async sendToNode(nodeId, type, data) {
|
|
493
|
+
const ws = this.connections.get(nodeId);
|
|
494
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
495
|
+
// Use WebSocket
|
|
496
|
+
return new Promise((resolve, reject) => {
|
|
497
|
+
const messageId = this.generateMessageId();
|
|
498
|
+
const timeout = setTimeout(() => {
|
|
499
|
+
this.responseHandlers.delete(messageId);
|
|
500
|
+
reject(new Error(`Timeout waiting for response from ${nodeId}`));
|
|
501
|
+
}, 5000);
|
|
502
|
+
this.responseHandlers.set(messageId, (response) => {
|
|
503
|
+
clearTimeout(timeout);
|
|
504
|
+
resolve(response);
|
|
505
|
+
});
|
|
506
|
+
ws.send(JSON.stringify({
|
|
507
|
+
type,
|
|
508
|
+
from: this.nodeId,
|
|
509
|
+
to: nodeId,
|
|
510
|
+
data,
|
|
511
|
+
timestamp: Date.now(),
|
|
512
|
+
id: messageId
|
|
513
|
+
}));
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
// Use HTTP fallback
|
|
518
|
+
const endpoint = this.peers.get(nodeId);
|
|
519
|
+
if (!endpoint) {
|
|
520
|
+
throw new Error(`Unknown node: ${nodeId}`);
|
|
521
|
+
}
|
|
522
|
+
return this.sendViaHTTP(endpoint, type, data);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Send via HTTP
|
|
527
|
+
*/
|
|
528
|
+
async sendViaHTTP(endpoint, type, data) {
|
|
529
|
+
return new Promise((resolve, reject) => {
|
|
530
|
+
const message = {
|
|
531
|
+
type,
|
|
532
|
+
from: this.nodeId,
|
|
533
|
+
to: endpoint.nodeId,
|
|
534
|
+
data,
|
|
535
|
+
timestamp: Date.now(),
|
|
536
|
+
id: this.generateMessageId()
|
|
537
|
+
};
|
|
538
|
+
const postData = JSON.stringify(message);
|
|
539
|
+
const req = http.request({
|
|
540
|
+
hostname: endpoint.host,
|
|
541
|
+
port: endpoint.httpPort,
|
|
542
|
+
path: '/message',
|
|
543
|
+
method: 'POST',
|
|
544
|
+
headers: {
|
|
545
|
+
'Content-Type': 'application/json',
|
|
546
|
+
'Content-Length': Buffer.byteLength(postData)
|
|
547
|
+
}
|
|
548
|
+
}, (res) => {
|
|
549
|
+
let responseData = '';
|
|
550
|
+
res.on('data', (chunk) => {
|
|
551
|
+
responseData += chunk;
|
|
552
|
+
});
|
|
553
|
+
res.on('end', () => {
|
|
554
|
+
try {
|
|
555
|
+
const response = JSON.parse(responseData);
|
|
556
|
+
if (response.success) {
|
|
557
|
+
resolve(response.data);
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
reject(new Error(response.error));
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
catch (err) {
|
|
564
|
+
reject(err);
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
req.on('error', reject);
|
|
569
|
+
req.setTimeout(5000, () => {
|
|
570
|
+
req.destroy();
|
|
571
|
+
reject(new Error('HTTP timeout'));
|
|
572
|
+
});
|
|
573
|
+
req.write(postData);
|
|
574
|
+
req.end();
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Broadcast to all peers
|
|
579
|
+
*/
|
|
580
|
+
async broadcast(type, data) {
|
|
581
|
+
const promises = [];
|
|
582
|
+
for (const nodeId of this.peers.keys()) {
|
|
583
|
+
promises.push(this.sendToNode(nodeId, type, data).catch(() => {
|
|
584
|
+
// Ignore broadcast failures
|
|
585
|
+
}));
|
|
586
|
+
}
|
|
587
|
+
await Promise.all(promises);
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Register message handler
|
|
591
|
+
*/
|
|
592
|
+
onMessage(type, handler) {
|
|
593
|
+
this.messageHandlers.set(type, handler);
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Get connected peers
|
|
597
|
+
*/
|
|
598
|
+
getPeers() {
|
|
599
|
+
return Array.from(this.peers.values());
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Check if connected
|
|
603
|
+
*/
|
|
604
|
+
isConnected(nodeId) {
|
|
605
|
+
const ws = this.connections.get(nodeId);
|
|
606
|
+
return ws !== undefined && ws.readyState === WebSocket.OPEN;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Generate node ID
|
|
610
|
+
*/
|
|
611
|
+
generateNodeId() {
|
|
612
|
+
return `node-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Generate message ID
|
|
616
|
+
*/
|
|
617
|
+
generateMessageId() {
|
|
618
|
+
return `${this.nodeId}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Get node ID
|
|
622
|
+
*/
|
|
623
|
+
getNodeId() {
|
|
624
|
+
return this.nodeId;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Create network transport
|
|
629
|
+
*/
|
|
630
|
+
export function createNetworkTransport(config) {
|
|
631
|
+
return new NetworkTransport(config);
|
|
632
|
+
}
|
|
633
|
+
//# sourceMappingURL=networkTransport.js.map
|