mirror of
https://github.com/lklynet/hypermind.git
synced 2026-05-03 17:40:29 +00:00
Merge PR #42 into main, resolving conflicts by preserving optimizations
This commit is contained in:
@@ -81,6 +81,33 @@ kubectl expose deployment hypermind --type=LoadBalancer --port=3000 --target-por
|
||||
|
||||
```
|
||||
|
||||
## » Configuration
|
||||
|
||||
You can customize Hypermind's behavior using environment variables.
|
||||
|
||||
### Extras
|
||||
These features are disabled by default. Set them to `true` to enable.
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `ENABLE_CHAT` | `false` | Enables the decentralized chat system. |
|
||||
| `ENABLE_MAP` | `false` | Enables map visualization features. |
|
||||
|
||||
### Refinement
|
||||
Tune the network parameters to fit your system resources. The defaults are safe for most users. Don't change unless you know what you're doing.
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `MAX_PEERS` | `50000` | Maximum number of peers to track in memory. |
|
||||
| `MAX_MESSAGE_SIZE` | `2048` | Maximum size of a single message in bytes. |
|
||||
| `MAX_RELAY_HOPS` | `2` | Maximum number of times a message is relayed. |
|
||||
| `MAX_CONNECTIONS` | `32` | Maximum number of active P2P connections. |
|
||||
| `HEARTBEAT_INTERVAL` | `5000` | How often (ms) to send heartbeat messages. |
|
||||
| `CONNECTION_ROTATION_INTERVAL` | `30000` | How often (ms) to rotate connections. |
|
||||
| `PEER_TIMEOUT` | `15000` | Time (ms) before a silent peer is considered offline. |
|
||||
| `CHAT_RATE_LIMIT` | `5000` | Time window (ms) for chat rate limiting. |
|
||||
| `VISUAL_LIMIT` | `500` | Max number of particles to render on the dashboard. |
|
||||
|
||||
## » Ecosystem & Integrations
|
||||
|
||||
The community has bravely stepped up to integrate Hypermind into critical monitoring infrastructure.
|
||||
|
||||
+12
-1
@@ -38,7 +38,8 @@ class Particle {
|
||||
}
|
||||
|
||||
const updateParticles = (count) => {
|
||||
const VISUAL_LIMIT = 500;
|
||||
const limitAttr = canvas.getAttribute('data-visual-limit');
|
||||
const VISUAL_LIMIT = limitAttr ? parseInt(limitAttr) : 500;
|
||||
const visualCount = Math.min(count, VISUAL_LIMIT);
|
||||
|
||||
const currentCount = particles.length;
|
||||
@@ -245,6 +246,7 @@ const terminal = document.getElementById('terminal');
|
||||
const terminalOutput = document.getElementById('terminal-output');
|
||||
const terminalInput = document.getElementById('terminal-input');
|
||||
const terminalToggle = document.getElementById('terminal-toggle');
|
||||
const mapContainer = document.getElementById('map-container');
|
||||
const promptEl = document.querySelector('.prompt');
|
||||
let myId = null;
|
||||
let myChatHistory = [];
|
||||
@@ -392,6 +394,15 @@ evtSource.onmessage = (event) => {
|
||||
document.body.classList.remove('chat-collapsed');
|
||||
}
|
||||
|
||||
if (data.mapEnabled) {
|
||||
if (mapContainer) mapContainer.style.display = 'inline';
|
||||
} else {
|
||||
if (mapContainer) mapContainer.style.display = 'none';
|
||||
if (document.getElementById('mapModal').classList.contains('active')) {
|
||||
closeMap();
|
||||
}
|
||||
}
|
||||
|
||||
if (data.id) myId = data.id;
|
||||
|
||||
if (data.peers) {
|
||||
|
||||
+3
-3
@@ -9,7 +9,7 @@
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="network"></canvas>
|
||||
<canvas id="network" data-visual-limit="{{VISUAL_LIMIT}}"></canvas>
|
||||
<div class="container">
|
||||
<div id="count" class="count" data-initial-count="{{COUNT}}">{{COUNT}}</div>
|
||||
<div class="label">Active Nodes</div>
|
||||
@@ -19,8 +19,8 @@
|
||||
<div class="debug">
|
||||
ID: {{ID}}<br>
|
||||
Direct Connections: <span id="direct">{{DIRECT}}</span><br>
|
||||
<span class="debug-link" onclick="openDiagnostics()">diagnostics</span> |
|
||||
<span class="debug-link" onclick="openMap()">map</span>
|
||||
<span class="debug-link" onclick="openDiagnostics()">diagnostics</span>
|
||||
<span id="map-container" class="{{MAP_CLASS}}"> | <span class="debug-link" id="map-link" onclick="openMap()">map</span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -155,6 +155,10 @@ a { color: #4b5563; text-decoration: none; border-bottom: 1px dotted #4b5563; }
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.terminal.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ const { relayMessage } = require("./src/p2p/relay");
|
||||
const { SwarmManager } = require("./src/p2p/swarm");
|
||||
const { SSEManager } = require("./src/web/sse");
|
||||
const { createServer, startServer } = require("./src/web/server");
|
||||
const { DIAGNOSTICS_INTERVAL, ENABLE_CHAT } = require("./src/config/constants");
|
||||
const { DIAGNOSTICS_INTERVAL, ENABLE_CHAT, ENABLE_MAP } = require("./src/config/constants");
|
||||
|
||||
const main = async () => {
|
||||
const identity = generateIdentity();
|
||||
@@ -26,6 +26,7 @@ const main = async () => {
|
||||
id: identity.id,
|
||||
diagnostics: diagnostics.getStats(),
|
||||
chatEnabled: ENABLE_CHAT,
|
||||
mapEnabled: ENABLE_MAP,
|
||||
peers: peerManager.getPeersWithIps()
|
||||
});
|
||||
};
|
||||
|
||||
+11
-7
@@ -17,18 +17,20 @@ const MY_POW_PREFIX = "00000";
|
||||
const VERIFICATION_POW_PREFIX = "0000";
|
||||
|
||||
const MAX_PEERS = parseInt(process.env.MAX_PEERS) || 50000;
|
||||
const MAX_MESSAGE_SIZE = 2048;
|
||||
const MAX_RELAY_HOPS = 2;
|
||||
const MAX_CONNECTIONS = 15;
|
||||
const MAX_MESSAGE_SIZE = parseInt(process.env.MAX_MESSAGE_SIZE) || 2048;
|
||||
const MAX_RELAY_HOPS = parseInt(process.env.MAX_RELAY_HOPS) || 2;
|
||||
const MAX_CONNECTIONS = parseInt(process.env.MAX_CONNECTIONS) || 15;
|
||||
|
||||
const HEARTBEAT_INTERVAL = 30000;
|
||||
const CONNECTION_ROTATION_INTERVAL = 300000;
|
||||
const PEER_TIMEOUT = 45000;
|
||||
const HEARTBEAT_INTERVAL = parseInt(process.env.HEARTBEAT_INTERVAL) || 30000;
|
||||
const CONNECTION_ROTATION_INTERVAL = parseInt(process.env.CONNECTION_ROTATION_INTERVAL) || 300000;
|
||||
const PEER_TIMEOUT = parseInt(process.env.PEER_TIMEOUT) || 45000;
|
||||
const BROADCAST_THROTTLE = 1000;
|
||||
const DIAGNOSTICS_INTERVAL = 10000;
|
||||
const PORT = process.env.PORT || 3000;
|
||||
const ENABLE_CHAT = process.env.ENABLE_CHAT === "true";
|
||||
const CHAT_RATE_LIMIT = 5000;
|
||||
const ENABLE_MAP = process.env.ENABLE_MAP === 'true';
|
||||
const CHAT_RATE_LIMIT = parseInt(process.env.CHAT_RATE_LIMIT) || 5000;
|
||||
const VISUAL_LIMIT = parseInt(process.env.VISUAL_LIMIT) || 500;
|
||||
|
||||
module.exports = {
|
||||
TOPIC_NAME,
|
||||
@@ -46,5 +48,7 @@ module.exports = {
|
||||
DIAGNOSTICS_INTERVAL,
|
||||
PORT,
|
||||
ENABLE_CHAT,
|
||||
ENABLE_MAP,
|
||||
CHAT_RATE_LIMIT,
|
||||
VISUAL_LIMIT,
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ const {
|
||||
verifySignature,
|
||||
createPublicKey,
|
||||
} = require("../core/security");
|
||||
const { MAX_RELAY_HOPS, ENABLE_CHAT } = require("../config/constants");
|
||||
const { MAX_RELAY_HOPS, ENABLE_CHAT, CHAT_RATE_LIMIT } = require("../config/constants");
|
||||
const { BloomFilterManager } = require("../state/bloom");
|
||||
|
||||
class MessageHandler {
|
||||
|
||||
+7
-5
@@ -1,7 +1,7 @@
|
||||
const express = require("express");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { ENABLE_CHAT, CHAT_RATE_LIMIT } = require("../config/constants");
|
||||
const { ENABLE_CHAT, ENABLE_MAP, CHAT_RATE_LIMIT, VISUAL_LIMIT } = require("../config/constants");
|
||||
|
||||
const HTML_TEMPLATE = fs.readFileSync(
|
||||
path.join(__dirname, "../../public/index.html"),
|
||||
@@ -18,7 +18,9 @@ const setupRoutes = (app, identity, peerManager, swarm, sseManager, diagnostics)
|
||||
const html = HTML_TEMPLATE
|
||||
.replace(/\{\{COUNT\}\}/g, count)
|
||||
.replace(/\{\{ID\}\}/g, "..." + identity.id.slice(-8))
|
||||
.replace(/\{\{DIRECT\}\}/g, directPeers);
|
||||
.replace(/\{\{DIRECT\}\}/g, directPeers)
|
||||
.replace(/\{\{MAP_CLASS\}\}/g, ENABLE_MAP ? '' : 'hidden')
|
||||
.replace(/\{\{VISUAL_LIMIT\}\}/g, VISUAL_LIMIT);
|
||||
|
||||
res.send(html);
|
||||
});
|
||||
@@ -67,11 +69,11 @@ const setupRoutes = (app, identity, peerManager, swarm, sseManager, diagnostics)
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
// Clean up old timestamps (older than 10 seconds)
|
||||
chatHistory = chatHistory.filter(time => now - time < 10000);
|
||||
// Clean up old timestamps (older than CHAT_RATE_LIMIT)
|
||||
chatHistory = chatHistory.filter(time => now - time < CHAT_RATE_LIMIT);
|
||||
|
||||
if (chatHistory.length >= 5) {
|
||||
return res.status(429).json({ error: "Rate limit exceeded: Max 5 messages per 10 seconds" });
|
||||
return res.status(429).json({ error: `Rate limit exceeded: Max 5 messages per ${CHAT_RATE_LIMIT / 1000} seconds` });
|
||||
}
|
||||
|
||||
chatHistory.push(now);
|
||||
|
||||
Reference in New Issue
Block a user