feat(dashboard): add total unique peers counter and update docs

- Add new counter for total unique peers in dashboard UI
- Update command description to clarify default message scope
- Enhance README with new features and better organization
This commit is contained in:
lklynet
2026-01-08 12:31:56 -05:00
parent 3c2abd711c
commit 9ba4bda355
5 changed files with 102 additions and 103 deletions
+96 -102
View File
@@ -5,41 +5,73 @@
### The High-Availability Solution to a Problem That Doesn't Exist.
**Hypermind** is a completely decentralized, Peer-to-Peer deployment counter.
**Hypermind** is a completely decentralized, Peer-to-Peer deployment counter and ephemeral chat platform.
It solves the critical infrastructure challenge of knowing exactly how many other people are currently wasting 50MB of RAM running this specific container.
It solves the critical infrastructure challenge of knowing exactly how many other people are currently wasting ~~50MB of~~ RAM running this specific container, while providing a secure, serverless way to say "hello" to them.
---
## » What is this?
You have a server rack in your basement. You have 128GB of RAM. You have deployed the Arr stack, Home Assistant, Pi-hole, and a dashboard to monitor them all. **But you crave more.**
## What is this?
You need a service that:
1. Does absolutely nothing useful.
2. Uses "Decentralized" and "P2P" in the description.
3. Makes a number go up on a screen.
1. **Does absolutely nothing useful.**
2. **Uses "Decentralized" and "P2P" in the description.**
3. **Makes a number go up on a screen.**
**Enter Hypermind.**
There is no central server. There is no database. There is only **The Swarm**.
## » How it works
## How it works
We utilize the **Hyperswarm** DHT (Distributed Hash Table) to achieve a singular, trivial goal of **Counting.**
We utilize the **Hyperswarm** DHT (Distributed Hash Table) to create a mesh network of useless nodes.
1. **Discovery:** Your node screams into the digital void (`hypermind-lklynet-v1`) to find friends.
2. **Gossip:** Nodes connect and whisper "I exist" to each other.
3. **Consensus:** Each node maintains a list of peers seen in the last 2.5 seconds.
1. **Discovery:** Your node screams into the digital void to find friends.
2. **Gossip:** Nodes connect and whisper "I exist" to each other.
3. **State:**
* **Active Count:** Maintained via a distributed LRU cache of peers seen in the last 45 seconds.
* **Total History:** Uses a **HyperLogLog** probabilistic data structure to estimate total unique peers with >98% accuracy.
4. **Chaos:** Connections are rotated every 5 minutes to ensure a dynamic, unblockable topology.
If you turn your container off, you vanish from the count. If everyone turns it off, the network ceases to exist. If you turn it back on, you are the Creator of the Universe (Population: 1).
## Features
## » Deployment
### 1. The Counter
It counts. That's the main thing.
* **Active Nodes:** Real-time count of currently online peers.
* **Total Unique:** A probabilistic estimate of every unique node ever encountered.
### Docker (The Fast Way)
### 2. Ephemeral Chat
A completely decentralized chat system built directly on top of the swarm topology.
* **Modes:** Local (direct neighbors) and Global (gossip relay).
* **Ephemeral:** No database. No history.
* **Markdown:** Full support for rich text.
### 3. Visualizations
* **Particle Map:** Visualizes approximate peer locations (if enabled).
* **Themes:** Built-in theme switcher (Nord, Solarized, Tokyo Night, etc).
---
## Usage
### Dashboard
Open `http://localhost:3000`. The dashboard updates in **Realtime** via Server-Sent Events.
### Chat Commands
* `/help` - Show all commands.
* `/local <msg>` - Send message only to direct connections.
* `/whisper <user> <msg>` - Send a private message.
* `/block <user>` - Block a user.
* **Easter Eggs:** `/shrug`, `/tableflip`, `/heart`, and more.
---
<details>
<summary><strong>Deployment</strong></summary>
### Docker
Since you're probably pasting this into Portainer anyway:
```bash
docker run -d \
@@ -47,8 +79,9 @@ docker run -d \
--network host \
--restart unless-stopped \
-e PORT=3000 \
-e ENABLE_CHAT=true \
-e ENABLE_MAP=true \
ghcr.io/lklynet/hypermind:latest
```
> **⚠️ CRITICAL NETWORK NOTE:**
@@ -67,7 +100,8 @@ services:
restart: unless-stopped
environment:
- PORT=3000
- ENABLE_CHAT=true
- ENABLE_MAP=true
```
### Kubernetes (The Enterprise Way)
@@ -76,40 +110,40 @@ For when you need your useless counter to be orchestrated by a control plane.
```bash
kubectl create deployment hypermind --image=ghcr.io/lklynet/hypermind:latest --port=3000
kubectl set env deployment/hypermind PORT=3000
kubectl set env deployment/hypermind PORT=3000 ENABLE_CHAT=true
kubectl expose deployment hypermind --type=LoadBalancer --port=3000 --target-port=3000
```
## » Configuration
</details>
You can customize Hypermind's behavior using environment variables.
<details>
<summary><strong>Environment Variables</strong></summary>
### Extras
These features are disabled by default. Set them to `true` to enable.
Hypermind is highly configurable. Use these variables to tune your experience.
### Feature Flags
| Variable | Default | Description |
|----------|---------|-------------|
| `ENABLE_CHAT` | `false` | Enables the decentralized chat system. |
| `ENABLE_MAP` | `false` | Enables map visualization features. |
| `ENABLE_THEMES` | `true` | Controls the theme switcher function ([THEMES.md](THEMES.md))
### 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` | `5` | Maximum number of times a message is relayed. |
| `MAX_CONNECTIONS` | `15` | Maximum number of active P2P connections. |
| `HEARTBEAT_INTERVAL` | `30000` | How often (ms) to send heartbeat messages. |
| `CONNECTION_ROTATION_INTERVAL` | `300000` | How often (ms) to rotate connections. |
| `PEER_TIMEOUT` | `45000` | Time (ms) before a silent peer is considered offline. |
| `CHAT_RATE_LIMIT` | `5000` | Time window (ms) for chat rate limiting. |
| `ENABLE_CHAT` | `false` | Set to `true` to enable the P2P chat system. |
| `ENABLE_MAP` | `false` | Set to `true` to enable the map visualization. |
| `ENABLE_THEMES` | `true` | Set to `false` to disable the theme switcher. |
| `VISUAL_LIMIT` | `500` | Max number of particles to render on the dashboard. |
## » Ecosystem & Integrations
### Network Tuning
| Variable | Default | Description |
|----------|---------|-------------|
| `PORT` | `3000` | The web dashboard port. |
| `MAX_PEERS` | `50000` | Max peers to track in LRU cache. |
| `MAX_CONNECTIONS` | `15` | Max active TCP/UTP connections. |
| `MAX_RELAY_HOPS` | `5` | How far a global chat message travels (TTL). |
| `PEER_TIMEOUT` | `45000` | ms before a silent peer is considered offline. |
</details>
<details>
<summary><strong>Integrations</strong></summary>
The community has bravely stepped up to integrate Hypermind into critical monitoring infrastructure.
@@ -119,9 +153,9 @@ Do you want your living room lights to turn red when the swarm grows? Of course
The [Hypermind HA Integration](https://github.com/synssins/hypermind-ha) (installable via HACS) provides:
* **RGB Control:** 0 nodes = Green. 10,000 nodes = Red.
* **Sensors:** Swarm health checks and statistics logging.
* **WLED Support:** Visualize the swarm size on a literal LED strip.
* **RGB Control:** 0 nodes = Green. 10,000 nodes = Red.
* **Sensors:** Swarm health checks and statistics logging.
* **WLED Support:** Visualize the swarm size on a literal LED strip.
### Homepage Dashboard
@@ -139,56 +173,17 @@ Add this to your `services.yaml`:
method: GET
mappings:
- field: count
label: Swarm Size
- field: direct
label: Friends
label: Active
- field: totalUnique
label: All Time
```
To get the icon to work, you have to add the icon to `/app/public/icons`. If you have homepage running in a docker you mount an extra volume in your compose file.
See detailed [instructions](https://gethomepage.dev/configs/services/#icons).
To get the icon to work, you have to add the icon to `/app/public/icons`. See detailed [instructions](https://gethomepage.dev/configs/services/#icons).
## » Environment Variables
</details>
| Variable | Default | Description |
| --- | --- | --- |
| `PORT` | `3000` | The port the web dashboard listens on. Since `--network host` is used, this port opens directly on the host. |
| `MAX_PEERS` | `50000` | Maximum number of peers to track in the swarm. Unless you're expecting the entire internet to join, the default is probably fine. |
| `ENABLE_CHAT` | `false` | Set to `true` to enable the ephemeral P2P chat terminal. |
## » Features
### 1. The Counter
It counts. That's the main thing.
### 2. Ephemeral Chat
**New:** A completely decentralized, ephemeral chat system built directly on top of the swarm topology.
* **Ephemeral:** No database. No history. If you refresh, it's gone.
* **Restricted (Default):** You can only talk to your ~32 direct connections.
* **Global Mode:** Use `/global your message` to broadcast messages to the entire swarm (relayed via gossip).
* **Chaotic:** Every 30 seconds, the network rotates your connections. You might be mid-sentence and—*poof*—your audience changes.
* **Anonymous:** You are identified only by the last 4 characters of your node ID.
To enable this feature, set `ENABLE_CHAT=true`.
**Commands:**
* `/global on` - Enable global chat mode.
* `/global off` - Disable global chat mode (local only).
* `/global <message>` - Send a single message to the global swarm without switching modes.
## » Usage
Open your browser to: `http://localhost:3000`
The dashboard updates in **Realtime** via Server-Sent Events.
**You will see:**
* **Active Nodes:** The total number of people currently running this joke.
* **Direct Connections:** The number of peers your node is actually holding hands with.
## » Local Development
<details>
<summary><strong>Local Development</strong></summary>
Want to contribute? Why? It already does nothing perfectly. But here is how anyway:
@@ -198,38 +193,37 @@ npm install
# Run the beast
npm start
```
### Simulating Friends (Local Testing)
### Simulating a Swarm
You can run multiple instances locally to simulate popularity:
```bash
# Terminal 1 (You)
# Terminal 1
PORT=3000 npm start
# Terminal 2 (Your imaginary friend)
# Terminal 2
PORT=3001 npm start
```
They should discover each other, and the number will become `2`. Dopamine achieved.
They will discover each other via the local network DHT, and the number will become `2`. Dopamine achieved.
</details>
---
### FAQ
## FAQ
**Q: Is this crypto mining?**
A: No. We respect your GPU too much.
**Q: Does this store data?**
A: No. It has the short-term working memory of a honeybee (approx. 2.5 seconds). Which is biologically accurate and thematically consistent.
A: No. It has the short-term working memory of a honeybee (approx. 45 seconds).
**Q: Why did you make this?**
A: The homelab must grow. ¯\\_(ツ)_/¯
## » Star History!!
## Star History
<a href="https://star-history.com/#lklynet/hypermind&Date">
<picture>
+2
View File
@@ -1,5 +1,6 @@
const countEl = document.getElementById("count");
const directEl = document.getElementById("direct");
const totalUniqueEl = document.getElementById("total-unique");
const canvas = document.getElementById("network");
const ctx = canvas.getContext("2d");
let particles = [];
@@ -696,6 +697,7 @@ evtSource.onmessage = (event) => {
}
directEl.innerText = data.direct;
if (totalUniqueEl) totalUniqueEl.innerText = data.totalUnique;
if (data.diagnostics) {
const d = data.diagnostics;
+1
View File
@@ -48,6 +48,7 @@
<div class="debug">
ID: <span id="my-screenname">{{ID}}</span><br />
Direct Connections: <span id="direct">{{DIRECT}}</span><br />
Total Unique: <span id="total-unique">{{TOTAL_UNIQUE}}</span><br />
<span class="debug-link" onclick="openDiagnostics()">diagnostics</span>
<span id="map-container" class="{{MAP_CLASS}}">
|
+1 -1
View File
@@ -54,7 +54,7 @@ const ChatCommands = {
{ cmd: "/unblock &lt;user&gt;", desc: "Unblock a user" },
{
cmd: "/local &lt;msg&gt;",
desc: "Send message to direct peers only",
desc: "Send message to direct peers only (Global by default)",
},
{ cmd: "/clear", desc: "Clear chat history" },
{ cmd: "/help", desc: "Show this help menu" },
+2
View File
@@ -65,11 +65,13 @@ const setupRoutes = (
app.get("/", (req, res) => {
const count = peerManager.size;
const directPeers = swarm.getSwarm().connections.size;
const totalUnique = peerManager.totalUniquePeers;
const html = HTML_TEMPLATE.replace(/\{\{COUNT\}\}/g, count)
.replace(/\{\{ID\}\}/g, identity.screenname || "Unknown")
.replace(/\{\{FULL_ID\}\}/g, identity.id)
.replace(/\{\{DIRECT\}\}/g, directPeers)
.replace(/\{\{TOTAL_UNIQUE\}\}/g, totalUnique)
.replace(/\{\{MAP_CLASS\}\}/g, ENABLE_MAP ? "" : "hidden")
.replace(/\{\{THEMES_CLASS\}\}/g, ENABLE_THEMES ? "" : "hidden")
.replace(/\{\{VISUAL_LIMIT\}\}/g, VISUAL_LIMIT);