Merge PR #42 into main, resolving conflicts by preserving optimizations

This commit is contained in:
lklynet
2026-01-06 18:40:50 -05:00
8 changed files with 67 additions and 18 deletions
+27
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+4
View File
@@ -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;
}
+2 -1
View File
@@ -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
View File
@@ -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,
};
+1 -1
View File
@@ -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
View File
@@ -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);