Skip to content

Commit 9ba4bda

Browse files
committed
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
1 parent 3c2abd7 commit 9ba4bda

File tree

5 files changed

+99
-100
lines changed

5 files changed

+99
-100
lines changed

README.md

Lines changed: 93 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -5,50 +5,83 @@
55

66
### The High-Availability Solution to a Problem That Doesn't Exist.
77

8-
**Hypermind** is a completely decentralized, Peer-to-Peer deployment counter.
8+
**Hypermind** is a completely decentralized, Peer-to-Peer deployment counter and ephemeral chat platform.
99

10-
It solves the critical infrastructure challenge of knowing exactly how many other people are currently wasting 50MB of RAM running this specific container.
10+
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.
1111

1212
---
1313

14-
## » What is this?
15-
16-
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.**
14+
## What is this?
1715

1816
You need a service that:
1917

20-
1. Does absolutely nothing useful.
21-
2. Uses "Decentralized" and "P2P" in the description.
22-
3. Makes a number go up on a screen.
18+
1. **Does absolutely nothing useful.**
19+
2. **Uses "Decentralized" and "P2P" in the description.**
20+
3. **Makes a number go up on a screen.**
2321

2422
**Enter Hypermind.**
2523

2624
There is no central server. There is no database. There is only **The Swarm**.
2725

28-
## » How it works
26+
## How it works
27+
28+
We utilize the **Hyperswarm** DHT (Distributed Hash Table) to create a mesh network of useless nodes.
2929

30-
We utilize the **Hyperswarm** DHT (Distributed Hash Table) to achieve a singular, trivial goal of **Counting.**
30+
1. **Discovery:** Your node screams into the digital void to find friends.
31+
2. **Gossip:** Nodes connect and whisper "I exist" to each other.
32+
3. **State:**
33+
* **Active Count:** Maintained via a distributed LRU cache of peers seen in the last 45 seconds.
34+
* **Total History:** Uses a **HyperLogLog** probabilistic data structure to estimate total unique peers with >98% accuracy.
35+
4. **Chaos:** Connections are rotated every 5 minutes to ensure a dynamic, unblockable topology.
3136

32-
1. **Discovery:** Your node screams into the digital void (`hypermind-lklynet-v1`) to find friends.
33-
2. **Gossip:** Nodes connect and whisper "I exist" to each other.
34-
3. **Consensus:** Each node maintains a list of peers seen in the last 2.5 seconds.
37+
## Features
3538

36-
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).
39+
### 1. The Counter
40+
It counts. That's the main thing.
41+
* **Active Nodes:** Real-time count of currently online peers.
42+
* **Total Unique:** A probabilistic estimate of every unique node ever encountered.
3743

38-
## » Deployment
44+
### 2. Ephemeral Chat
45+
A completely decentralized chat system built directly on top of the swarm topology.
46+
* **Modes:** Local (direct neighbors) and Global (gossip relay).
47+
* **Ephemeral:** No database. No history.
48+
* **Markdown:** Full support for rich text.
3949

40-
### Docker (The Fast Way)
50+
### 3. Visualizations
51+
* **Particle Map:** Visualizes approximate peer locations (if enabled).
52+
* **Themes:** Built-in theme switcher (Nord, Solarized, Tokyo Night, etc).
53+
54+
---
55+
56+
## Usage
57+
58+
### Dashboard
59+
Open `http://localhost:3000`. The dashboard updates in **Realtime** via Server-Sent Events.
60+
61+
### Chat Commands
62+
* `/help` - Show all commands.
63+
* `/local <msg>` - Send message only to direct connections.
64+
* `/whisper <user> <msg>` - Send a private message.
65+
* `/block <user>` - Block a user.
66+
* **Easter Eggs:** `/shrug`, `/tableflip`, `/heart`, and more.
67+
68+
---
69+
70+
<details>
71+
<summary><strong>Deployment</strong></summary>
72+
73+
### Docker
4174

42-
Since you're probably pasting this into Portainer anyway:
4375

4476
```bash
4577
docker run -d \
4678
--name hypermind \
4779
--network host \
4880
--restart unless-stopped \
4981
-e PORT=3000 \
82+
-e ENABLE_CHAT=true \
83+
-e ENABLE_MAP=true \
5084
ghcr.io/lklynet/hypermind:latest
51-
5285
```
5386

