Skip to content

Commit 1ae1a83

Browse files
Merge branch 'main' into feat/nip43-join-leave
2 parents 090d55e + 44f3bb4 commit 1ae1a83

46 files changed

Lines changed: 3283 additions & 592 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.changeset/admin-dashboard-ui.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"nostream": minor
3+
---
4+
5+
feat: add admin observability dashboard with Grafana embed and provisioned metrics panels

‎.changeset/flat-rice-brush.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"nostream": patch
3+
---
4+
5+
fix: stop checking additional rate limit windows once a client is already rate-limited
6+
7+
`isRateLimited()` in `EventMessageHandler` and `WebSocketAdapter` looped through every
8+
configured rate limit window even after one had already tripped, calling `rateLimiter.hit()`
9+
(a Redis write) for each remaining window. Both now return as soon as the first exceeded
10+
window is found, avoiding redundant Redis writes for clients that are already being limited.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"nostream": patch
3+
---
4+
5+
fix: await Redis EXISTS call in RedisAdapter.hasKey() so it reflects actual key presence instead of always returning true
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"nostream": minor
3+
---
4+
5+
refactor: extract shared settings-config module and guided schema for admin settings editor foundation

‎.env.example‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ WORKER_COUNT=2 # Defaults to CPU count. Use 1 or 2 for local testing.
4141
# PROMETHEUS_URL=http://127.0.0.1:9090
4242
# PROMETHEUS_QUERY_TIMEOUT_MS=5000
4343
# ADMIN_METRICS_SSE_INTERVAL_MS=5000
44+
# ADMIN_METRICS_SNAPSHOT_TIMEOUT_MS=10000
45+
# ADMIN_DEPENDENCY_PING_TIMEOUT_MS=3000
46+
47+
# --- ADMIN CONSOLE (opt-in; disabled by default in default-settings.yaml) ---
48+
# ADMIN_PASSWORD=dev-admin-password
49+
# Set admin.enabled: true in .nostr/settings.yaml to enable the console
50+
# GRAFANA_URL=http://127.0.0.1:7777
51+
# GRAFANA_DASHBOARD_UID=nostream-overview
52+
# GRAFANA_ADMIN_USER=admin
53+
# GRAFANA_ADMIN_PASSWORD=admin
4454

4555
# --- RELAY PRIVATE KEY (Optional) ---
4656
# RELAY_PRIVATE_KEY=your_hex_private_key

‎CONFIGURATION.md‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ The following environment variables can be set:
5454
| REDIS_PORT | Redis Port | 6379 |
5555
| REDIS_USER | Redis User | default |
5656
| REDIS_PASSWORD | Redis Password | nostr_ts_relay |
57+
| PROMETHEUS_URL | Prometheus base URL for admin metrics queries | http://127.0.0.1:9090 |
58+
| PROMETHEUS_QUERY_TIMEOUT_MS | Timeout for each Prometheus admin metrics query (ms) | 5000 |
59+
| ADMIN_METRICS_SSE_INTERVAL_MS | Interval between `/admin/metrics` SSE snapshots (ms) | 5000 |
60+
| ADMIN_METRICS_SNAPSHOT_TIMEOUT_MS| Timeout for collecting one `/admin/metrics` snapshot (ms) | 10000 |
61+
| ADMIN_DEPENDENCY_PING_TIMEOUT_MS | Timeout for admin DB/Redis dependency pings (ms) | 3000 |
62+
| GRAFANA_URL | Grafana base URL for admin dashboard embeds | http://127.0.0.1:7777 |
5763
| NOSTR_CONFIG_DIR | Configuration directory | <project_root>/.nostr/ |
5864
| DEBUG | Debugging filter | |
5965
| ZEBEDEE_API_KEY | Zebedee Project API Key | |
@@ -143,8 +149,8 @@ The settings below are listed in alphabetical order by name. Please keep this ta
143149
| limits.client.subscription.maxSubscriptions | Maximum number of subscriptions per connected client. Defaults to 10. Disabled when set to zero. |
144150
| limits.event.content[].kinds | List of event kinds to apply limit. Use `[min, max]` for ranges. Optional. |
145151
| limits.event.content[].maxLength | Maximum length of `content`. Defaults to 1 MB. Disabled when set to zero. |
152+
| limits.event.createdAt.maxNegativeDelta | Maximum number of seconds an event's `created_at` can be in the past. Defaults to zero. Disabled when set to zero. |
146153
| limits.event.createdAt.maxPositiveDelta | Maximum number of seconds an event's `created_at` can be in the future. Defaults to 900 (15 minutes). Disabled when set to zero. |
147-
| limits.event.createdAt.minNegativeDelta | Maximum number of seconds an event's `created_at` can be in the past. Defaults to zero. Disabled when set to zero. |
148154
| limits.event.eventId.minLeadingZeroBits | Leading zero bits required on every incoming event for proof of work. Defaults to zero. Disabled when set to zero. |
149155
| limits.event.kind.blacklist | List of event kinds to always reject. Leave empty to allow any. |
150156
| limits.event.kind.whitelist | List of event kinds to always allow. Leave empty to allow any. |

‎docker-compose.yml‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,29 @@ services:
179179
networks:
180180
default:
181181

182+
grafana:
183+
image: grafana/grafana:11.2.0
184+
container_name: grafana
185+
environment:
186+
GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER:-admin}
187+
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:-admin}
188+
GF_AUTH_ANONYMOUS_ENABLED: 'true'
189+
GF_AUTH_ANONYMOUS_ORG_ROLE: Viewer
190+
GF_SECURITY_ALLOW_EMBEDDING: 'true'
191+
GF_SERVER_ROOT_URL: ${GRAFANA_URL:-http://127.0.0.1:7777}
192+
volumes:
193+
- ./grafana/provisioning:/etc/grafana/provisioning:ro
194+
- ./grafana/dashboards:/var/lib/grafana/dashboards:ro
195+
- grafana-data:/var/lib/grafana
196+
ports:
197+
- 127.0.0.1:7777:3000
198+
depends_on:
199+
prometheus:
200+
condition: service_started
201+
restart: always
202+
networks:
203+
default:
204+
182205
networks:
183206
default:
184207
name: nostream
@@ -190,3 +213,4 @@ networks:
190213
volumes:
191214
cache:
192215
prometheus-data:
216+
grafana-data:

‎docs/REDIS.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Nostream needs.
1111

1212
Rate limiting is implemented using a sliding window strategy, which uses Redis sorted sets to track request timestamps. This allows Nostream to accurately enforce rate limits over a rolling time window rather than a fixed one, preventing clients from bursting requests at window boundaries.
1313

14+
When Redis is temporarily unavailable, Nostream keeps serving the relay and admin HTTP endpoints and treats rate-limiter Redis failures as fail-closed (events are rejected as rate-limited when the backend cannot be consulted). Admin health degrades accordingly (`redis.ok=false`), so operators can detect and recover Redis without taking the relay offline.
15+
1416
## Requirements
1517

1618
- Redis 6.0 or higher (for ACL support)

0 commit comments

Comments
 (0)