5487
> **⚠️ CRITICAL NETWORK NOTE:**
@@ -67,7 +100,8 @@ services:
67100
restart: unless-stopped
68101
environment:
69102
- PORT=3000
70-
103+
- ENABLE_CHAT=true
104+
- ENABLE_MAP=true
71105
```
72106
73107
### Kubernetes (The Enterprise Way)
@@ -76,40 +110,40 @@ For when you need your useless counter to be orchestrated by a control plane.
76110
77111
```bash
78112
kubectl create deployment hypermind --image=ghcr.io/lklynet/hypermind:latest --port=3000
79-
kubectl set env deployment/hypermind PORT=3000
113+
kubectl set env deployment/hypermind PORT=3000 ENABLE_CHAT=true
80114
kubectl expose deployment hypermind --type=LoadBalancer --port=3000 --target-port=3000
81-
82115
```
83116

84-
## » Configuration
117+
</details>
118+
119+
<details>
120+
<summary><strong>Environment Variables</strong></summary>
85121

86-
You can customize Hypermind's behavior using environment variables.
122+
Hypermind is highly configurable. Use these variables to tune your experience.
87123

88-
### Extras
89-
These features are disabled by default. Set them to `true` to enable.
124+
### Feature Flags
90125

91126
| Variable | Default | Description |
92127
|----------|---------|-------------|
93-
| `ENABLE_CHAT` | `false` | Enables the decentralized chat system. |
94-
| `ENABLE_MAP` | `false` | Enables map visualization features. |
95-
| `ENABLE_THEMES` | `true` | Controls the theme switcher function ([THEMES.md](THEMES.md))
128+
| `ENABLE_CHAT` | `false` | Set to `true` to enable the P2P chat system. |
129+
| `ENABLE_MAP` | `false` | Set to `true` to enable the map visualization. |
130+
| `ENABLE_THEMES` | `true` | Set to `false` to disable the theme switcher. |
131+
| `VISUAL_LIMIT` | `500` | Max number of particles to render on the dashboard. |
96132

97-
### Refinement
98-
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.
133+
### Network Tuning
99134

100135
| Variable | Default | Description |
101136
|----------|---------|-------------|
102-
| `MAX_PEERS` | `50000` | Maximum number of peers to track in memory. |
103-
| `MAX_MESSAGE_SIZE` | `2048` | Maximum size of a single message in bytes. |
104-
| `MAX_RELAY_HOPS` | `5` | Maximum number of times a message is relayed. |
105-
| `MAX_CONNECTIONS` | `15` | Maximum number of active P2P connections. |
106-
| `HEARTBEAT_INTERVAL` | `30000` | How often (ms) to send heartbeat messages. |
107-
| `CONNECTION_ROTATION_INTERVAL` | `300000` | How often (ms) to rotate connections. |
108-
| `PEER_TIMEOUT` | `45000` | Time (ms) before a silent peer is considered offline. |
109-
| `CHAT_RATE_LIMIT` | `5000` | Time window (ms) for chat rate limiting. |
110-
| `VISUAL_LIMIT` | `500` | Max number of particles to render on the dashboard. |
137+
| `PORT` | `3000` | The web dashboard port. |
138+
| `MAX_PEERS` | `50000` | Max peers to track in LRU cache. |
139+
| `MAX_CONNECTIONS` | `15` | Max active TCP/UTP connections. |
140+
| `MAX_RELAY_HOPS` | `5` | How far a global chat message travels (TTL). |
141+
| `PEER_TIMEOUT` | `45000` | ms before a silent peer is considered offline. |
142+
143+
</details>
111144

112-
## » Ecosystem & Integrations
145+
<details>
146+
<summary><strong>Integrations</strong></summary>
113147

114148
The community has bravely stepped up to integrate Hypermind into critical monitoring infrastructure.
115149

@@ -119,9 +153,9 @@ Do you want your living room lights to turn red when the swarm grows? Of course
119153

120154
The [Hypermind HA Integration](https://github.com/synssins/hypermind-ha) (installable via HACS) provides:
121155

122-
* **RGB Control:** 0 nodes = Green. 10,000 nodes = Red.
123-
* **Sensors:** Swarm health checks and statistics logging.
124-
* **WLED Support:** Visualize the swarm size on a literal LED strip.
156+
* **RGB Control:** 0 nodes = Green. 10,000 nodes = Red.
157+
* **Sensors:** Swarm health checks and statistics logging.
158+
* **WLED Support:** Visualize the swarm size on a literal LED strip.
125159

126160
### Homepage Dashboard
127161

@@ -139,56 +173,17 @@ Add this to your `services.yaml`:
139173
method: GET
140174
mappings:
141175
- field: count
142-
label: Swarm Size
143-
- field: direct
144-
label: Friends
145-
176+
label: Active
177+
- field: totalUnique
178+
label: All Time
146179
```
147180
148-
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.
149-
See detailed [instructions](https://gethomepage.dev/configs/services/#icons).
150-
151-
## » Environment Variables
152-
153-
| Variable | Default | Description |
154-
| --- | --- | --- |
155-
| `PORT` | `3000` | The port the web dashboard listens on. Since `--network host` is used, this port opens directly on the host. |
156-
| `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. |
157-
| `ENABLE_CHAT` | `false` | Set to `true` to enable the ephemeral P2P chat terminal. |
158-
159-
## » Features
160-
161-
### 1. The Counter
162-
It counts. That's the main thing.
163-
164-
### 2. Ephemeral Chat
165-
**New:** A completely decentralized, ephemeral chat system built directly on top of the swarm topology.
166-
167-
* **Ephemeral:** No database. No history. If you refresh, it's gone.
168-
* **Restricted (Default):** You can only talk to your ~32 direct connections.
169-
* **Global Mode:** Use `/global your message` to broadcast messages to the entire swarm (relayed via gossip).
170-
* **Chaotic:** Every 30 seconds, the network rotates your connections. You might be mid-sentence and—*poof*—your audience changes.
171-
* **Anonymous:** You are identified only by the last 4 characters of your node ID.
181+
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).
172182

173-
To enable this feature, set `ENABLE_CHAT=true`.
183+
</details>
174184

175-
**Commands:**
176-
* `/global on` - Enable global chat mode.
177-
* `/global off` - Disable global chat mode (local only).
178-
* `/global <message>` - Send a single message to the global swarm without switching modes.
179-
180-
## » Usage
181-
182-
Open your browser to: `http://localhost:3000`
183-
184-
The dashboard updates in **Realtime** via Server-Sent Events.
185-
186-
**You will see:**
187-
188-
* **Active Nodes:** The total number of people currently running this joke.
189-
* **Direct Connections:** The number of peers your node is actually holding hands with.
190-
191-
## » Local Development
185+
<details>
186+
<summary><strong>Local Development</strong></summary>
192187

193188
Want to contribute? Why? It already does nothing perfectly. But here is how anyway:
194189

@@ -198,38 +193,37 @@ npm install
198193
199194
# Run the beast
200195
npm start
201-
202196
```
203197

204-
### Simulating Friends (Local Testing)
205-
198+
### Simulating a Swarm
206199
You can run multiple instances locally to simulate popularity:
207200

208201
```bash
209-
# Terminal 1 (You)
202+
# Terminal 1
210203
PORT=3000 npm start
211204
212-
# Terminal 2 (Your imaginary friend)
205+
# Terminal 2
213206
PORT=3001 npm start
214-
215207
```
216208

217-
They should discover each other, and the number will become `2`. Dopamine achieved.
209+
They will discover each other via the local network DHT, and the number will become `2`. Dopamine achieved.
210+
211+
</details>
218212

219213
---
220214

221-
### FAQ
215+
## FAQ
222216

223217
**Q: Is this crypto mining?**
224218
A: No. We respect your GPU too much.
225219

226220
**Q: Does this store data?**
227-
A: No. It has the short-term working memory of a honeybee (approx. 2.5 seconds). Which is biologically accurate and thematically consistent.
221+
A: No. It has the short-term working memory of a honeybee (approx. 45 seconds).
228222

229223
**Q: Why did you make this?**
230224
A: The homelab must grow. ¯\\_(ツ)_/¯
231225

232-
## » Star History!!
226+
## Star History
233227

234228
<a href="https://star-history.com/#lklynet/hypermind&Date">
235229
<picture>

public/app.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const countEl = document.getElementById("count");
22
const directEl = document.getElementById("direct");
3+
const totalUniqueEl = document.getElementById("total-unique");
34
const canvas = document.getElementById("network");
45
const ctx = canvas.getContext("2d");
56
let particles = [];
@@ -696,6 +697,7 @@ evtSource.onmessage = (event) => {
696697
}
697698

698699
directEl.innerText = data.direct;
700+
if (totalUniqueEl) totalUniqueEl.innerText = data.totalUnique;
699701

700702
if (data.diagnostics) {
701703
const d = data.diagnostics;

public/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
<div class="debug">
4949
ID: <span id="my-screenname">{{ID}}</span><br />
5050
Direct Connections: <span id="direct">{{DIRECT}}</span><br />
51+
Total Unique: <span id="total-unique">{{TOTAL_UNIQUE}}</span><br />
5152
<span class="debug-link" onclick="openDiagnostics()">diagnostics</span>
5253
<span id="map-container" class="{{MAP_CLASS}}">
5354
|

public/js/commands.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const ChatCommands = {
5454
{ cmd: "/unblock &lt;user&gt;", desc: "Unblock a user" },
5555
{
5656
cmd: "/local &lt;msg&gt;",
57-
desc: "Send message to direct peers only",
57+
desc: "Send message to direct peers only (Global by default)",
5858
},
5959
{ cmd: "/clear", desc: "Clear chat history" },
6060
{ cmd: "/help", desc: "Show this help menu" },

src/web/routes.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,13 @@ const setupRoutes = (
6565
app.get("/", (req, res) => {
6666
const count = peerManager.size;
6767
const directPeers = swarm.getSwarm().connections.size;
68+
const totalUnique = peerManager.totalUniquePeers;
6869

6970
const html = HTML_TEMPLATE.replace(/\{\{COUNT\}\}/g, count)
7071
.replace(/\{\{ID\}\}/g, identity.screenname || "Unknown")
7172
.replace(/\{\{FULL_ID\}\}/g, identity.id)
7273
.replace(/\{\{DIRECT\}\}/g, directPeers)
74+
.replace(/\{\{TOTAL_UNIQUE\}\}/g, totalUnique)
7375
.replace(/\{\{MAP_CLASS\}\}/g, ENABLE_MAP ? "" : "hidden")
7476
.replace(/\{\{THEMES_CLASS\}\}/g, ENABLE_THEMES ? "" : "hidden")
7577
.replace(/\{\{VISUAL_LIMIT\}\}/g, VISUAL_LIMIT);

0 commit comments

Comments
 (0)