Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8453d82ee4 | ||
|
|
8c6770c7e2 | ||
|
|
7cd33aa6ea | ||
|
|
81c5339063 | ||
|
|
5ec5ed9bd4 | ||
|
|
bd5150cd09 | ||
|
|
2e1d731de4 | ||
|
|
75d983b2df | ||
|
|
a766f08738 | ||
|
|
23c37abe3a | ||
|
|
5b3ccfd1f4 | ||
|
|
38a027e626 | ||
|
|
a042aca524 | ||
|
|
20902e1c5d | ||
|
|
7233818da9 | ||
|
|
86cbf7ff16 | ||
|
|
3035e71ca5 | ||
|
|
179b160cf3 | ||
|
|
aedd22436e | ||
|
|
8fdc362a8b | ||
|
|
67cf3973c5 | ||
|
|
c02ae2be5b | ||
|
|
fd3efdd01f | ||
|
|
232f93c16f | ||
|
|
9a9365dcfa | ||
|
|
5577b57149 | ||
|
|
22c943d495 | ||
|
|
7e3d9b6825 | ||
|
|
547d22d09f | ||
|
|
ce9ae5a488 | ||
|
|
9b248b740f | ||
|
|
0f77aeb72b | ||
|
|
bb64651a0c | ||
|
|
17be9c2b03 | ||
|
|
f396c622b6 | ||
|
|
cbd260c1ae | ||
|
|
bc9ac290ab | ||
|
|
192eeb248d | ||
|
|
da6c505420 | ||
|
|
c077c209e5 | ||
|
|
9bf02702c2 | ||
|
|
0920cc092d | ||
|
|
a89460be5d | ||
|
|
ff2a3aa335 | ||
|
|
94b61e8a7c | ||
|
|
b0c0754e83 | ||
|
|
3265e3d114 | ||
|
|
927659ece1 | ||
|
|
b6ff4150b4 | ||
|
|
63bc526163 | ||
|
|
a1f712236a | ||
|
|
06e6c17b7b | ||
|
|
0751a7c55c | ||
|
|
f1728932a9 | ||
|
|
ef8bdef2a8 | ||
|
|
c11a8ba292 | ||
|
|
0f124fe575 | ||
|
|
6b20452fab | ||
|
|
10c19bc243 | ||
|
|
3d7aa2196f | ||
|
|
a416c3f275 | ||
|
|
bba9baabc3 | ||
|
|
31187c4c4f | ||
|
|
55f862b879 | ||
|
|
76c9b3fcf0 | ||
|
|
929bd09164 | ||
|
|
d17f1dd8d5 | ||
|
|
207a949835 | ||
|
|
d08f4e4221 | ||
|
|
c96736fa6a | ||
|
|
f8ec4ae924 | ||
|
|
fe7304ac7f | ||
|
|
e5d39c984b | ||
|
|
5e45f21e35 | ||
|
|
5321a238b8 | ||
|
|
083bc14972 | ||
|
|
11aaccba9b | ||
|
|
bd1bbd763d | ||
|
|
2bd7aa5a10 | ||
|
|
361912ec85 | ||
|
|
0de491382e | ||
|
|
3148bbbee7 | ||
|
|
3965ba04d8 | ||
|
|
b96af938bd | ||
|
|
89c8248013 | ||
|
|
d8f477c6cf | ||
|
|
040eeadb13 | ||
|
|
83f8b0ab88 | ||
|
|
b82f7eaaf3 | ||
|
|
0dc5b75d7c | ||
|
|
e94b1a81e3 | ||
|
|
1adabdbc4e | ||
|
|
81d44c3d8c | ||
|
|
7acc0bdd90 | ||
|
|
c4ef71d673 | ||
|
|
086d2af56c | ||
|
|
18a7deec54 | ||
|
|
c794370a3f | ||
|
|
2ed4b96058 | ||
|
|
c0051b22be | ||
|
|
4cc2d2376e | ||
|
|
30dc4bf67d | ||
|
|
a1928cc5d7 | ||
|
|
7bf0757b1f | ||
|
|
11b0a88cdd | ||
|
|
e8f8e3b0cf | ||
|
|
35b1461ff6 | ||
|
|
87c6aa5e16 | ||
|
|
f0462929ea | ||
|
|
0ccf1959c2 | ||
|
|
ef172c8356 | ||
|
|
ae0370b47f | ||
|
|
137df6253d | ||
|
|
79f06bf1ed | ||
|
|
9e5a42fd3c | ||
|
|
553d398ef5 | ||
|
|
ac0bf17c4f | ||
|
|
4efd7140d7 | ||
|
|
43b9027d4a | ||
|
|
9a0b2714f5 | ||
|
|
10fc80aa07 | ||
|
|
9fa4e1dcf1 | ||
|
|
11c9f8c2a4 | ||
|
|
17ddf3f2b8 | ||
|
|
f70d5077e8 | ||
|
|
19cc1fa804 | ||
|
|
ed1de7d32d | ||
|
|
7b02c6a2cb | ||
|
|
dba229040d | ||
|
|
d8b09e0dbb | ||
|
|
73fb681118 | ||
|
|
cf0f606dd9 | ||
|
|
cb165ddab1 | ||
|
|
58eb19e4e7 | ||
|
|
aeaecddb5a | ||
|
|
09dff8e91f | ||
|
|
f49aae8ab0 | ||
|
|
f6debcf799 | ||
|
|
edbc4f1359 | ||
|
|
5242f066e7 | ||
|
|
af186800fa | ||
|
|
2bff4a5f44 | ||
|
|
edb73d50cf | ||
|
|
3dc09d55fd | ||
|
|
079fb1b0f5 | ||
|
|
17b2aa8111 | ||
|
|
78d484cfe0 | ||
|
|
182e12817d | ||
|
|
9179d57cc9 | ||
|
|
9cb9b746d8 | ||
|
|
57a0089664 | ||
|
|
53f7608872 | ||
|
|
838ce5b45a | ||
|
|
e878b9557e | ||
|
|
6638d37d6f | ||
|
|
4c29e15329 | ||
|
|
48890a2121 | ||
|
|
e312d7e18c | ||
|
|
6c38aaebf3 | ||
|
|
18b0ac44bf | ||
|
|
b6749eff2f | ||
|
|
c73a103280 | ||
|
|
a5d194f730 | ||
|
|
6320436b88 | ||
|
|
87325927ed | ||
|
|
4435cdf5b6 | ||
|
|
b041654611 | ||
|
|
e833dcefd4 | ||
|
|
29680f0ee8 | ||
|
|
670329700c | ||
|
|
62e17af311 | ||
|
|
e3938a2c85 | ||
|
|
49ffc3d99e | ||
|
|
34bb1c34a2 |
+1
-1
@@ -11,4 +11,4 @@ copy_executable_local.sh
|
||||
nostr_login_lite/
|
||||
style_guide/
|
||||
nostr-tools
|
||||
|
||||
.test_keysadmin/cache/
|
||||
|
||||
+6
-3
@@ -1,3 +1,6 @@
|
||||
[submodule "nostr_core_lib"]
|
||||
path = nostr_core_lib
|
||||
url = https://git.laantungir.net/laantungir/nostr_core_lib.git
|
||||
[submodule "c_utils_lib"]
|
||||
path = c_utils_lib
|
||||
url = ssh://git@git.laantungir.net:2222/laantungir/c_utils_lib.git
|
||||
[submodule "text_graph"]
|
||||
path = text_graph
|
||||
url = ssh://git@git.laantungir.net:2222/laantungir/text_graph.git
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ADMIN_PUBKEY='6a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3'
|
||||
SERVER_PRIVKEY='1111111111111111111111111111111111111111111111111111111111111111'
|
||||
+11
-11
@@ -1,12 +1,12 @@
|
||||
|
||||
# AGENTS.md - AI Agent Integration Guide for Architect Mode
|
||||
|
||||
**Project-Specific Information for AI Agents Working with C-Relay in Architect Mode**
|
||||
**Project-Specific Information for AI Agents Working with C-Relay-PG in Architect Mode**
|
||||
|
||||
## Critical Architecture Understanding
|
||||
|
||||
### System Architecture Overview
|
||||
C-Relay implements a **unique event-based configuration architecture** that fundamentally differs from traditional Nostr relays:
|
||||
C-Relay-PG implements a **unique event-based configuration architecture** that fundamentally differs from traditional Nostr relays:
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
||||
@@ -51,9 +51,9 @@ C-Relay implements a **unique event-based configuration architecture** that fund
|
||||
## Architectural Decision Analysis
|
||||
|
||||
### Configuration System Design
|
||||
**Traditional Approach vs C-Relay:**
|
||||
**Traditional Approach vs C-Relay-PG:**
|
||||
```
|
||||
Traditional: C-Relay:
|
||||
Traditional: C-Relay-PG:
|
||||
config.json → kind 33334 events
|
||||
ENV variables → cryptographically signed tags
|
||||
File watching → database polling/restart
|
||||
@@ -119,18 +119,18 @@ File watching → database polling/restart
|
||||
```
|
||||
Developer Machine:
|
||||
├── ./make_and_restart_relay.sh
|
||||
├── build/c_relay_x86
|
||||
├── build/c_relay_pg_x86
|
||||
├── build/<relay_pubkey>.db
|
||||
└── relay.log
|
||||
```
|
||||
|
||||
### Production SystemD Deployment
|
||||
```
|
||||
/opt/c-relay/:
|
||||
├── c_relay_x86
|
||||
/opt/c-relay-pg/:
|
||||
├── c_relay_pg_x86
|
||||
├── <relay_pubkey>.db
|
||||
├── systemd service (c-relay.service)
|
||||
└── c-relay user isolation
|
||||
├── systemd service (c-relay-pg.service)
|
||||
└── c-relay-pg user isolation
|
||||
```
|
||||
|
||||
### Container Deployment Architecture
|
||||
@@ -144,7 +144,7 @@ Container:
|
||||
|
||||
### Reverse Proxy Architecture
|
||||
```
|
||||
Internet → Nginx/HAProxy → C-Relay
|
||||
Internet → Nginx/HAProxy → C-Relay-PG
|
||||
├── WebSocket upgrade handling
|
||||
├── SSL termination
|
||||
└── Rate limiting
|
||||
@@ -292,7 +292,7 @@ Admin Signs Event → WebSocket Submit → Validate → Store → Restart Requir
|
||||
**Decision**: Same port serves both protocols
|
||||
**Consequences**: Simplified deployment, protocol detection overhead, libwebsockets dependency
|
||||
|
||||
These architectural decisions form the foundation of C-Relay's unique approach to Nostr relay implementation and should be carefully considered when planning extensions or modifications.
|
||||
These architectural decisions form the foundation of C-Relay-PG's unique approach to Nostr relay implementation and should be carefully considered when planning extensions or modifications.
|
||||
**
|
||||
|
||||
[Response interrupted by a tool use result. Only one tool may be used at a time and should be placed at the end of the message.]
|
||||
@@ -2,6 +2,6 @@
|
||||
description: "Brief description of what this command does"
|
||||
---
|
||||
|
||||
Run build_and_push.sh, and supply a good git commit message. For example:
|
||||
Run increment_and_push.sh, and supply a good git commit message. For example:
|
||||
|
||||
./build_and_push.sh "Fixed the bug with nip05 implementation"
|
||||
./increment_and_push.sh "Fixed the bug with nip05 implementation"
|
||||
+1
-1
@@ -1 +1 @@
|
||||
src/embedded_web_content.c
|
||||
src/embedded_web_content.c
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ADMIN_PUBKEY='8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e'
|
||||
SERVER_PRIVKEY='1111111111111111111111111111111111111111111111111111111111111111'
|
||||
Executable
BIN
Binary file not shown.
@@ -1,6 +1,59 @@
|
||||
# AGENTS.md - AI Agent Integration Guide
|
||||
|
||||
**Project-Specific Information for AI Agents Working with C-Relay**
|
||||
**Project-Specific Information for AI Agents Working with C-Relay-PG**
|
||||
|
||||
## ⚠️ CRITICAL: Never Run `make` Directly
|
||||
|
||||
**NEVER run `make` to build the relay binary.** The Makefile will refuse and
|
||||
print an error. Running `make` directly produces a dynamically-linked binary
|
||||
that will silently fall back to SQLite storage while the admin UI connects to
|
||||
PostgreSQL — causing the admin page to show stale data.
|
||||
|
||||
Always use one of these instead:
|
||||
|
||||
- **`./build_static.sh`** — Build the static MUSL binary with PostgreSQL backend
|
||||
- **`./make_and_restart_relay.sh`** — Build, kill old relay, and start new one
|
||||
|
||||
The Makefile exists only for submodule compilation (nostr_core_lib, c_utils_lib)
|
||||
and utility targets (clean, install-deps). It will refuse to build the relay
|
||||
binary directly.
|
||||
|
||||
## Critical Build Commands
|
||||
|
||||
### Primary Build Command
|
||||
```bash
|
||||
./make_and_restart_relay.sh
|
||||
```
|
||||
**Never use `make` directly.** The project requires the custom restart script which:
|
||||
- Handles database preservation/cleanup based on flags
|
||||
- Manages architecture-specific binary detection (x86/ARM64)
|
||||
- Performs automatic process cleanup and port management
|
||||
- Starts relay in background with proper logging
|
||||
|
||||
**Note:** `--test-keys` / `-t` is now the **default**. Use `--no-test-keys` or `--production` for random key generation.
|
||||
|
||||
### Architecture-Specific Binary Outputs
|
||||
- **x86_64**: `./build/c_relay_pg_x86`
|
||||
- **ARM64**: `./build/c_relay_pg_arm64`
|
||||
- **Other**: `./build/c_relay_pg_$(ARCH)`
|
||||
|
||||
**Project-Specific Information for AI Agents Working with C-Relay-PG**
|
||||
|
||||
## ⚠️ CRITICAL: Never Run `make` Directly
|
||||
|
||||
**NEVER run `make` to build the relay binary.** The Makefile will refuse and
|
||||
print an error. Running `make` directly produces a dynamically-linked binary
|
||||
that will silently fall back to SQLite storage while the admin UI connects to
|
||||
PostgreSQL — causing the admin page to show stale data.
|
||||
|
||||
Always use one of these instead:
|
||||
|
||||
- **`./build_static.sh`** — Build the static MUSL binary with PostgreSQL backend
|
||||
- **`./make_and_restart_relay.sh`** — Build, kill old relay, and start new one
|
||||
|
||||
The Makefile exists only for submodule compilation (nostr_core_lib, c_utils_lib)
|
||||
and utility targets (clean, install-deps). It will refuse to build the relay
|
||||
binary directly.
|
||||
|
||||
## Critical Build Commands
|
||||
|
||||
@@ -15,9 +68,9 @@
|
||||
- Starts relay in background with proper logging
|
||||
|
||||
### Architecture-Specific Binary Outputs
|
||||
- **x86_64**: `./build/c_relay_x86`
|
||||
- **ARM64**: `./build/c_relay_arm64`
|
||||
- **Other**: `./build/c_relay_$(ARCH)`
|
||||
- **x86_64**: `./build/c_relay_pg_x86`
|
||||
- **ARM64**: `./build/c_relay_pg_arm64`
|
||||
- **Other**: `./build/c_relay_pg_$(ARCH)`
|
||||
|
||||
### Database File Naming Convention
|
||||
- **Format**: `<relay_pubkey>.db` (NOT `.nrdb` as shown in docs)
|
||||
@@ -75,10 +128,10 @@
|
||||
### Process Management
|
||||
```bash
|
||||
# Kill existing relay processes
|
||||
pkill -f "c_relay_"
|
||||
pkill -f "c_relay_pg_"
|
||||
|
||||
# Check running processes
|
||||
ps aux | grep c_relay_
|
||||
ps aux | grep c_relay_pg_
|
||||
|
||||
# Force kill port binding
|
||||
fuser -k 8888/tcp
|
||||
@@ -95,7 +148,7 @@ fuser -k 8888/tcp
|
||||
- Event configuration tests: `tests/event_config_tests.sh`
|
||||
|
||||
### SystemD Integration Considerations
|
||||
- Service runs as `c-relay` user in `/opt/c-relay`
|
||||
- Service runs as `c-relay-pg` user in `/opt/c-relay-pg`
|
||||
- Database files created in WorkingDirectory automatically
|
||||
- No environment variables needed (event-based config)
|
||||
- Resource limits: 65536 file descriptors, 4096 processes
|
||||
@@ -121,8 +174,8 @@ fuser -k 8888/tcp
|
||||
- Event filtering done at C level, not SQL level for NIP-40 expiration
|
||||
|
||||
### Configuration Override Behavior
|
||||
- CLI port override only affects first-time startup
|
||||
- After database creation, all config comes from events
|
||||
- CLI port override applies during first-time startup and existing relay restarts
|
||||
- After database creation, all config comes from events (but CLI overrides can still be applied)
|
||||
- Database path cannot be changed after initialization
|
||||
|
||||
## Non-Obvious Pitfalls
|
||||
@@ -137,7 +190,7 @@ fuser -k 8888/tcp
|
||||
## Quick Debugging Commands
|
||||
```bash
|
||||
# Check relay status
|
||||
ps aux | grep c_relay_ && netstat -tln | grep 8888
|
||||
ps aux | grep c_relay_pg_ && netstat -tln | grep 8888
|
||||
|
||||
# View logs
|
||||
tail -f relay.log
|
||||
|
||||
@@ -0,0 +1,995 @@
|
||||
# C-Relay-PG API Documentation
|
||||
|
||||
Complete API reference for the C-Relay-PG event-based administration system and advanced features.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Authentication](#authentication)
|
||||
- [Admin API](#admin-api)
|
||||
- [Event Structure](#event-structure)
|
||||
- [Configuration Management](#configuration-management)
|
||||
- [Auth Rules Management](#auth-rules-management)
|
||||
- [System Commands](#system-commands)
|
||||
- [Database Queries](#database-queries)
|
||||
- [Configuration Reference](#configuration-reference)
|
||||
- [Real-time Monitoring](#real-time-monitoring)
|
||||
- [Direct Message Admin](#direct-message-admin)
|
||||
- [Response Formats](#response-formats)
|
||||
- [Error Handling](#error-handling)
|
||||
- [Examples](#examples)
|
||||
|
||||
## Overview
|
||||
|
||||
C-Relay-PG uses an innovative **event-based administration system** where all configuration and management commands are sent as cryptographically signed Nostr events. This provides:
|
||||
|
||||
- **Cryptographic security**: All commands must be signed with the admin private key
|
||||
- **Audit trail**: Complete history of all administrative actions
|
||||
- **Real-time updates**: Configuration changes applied instantly
|
||||
- **Standard protocol**: Uses Nostr events, no custom protocols
|
||||
- **NIP-44 encryption**: All admin commands and responses are encrypted
|
||||
|
||||
### Key Concepts
|
||||
|
||||
1. **Admin Keypair**: Generated on first startup, used to sign all admin commands
|
||||
2. **Relay Keypair**: The relay's identity on the Nostr network
|
||||
3. **Admin Events**: Kind 23456 events with NIP-44 encrypted commands
|
||||
4. **Response Events**: Kind 23457 events with NIP-44 encrypted responses
|
||||
5. **Event-Based Config**: All settings stored as events in the database
|
||||
|
||||
## Authentication
|
||||
|
||||
### Admin Private Key
|
||||
|
||||
The admin private key is displayed **only once** during first startup:
|
||||
|
||||
```
|
||||
========================================
|
||||
IMPORTANT: SAVE THIS ADMIN PRIVATE KEY
|
||||
========================================
|
||||
Admin Private Key: nsec1abc123...
|
||||
Admin Public Key: npub1def456...
|
||||
========================================
|
||||
```
|
||||
|
||||
**Critical**: Save this key immediately. It cannot be recovered and is required for all administrative operations.
|
||||
|
||||
### Secure Storage
|
||||
|
||||
Store the admin private key securely:
|
||||
|
||||
```bash
|
||||
# Environment variable
|
||||
export C_RELAY_ADMIN_KEY="nsec1abc123..."
|
||||
|
||||
# Secure file
|
||||
echo "nsec1abc123..." > ~/.c-relay-pg-admin
|
||||
chmod 600 ~/.c-relay-pg-admin
|
||||
|
||||
# Password manager (recommended)
|
||||
# Store in 1Password, Bitwarden, etc.
|
||||
```
|
||||
|
||||
### Key Loss Recovery
|
||||
|
||||
If you lose the admin private key:
|
||||
|
||||
1. Stop the relay
|
||||
2. Delete the database file (`*.db`)
|
||||
3. Restart the relay (generates new keys)
|
||||
4. **Note**: This deletes all events and configuration
|
||||
|
||||
## Admin API
|
||||
|
||||
### Event Structure
|
||||
|
||||
All admin commands use the same event structure with NIP-44 encrypted content.
|
||||
|
||||
#### Admin Command Event (Kind 23456)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "computed_event_id",
|
||||
"pubkey": "admin_public_key_hex",
|
||||
"created_at": 1234567890,
|
||||
"kind": 23456,
|
||||
"content": "AqHBUgcM7dXFYLQuDVzGwMST1G8jtWYyVvYxXhVGEu4nAb4LVw...",
|
||||
"tags": [
|
||||
["p", "relay_public_key_hex"]
|
||||
],
|
||||
"sig": "event_signature"
|
||||
}
|
||||
```
|
||||
|
||||
**Fields**:
|
||||
- `kind`: Must be `23456` for admin commands
|
||||
- `pubkey`: Admin public key (hex format)
|
||||
- `content`: NIP-44 encrypted JSON array containing the command
|
||||
- `tags`: Must include `["p", "relay_pubkey"]` tag
|
||||
- `sig`: Valid signature from admin private key
|
||||
|
||||
#### Encrypted Content Format
|
||||
|
||||
The `content` field contains a NIP-44 encrypted JSON array:
|
||||
|
||||
```json
|
||||
["command_name", "param1", "param2", ...]
|
||||
```
|
||||
|
||||
Examples:
|
||||
```json
|
||||
["config_query", "all"]
|
||||
["config_update", [{"key": "relay_name", "value": "My Relay", ...}]]
|
||||
["blacklist", "pubkey", "abc123..."]
|
||||
["auth_query", "all"]
|
||||
["sql_query", "SELECT * FROM events LIMIT 10"]
|
||||
```
|
||||
|
||||
#### Admin Response Event (Kind 23457)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "response_event_id",
|
||||
"pubkey": "relay_public_key_hex",
|
||||
"created_at": 1234567890,
|
||||
"kind": 23457,
|
||||
"content": "BpKCVhfN8eYtRmPqSvWxZnMkL2gHjUiOp3rTyEwQaS5dFg...",
|
||||
"tags": [
|
||||
["p", "admin_public_key_hex"],
|
||||
["e", "request_event_id"]
|
||||
],
|
||||
"sig": "response_signature"
|
||||
}
|
||||
```
|
||||
|
||||
**Fields**:
|
||||
- `kind`: Always `23457` for admin responses
|
||||
- `pubkey`: Relay public key (hex format)
|
||||
- `content`: NIP-44 encrypted JSON response object
|
||||
- `tags`: Includes `["p", "admin_pubkey"]` and optionally `["e", "request_id"]`
|
||||
- `sig`: Valid signature from relay private key
|
||||
|
||||
### Configuration Management
|
||||
|
||||
#### Query All Configuration
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["config_query", "all"]
|
||||
```
|
||||
|
||||
**Response** (decrypted):
|
||||
```json
|
||||
{
|
||||
"query_type": "config_all",
|
||||
"total_results": 27,
|
||||
"timestamp": 1234567890,
|
||||
"data": [
|
||||
{
|
||||
"key": "relay_name",
|
||||
"value": "C-Relay-PG",
|
||||
"data_type": "string",
|
||||
"category": "relay",
|
||||
"description": "Relay name displayed in NIP-11"
|
||||
},
|
||||
{
|
||||
"key": "auth_enabled",
|
||||
"value": "false",
|
||||
"data_type": "boolean",
|
||||
"category": "auth",
|
||||
"description": "Enable whitelist/blacklist authentication"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Update Configuration
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["config_update", [
|
||||
{
|
||||
"key": "relay_name",
|
||||
"value": "My Awesome Relay",
|
||||
"data_type": "string",
|
||||
"category": "relay"
|
||||
},
|
||||
{
|
||||
"key": "max_subscriptions_per_client",
|
||||
"value": "50",
|
||||
"data_type": "integer",
|
||||
"category": "limits"
|
||||
}
|
||||
]]
|
||||
```
|
||||
|
||||
**Response** (decrypted):
|
||||
```json
|
||||
{
|
||||
"query_type": "config_update",
|
||||
"status": "success",
|
||||
"total_results": 2,
|
||||
"timestamp": 1234567890,
|
||||
"data": [
|
||||
{
|
||||
"key": "relay_name",
|
||||
"value": "My Awesome Relay",
|
||||
"status": "updated"
|
||||
},
|
||||
{
|
||||
"key": "max_subscriptions_per_client",
|
||||
"value": "50",
|
||||
"status": "updated"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Auth Rules Management
|
||||
|
||||
#### Add Blacklist Rule
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["blacklist", "pubkey", "abc123def456..."]
|
||||
```
|
||||
|
||||
**Response** (decrypted):
|
||||
```json
|
||||
{
|
||||
"query_type": "auth_add",
|
||||
"status": "success",
|
||||
"message": "Blacklist rule added successfully",
|
||||
"timestamp": 1234567890
|
||||
}
|
||||
```
|
||||
|
||||
#### Add Whitelist Rule
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["whitelist", "pubkey", "def456abc123..."]
|
||||
```
|
||||
|
||||
#### Delete Auth Rule
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["delete_auth_rule", "blacklist", "pubkey", "abc123def456..."]
|
||||
```
|
||||
|
||||
**Response** (decrypted):
|
||||
```json
|
||||
{
|
||||
"query_type": "auth_delete",
|
||||
"status": "success",
|
||||
"message": "Auth rule deleted successfully",
|
||||
"timestamp": 1234567890
|
||||
}
|
||||
```
|
||||
|
||||
#### Query All Auth Rules
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["auth_query", "all"]
|
||||
```
|
||||
|
||||
**Response** (decrypted):
|
||||
```json
|
||||
{
|
||||
"query_type": "auth_rules_all",
|
||||
"total_results": 5,
|
||||
"timestamp": 1234567890,
|
||||
"data": [
|
||||
{
|
||||
"rule_type": "blacklist",
|
||||
"pattern_type": "pubkey",
|
||||
"pattern_value": "abc123...",
|
||||
"action": "deny"
|
||||
},
|
||||
{
|
||||
"rule_type": "whitelist",
|
||||
"pattern_type": "pubkey",
|
||||
"pattern_value": "def456...",
|
||||
"action": "allow"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Query Specific Rule Type
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["auth_query", "whitelist"]
|
||||
```
|
||||
|
||||
#### Query Specific Pattern
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["auth_query", "pattern", "abc123..."]
|
||||
```
|
||||
|
||||
### System Commands
|
||||
|
||||
#### System Status
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["system_command", "system_status"]
|
||||
```
|
||||
|
||||
**Response** (decrypted):
|
||||
```json
|
||||
{
|
||||
"query_type": "system_status",
|
||||
"timestamp": 1234567890,
|
||||
"status": "running",
|
||||
"uptime_seconds": 86400,
|
||||
"version": "0.6.0",
|
||||
"relay_pubkey": "relay_public_key_hex",
|
||||
"database_size_bytes": 10485760,
|
||||
"total_events": 15432,
|
||||
"active_connections": 42,
|
||||
"active_subscriptions": 156
|
||||
}
|
||||
```
|
||||
|
||||
#### Clear All Auth Rules
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["system_command", "clear_all_auth_rules"]
|
||||
```
|
||||
|
||||
**Response** (decrypted):
|
||||
```json
|
||||
{
|
||||
"query_type": "system_command",
|
||||
"status": "success",
|
||||
"message": "All auth rules cleared",
|
||||
"timestamp": 1234567890
|
||||
}
|
||||
```
|
||||
|
||||
#### Database Statistics
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["stats_query"]
|
||||
```
|
||||
|
||||
**Response** (decrypted):
|
||||
```json
|
||||
{
|
||||
"query_type": "stats_query",
|
||||
"timestamp": 1234567890,
|
||||
"database_size_bytes": 10485760,
|
||||
"total_events": 15432,
|
||||
"database_created_at": 1234567800,
|
||||
"latest_event_at": 1234567890,
|
||||
"event_kinds": [
|
||||
{
|
||||
"kind": 1,
|
||||
"count": 12000,
|
||||
"percentage": 77.8
|
||||
},
|
||||
{
|
||||
"kind": 0,
|
||||
"count": 2500,
|
||||
"percentage": 16.2
|
||||
}
|
||||
],
|
||||
"time_stats": {
|
||||
"total": 15432,
|
||||
"last_24h": 234,
|
||||
"last_7d": 1456,
|
||||
"last_30d": 5432
|
||||
},
|
||||
"top_pubkeys": [
|
||||
{
|
||||
"pubkey": "abc123...",
|
||||
"event_count": 1234,
|
||||
"percentage": 8.0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Database Queries
|
||||
|
||||
#### SQL Query Command
|
||||
|
||||
Execute read-only SQL queries against the relay database.
|
||||
|
||||
**Command**:
|
||||
```json
|
||||
["sql_query", "SELECT * FROM events ORDER BY created_at DESC LIMIT 10"]
|
||||
```
|
||||
|
||||
**Response** (decrypted):
|
||||
```json
|
||||
{
|
||||
"query_type": "sql_query",
|
||||
"request_id": "request_event_id",
|
||||
"timestamp": 1234567890,
|
||||
"query": "SELECT * FROM events ORDER BY created_at DESC LIMIT 10",
|
||||
"execution_time_ms": 45,
|
||||
"row_count": 10,
|
||||
"columns": ["id", "pubkey", "created_at", "kind", "content", "tags", "sig"],
|
||||
"rows": [
|
||||
["abc123...", "def456...", 1234567890, 1, "Hello world", "[]", "sig123..."],
|
||||
["ghi789...", "jkl012...", 1234567880, 0, "{\"name\":\"Alice\"}", "[]", "sig456..."]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Security Features
|
||||
|
||||
- **Read-only**: Only SELECT statements allowed
|
||||
- **Query timeout**: 5 seconds maximum
|
||||
- **Result limit**: 1000 rows maximum
|
||||
- **Logging**: All queries logged with execution time
|
||||
- **Validation**: SQL injection protection
|
||||
|
||||
#### Available Tables and Views
|
||||
|
||||
**Core Tables**:
|
||||
- `events` - All Nostr events
|
||||
- `config` - Configuration parameters
|
||||
- `auth_rules` - Authentication rules
|
||||
- `subscription_events` - Subscription lifecycle log
|
||||
- `event_broadcasts` - Event broadcast log
|
||||
|
||||
**Views**:
|
||||
- `recent_events` - Last 1000 events
|
||||
- `event_stats` - Event statistics by type
|
||||
- `subscription_analytics` - Subscription metrics
|
||||
- `active_subscriptions_log` - Currently active subscriptions
|
||||
- `event_kinds_view` - Event distribution by kind
|
||||
- `top_pubkeys_view` - Top 10 pubkeys by event count
|
||||
- `time_stats_view` - Time-based statistics
|
||||
|
||||
#### Example Queries
|
||||
|
||||
**Recent events**:
|
||||
```sql
|
||||
SELECT id, pubkey, created_at, kind
|
||||
FROM events
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 20
|
||||
```
|
||||
|
||||
**Event distribution**:
|
||||
```sql
|
||||
SELECT * FROM event_kinds_view
|
||||
ORDER BY count DESC
|
||||
```
|
||||
|
||||
**Active subscriptions**:
|
||||
```sql
|
||||
SELECT * FROM active_subscriptions_log
|
||||
ORDER BY created_at DESC
|
||||
```
|
||||
|
||||
**Database statistics**:
|
||||
```sql
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM events) as total_events,
|
||||
(SELECT COUNT(*) FROM subscription_events) as total_subscriptions,
|
||||
(SELECT COUNT(DISTINCT pubkey) FROM events) as unique_pubkeys
|
||||
```
|
||||
|
||||
**Events by specific pubkey**:
|
||||
```sql
|
||||
SELECT id, created_at, kind, content
|
||||
FROM events
|
||||
WHERE pubkey = 'abc123...'
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 50
|
||||
```
|
||||
|
||||
**Events in time range**:
|
||||
```sql
|
||||
SELECT COUNT(*) as count, kind
|
||||
FROM events
|
||||
WHERE created_at BETWEEN 1234567000 AND 1234567890
|
||||
GROUP BY kind
|
||||
ORDER BY count DESC
|
||||
```
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
### Basic Relay Settings
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| `relay_name` | string | "C-Relay-PG" | Relay name (NIP-11) |
|
||||
| `relay_description` | string | "C Nostr Relay" | Relay description |
|
||||
| `relay_contact` | string | "" | Admin contact info |
|
||||
| `relay_software` | string | "c-relay-pg" | Software identifier |
|
||||
| `relay_version` | string | auto | Software version |
|
||||
| `supported_nips` | string | "1,9,11,13,15,20,33,40,42,45,50,70" | Supported NIPs |
|
||||
| `language_tags` | string | "*" | Supported languages |
|
||||
| `relay_countries` | string | "*" | Supported countries |
|
||||
| `posting_policy` | string | "" | Posting policy URL |
|
||||
| `payments_url` | string | "" | Payment URL |
|
||||
|
||||
### Connection & Limits
|
||||
|
||||
| Key | Type | Default | Range | Restart Required |
|
||||
|-----|------|---------|-------|------------------|
|
||||
| `max_connections` | integer | 1000 | 1-10000 | Yes |
|
||||
| `max_subscriptions_per_client` | integer | 25 | 1-100 | No |
|
||||
| `max_total_subscriptions` | integer | 5000 | 100-50000 | No |
|
||||
| `max_message_length` | integer | 65536 | 1024-1048576 | No |
|
||||
| `max_event_tags` | integer | 2000 | 10-10000 | No |
|
||||
| `max_content_length` | integer | 65536 | 1-1048576 | No |
|
||||
|
||||
### Authentication & Access Control
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| `auth_enabled` | boolean | false | Enable whitelist/blacklist |
|
||||
| `nip42_auth_required` | boolean | false | Require NIP-42 auth |
|
||||
| `nip42_auth_required_kinds` | string | "" | Kinds requiring NIP-42 |
|
||||
| `nip42_challenge_timeout` | integer | 300 | Challenge timeout (seconds) |
|
||||
|
||||
### Proof of Work (NIP-13)
|
||||
|
||||
| Key | Type | Default | Values | Description |
|
||||
|-----|------|---------|--------|-------------|
|
||||
| `pow_min_difficulty` | integer | 0 | 0-40 | Minimum PoW difficulty |
|
||||
| `pow_mode` | string | "optional" | disabled/optional/required | PoW enforcement mode |
|
||||
|
||||
### Event Expiration (NIP-40)
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| `nip40_expiration_enabled` | boolean | true | Enable expiration support |
|
||||
| `nip40_expiration_strict` | boolean | false | Reject expired events |
|
||||
| `nip40_expiration_filter` | boolean | true | Filter expired from results |
|
||||
| `nip40_expiration_grace_period` | integer | 300 | Grace period (seconds) |
|
||||
|
||||
### Monitoring
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| `kind_24567_reporting_throttle_sec` | integer | 5 | Monitoring event throttle |
|
||||
|
||||
### Dynamic vs Restart-Required
|
||||
|
||||
**Dynamic (No Restart)**:
|
||||
- All NIP-11 relay information
|
||||
- Authentication settings
|
||||
- Subscription limits
|
||||
- Event validation limits
|
||||
- Proof of Work settings
|
||||
- Expiration settings
|
||||
|
||||
**Restart Required**:
|
||||
- `max_connections`
|
||||
- `relay_port`
|
||||
- Database settings
|
||||
|
||||
## Real-time Monitoring
|
||||
|
||||
C-Relay-PG provides subscription-based real-time monitoring using ephemeral events (kind 24567).
|
||||
|
||||
### Activation
|
||||
|
||||
Subscribe to kind 24567 events to activate monitoring:
|
||||
|
||||
```json
|
||||
["REQ", "monitoring-sub", {"kinds": [24567]}]
|
||||
```
|
||||
|
||||
### Monitoring Event Types
|
||||
|
||||
Subscribe to specific monitoring types using d-tag filters:
|
||||
|
||||
```json
|
||||
["REQ", "event-kinds", {"kinds": [24567], "#d": ["event_kinds"]}]
|
||||
["REQ", "time-stats", {"kinds": [24567], "#d": ["time_stats"]}]
|
||||
["REQ", "top-pubkeys", {"kinds": [24567], "#d": ["top_pubkeys"]}]
|
||||
["REQ", "cpu-metrics", {"kinds": [24567], "#d": ["cpu_metrics"]}]
|
||||
```
|
||||
|
||||
### Event Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 24567,
|
||||
"pubkey": "relay_pubkey",
|
||||
"created_at": 1234567890,
|
||||
"content": "{\"data_type\":\"event_kinds\",\"timestamp\":1234567890,...}",
|
||||
"tags": [
|
||||
["d", "event_kinds"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Monitoring Types
|
||||
|
||||
#### Event Distribution (`event_kinds`)
|
||||
|
||||
```json
|
||||
{
|
||||
"data_type": "event_kinds",
|
||||
"timestamp": 1234567890,
|
||||
"total_events": 15432,
|
||||
"kinds": [
|
||||
{"kind": 1, "count": 12000, "percentage": 77.8},
|
||||
{"kind": 0, "count": 2500, "percentage": 16.2}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Time Statistics (`time_stats`)
|
||||
|
||||
```json
|
||||
{
|
||||
"data_type": "time_stats",
|
||||
"timestamp": 1234567890,
|
||||
"total_events": 15432,
|
||||
"last_24h": 234,
|
||||
"last_7d": 1456,
|
||||
"last_30d": 5432
|
||||
}
|
||||
```
|
||||
|
||||
#### Top Publishers (`top_pubkeys`)
|
||||
|
||||
```json
|
||||
{
|
||||
"data_type": "top_pubkeys",
|
||||
"timestamp": 1234567890,
|
||||
"top_pubkeys": [
|
||||
{"pubkey": "abc123...", "count": 1234, "percentage": 8.0},
|
||||
{"pubkey": "def456...", "count": 987, "percentage": 6.4}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### CPU Metrics (`cpu_metrics`)
|
||||
|
||||
```json
|
||||
{
|
||||
"data_type": "cpu_metrics",
|
||||
"timestamp": 1234567890,
|
||||
"cpu_percent": 12.5,
|
||||
"memory_mb": 45.2,
|
||||
"uptime_seconds": 86400
|
||||
}
|
||||
```
|
||||
|
||||
#### Active Subscriptions (`active_subscriptions`) - Admin Only
|
||||
|
||||
```json
|
||||
{
|
||||
"data_type": "active_subscriptions",
|
||||
"timestamp": 1234567890,
|
||||
"total_subscriptions": 156,
|
||||
"subscriptions_by_client": [
|
||||
{"client_id": "client1", "count": 12},
|
||||
{"client_id": "client2", "count": 8}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
Control monitoring frequency:
|
||||
|
||||
```json
|
||||
["config_update", [{
|
||||
"key": "kind_24567_reporting_throttle_sec",
|
||||
"value": "10",
|
||||
"data_type": "integer",
|
||||
"category": "monitoring"
|
||||
}]]
|
||||
```
|
||||
|
||||
### Performance
|
||||
|
||||
- Events are ephemeral (not stored)
|
||||
- Automatic activation/deactivation based on subscriptions
|
||||
- Throttling prevents excessive event generation
|
||||
- Minimal overhead when no clients monitoring
|
||||
|
||||
## Direct Message Admin
|
||||
|
||||
Control your relay by sending direct messages from any Nostr client.
|
||||
|
||||
### Setup
|
||||
|
||||
1. The relay has its own keypair (shown on startup)
|
||||
2. The relay knows the admin public key
|
||||
3. Send NIP-17 direct messages to the relay
|
||||
|
||||
### Available Commands
|
||||
|
||||
Send a DM containing any of these keywords:
|
||||
|
||||
| Command | Aliases | Response |
|
||||
|---------|---------|----------|
|
||||
| Statistics | stats, statistics | Database statistics |
|
||||
| Configuration | config, configuration | Current configuration |
|
||||
|
||||
### Example
|
||||
|
||||
Using any Nostr client that supports NIP-17:
|
||||
|
||||
1. Find the relay's public key (shown on startup)
|
||||
2. Send a DM: "stats"
|
||||
3. Receive a DM with current relay statistics
|
||||
|
||||
### Response Format
|
||||
|
||||
The relay responds with a NIP-17 DM containing:
|
||||
|
||||
**Stats Response**:
|
||||
```
|
||||
Relay Statistics
|
||||
================
|
||||
Total Events: 15,432
|
||||
Database Size: 10.5 MB
|
||||
Active Connections: 42
|
||||
Active Subscriptions: 156
|
||||
Uptime: 1 day, 2 hours
|
||||
```
|
||||
|
||||
**Config Response**:
|
||||
```
|
||||
Relay Configuration
|
||||
===================
|
||||
Name: My Awesome Relay
|
||||
Description: Community relay
|
||||
Max Subscriptions: 25
|
||||
Auth Enabled: false
|
||||
PoW Difficulty: 0
|
||||
```
|
||||
|
||||
## Response Formats
|
||||
|
||||
### Success Response
|
||||
|
||||
```json
|
||||
{
|
||||
"query_type": "command_name",
|
||||
"status": "success",
|
||||
"message": "Operation completed successfully",
|
||||
"timestamp": 1234567890,
|
||||
"data": [...]
|
||||
}
|
||||
```
|
||||
|
||||
### Error Response
|
||||
|
||||
```json
|
||||
{
|
||||
"query_type": "command_name",
|
||||
"status": "error",
|
||||
"error": "Error description",
|
||||
"timestamp": 1234567890
|
||||
}
|
||||
```
|
||||
|
||||
### Query Response
|
||||
|
||||
```json
|
||||
{
|
||||
"query_type": "query_name",
|
||||
"total_results": 10,
|
||||
"timestamp": 1234567890,
|
||||
"data": [...]
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors
|
||||
|
||||
| Error | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| `invalid_signature` | Event signature invalid | Check admin private key |
|
||||
| `unauthorized` | Wrong admin pubkey | Use correct admin key |
|
||||
| `invalid_command` | Unknown command | Check command format |
|
||||
| `validation_failed` | Invalid parameter value | Check parameter ranges |
|
||||
| `database_error` | Database operation failed | Check database integrity |
|
||||
| `timeout` | Query took too long | Simplify query or increase timeout |
|
||||
|
||||
### Error Response Example
|
||||
|
||||
```json
|
||||
{
|
||||
"query_type": "config_update",
|
||||
"status": "error",
|
||||
"error": "field validation failed: invalid port number '99999' (must be 1-65535)",
|
||||
"timestamp": 1234567890
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### JavaScript/TypeScript Example
|
||||
|
||||
```javascript
|
||||
import { SimplePool, nip44, getPublicKey, finalizeEvent } from 'nostr-tools';
|
||||
|
||||
const adminPrivkey = 'your_admin_privkey_hex';
|
||||
const adminPubkey = getPublicKey(adminPrivkey);
|
||||
const relayPubkey = 'relay_pubkey_hex';
|
||||
const relayUrl = 'ws://localhost:8888';
|
||||
|
||||
// Create admin command
|
||||
async function sendAdminCommand(command) {
|
||||
const pool = new SimplePool();
|
||||
|
||||
// Encrypt command with NIP-44
|
||||
const encryptedContent = await nip44.encrypt(
|
||||
adminPrivkey,
|
||||
relayPubkey,
|
||||
JSON.stringify(command)
|
||||
);
|
||||
|
||||
// Create event
|
||||
const event = finalizeEvent({
|
||||
kind: 23456,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
tags: [['p', relayPubkey]],
|
||||
content: encryptedContent
|
||||
}, adminPrivkey);
|
||||
|
||||
// Publish event
|
||||
await pool.publish([relayUrl], event);
|
||||
|
||||
// Subscribe to response
|
||||
const sub = pool.sub([relayUrl], [{
|
||||
kinds: [23457],
|
||||
'#p': [adminPubkey],
|
||||
since: Math.floor(Date.now() / 1000)
|
||||
}]);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
sub.on('event', async (event) => {
|
||||
// Decrypt response
|
||||
const decrypted = await nip44.decrypt(
|
||||
adminPrivkey,
|
||||
relayPubkey,
|
||||
event.content
|
||||
);
|
||||
resolve(JSON.parse(decrypted));
|
||||
sub.unsub();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Query configuration
|
||||
const config = await sendAdminCommand(['config_query', 'all']);
|
||||
console.log(config);
|
||||
|
||||
// Update configuration
|
||||
const result = await sendAdminCommand(['config_update', [
|
||||
{
|
||||
key: 'relay_name',
|
||||
value: 'My Relay',
|
||||
data_type: 'string',
|
||||
category: 'relay'
|
||||
}
|
||||
]]);
|
||||
console.log(result);
|
||||
|
||||
// Add blacklist rule
|
||||
const blacklist = await sendAdminCommand([
|
||||
'blacklist',
|
||||
'pubkey',
|
||||
'abc123...'
|
||||
]);
|
||||
console.log(blacklist);
|
||||
|
||||
// Execute SQL query
|
||||
const query = await sendAdminCommand([
|
||||
'sql_query',
|
||||
'SELECT * FROM events ORDER BY created_at DESC LIMIT 10'
|
||||
]);
|
||||
console.log(query);
|
||||
```
|
||||
|
||||
### Python Example
|
||||
|
||||
```python
|
||||
from nostr_sdk import Keys, Client, EventBuilder, Filter, nip44
|
||||
|
||||
admin_privkey = "your_admin_privkey_hex"
|
||||
relay_pubkey = "relay_pubkey_hex"
|
||||
relay_url = "ws://localhost:8888"
|
||||
|
||||
# Initialize
|
||||
keys = Keys.parse(admin_privkey)
|
||||
client = Client(keys)
|
||||
client.add_relay(relay_url)
|
||||
client.connect()
|
||||
|
||||
# Send admin command
|
||||
async def send_admin_command(command):
|
||||
# Encrypt command
|
||||
encrypted = nip44.encrypt(
|
||||
keys.secret_key(),
|
||||
relay_pubkey,
|
||||
json.dumps(command)
|
||||
)
|
||||
|
||||
# Create event
|
||||
event = EventBuilder.new(
|
||||
kind=23456,
|
||||
content=encrypted,
|
||||
tags=[["p", relay_pubkey]]
|
||||
).to_event(keys)
|
||||
|
||||
# Publish
|
||||
await client.send_event(event)
|
||||
|
||||
# Wait for response
|
||||
filter = Filter().kind(23457).pubkey(relay_pubkey).since(int(time.time()))
|
||||
events = await client.get_events_of([filter], timeout=5)
|
||||
|
||||
if events:
|
||||
# Decrypt response
|
||||
decrypted = nip44.decrypt(
|
||||
keys.secret_key(),
|
||||
relay_pubkey,
|
||||
events[0].content()
|
||||
)
|
||||
return json.loads(decrypted)
|
||||
|
||||
# Query configuration
|
||||
config = await send_admin_command(["config_query", "all"])
|
||||
print(config)
|
||||
```
|
||||
|
||||
### Bash/curl Example
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Note: This is a simplified example. Real implementation requires:
|
||||
# - NIP-44 encryption
|
||||
# - Event signing
|
||||
# - WebSocket connection
|
||||
|
||||
RELAY_URL="ws://localhost:8888"
|
||||
ADMIN_PRIVKEY="your_admin_privkey"
|
||||
RELAY_PUBKEY="relay_pubkey"
|
||||
|
||||
# Use nostrtool or similar for proper event creation
|
||||
nostrtool event \
|
||||
--kind 23456 \
|
||||
--content "$(echo '["config_query","all"]' | nip44-encrypt)" \
|
||||
--tag p "$RELAY_PUBKEY" \
|
||||
--private-key "$ADMIN_PRIVKEY" \
|
||||
| nostrtool send "$RELAY_URL"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- **[Configuration Guide](docs/configuration_guide.md)** - Detailed configuration options
|
||||
- **[Deployment Guide](docs/deployment_guide.md)** - Production deployment
|
||||
- **[NIP-42 Authentication](docs/NIP-42_Authentication.md)** - Authentication setup
|
||||
- **[User Guide](docs/user_guide.md)** - End-user documentation
|
||||
|
||||
## Support
|
||||
|
||||
For API questions or issues:
|
||||
- Open an issue on GitHub
|
||||
- Check existing documentation
|
||||
- Join the Nostr community
|
||||
|
||||
---
|
||||
|
||||
**API Version**: 0.6.0
|
||||
**Last Updated**: 2026-01-23
|
||||
+57
-29
@@ -1,8 +1,14 @@
|
||||
# Alpine-based MUSL static binary builder for C-Relay
|
||||
# Alpine-based MUSL static binary builder for C-Relay-PG
|
||||
# Produces truly portable binaries with zero runtime dependencies
|
||||
# PostgreSQL backend only.
|
||||
|
||||
ARG DEBUG_BUILD=false
|
||||
|
||||
FROM alpine:3.19 AS builder
|
||||
|
||||
# Re-declare build arguments in this stage
|
||||
ARG DEBUG_BUILD=false
|
||||
|
||||
# Install build dependencies
|
||||
RUN apk add --no-cache \
|
||||
build-base \
|
||||
@@ -21,9 +27,11 @@ RUN apk add --no-cache \
|
||||
curl-static \
|
||||
sqlite-dev \
|
||||
sqlite-static \
|
||||
postgresql-dev \
|
||||
linux-headers \
|
||||
wget \
|
||||
bash
|
||||
bash \
|
||||
openssh-client
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /build
|
||||
@@ -63,57 +71,77 @@ RUN cd /tmp && \
|
||||
make install && \
|
||||
rm -rf /tmp/libwebsockets
|
||||
|
||||
# Copy only submodule configuration and git directory
|
||||
COPY .gitmodules /build/.gitmodules
|
||||
COPY .git /build/.git
|
||||
|
||||
# Clean up any stale submodule references (nips directory is not a submodule)
|
||||
RUN git rm --cached nips 2>/dev/null || true
|
||||
|
||||
# Initialize submodules (cached unless .gitmodules changes)
|
||||
RUN git submodule update --init --recursive
|
||||
# Submodules are provided in the local build context and copied explicitly below.
|
||||
# Avoid network/SSH dependency inside Docker image build.
|
||||
|
||||
# Copy nostr_core_lib source files (cached unless nostr_core_lib changes)
|
||||
COPY nostr_core_lib /build/nostr_core_lib/
|
||||
|
||||
# Copy c_utils_lib source files (cached unless c_utils_lib changes)
|
||||
COPY c_utils_lib /build/c_utils_lib/
|
||||
|
||||
# Build c_utils_lib static library for relay logging utilities
|
||||
# (build only debug.c to avoid broken/missing version header surface in submodule revision)
|
||||
RUN cd c_utils_lib && \
|
||||
mkdir -p build && \
|
||||
gcc -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -Wall -Wextra -std=c99 -O2 -g \
|
||||
-Isrc -Iinclude -c src/debug.c -o build/debug.o && \
|
||||
ar rcs libc_utils.a build/debug.o
|
||||
|
||||
# Build nostr_core_lib with required NIPs (cached unless nostr_core_lib changes)
|
||||
# Disable fortification in build.sh to prevent __*_chk symbol issues
|
||||
# NIPs: 001(Basic), 006(Keys), 013(PoW), 017(DMs), 019(Bech32), 044(Encryption), 059(Gift Wrap - required by NIP-17)
|
||||
# NIPs: 001(Basic), 004(Encryption), 006(Keys), 013(PoW), 017(DMs), 019(Bech32), 044(Encryption), 059(Gift Wrap - required by NIP-17)
|
||||
# NIP-04 is required by nostr_signer.c (NIP-46 bunker signer uses NIP-04 encryption)
|
||||
RUN cd nostr_core_lib && \
|
||||
chmod +x build.sh && \
|
||||
sed -i 's/CFLAGS="-Wall -Wextra -std=c99 -fPIC -O2"/CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -Wall -Wextra -std=c99 -fPIC -O2"/' build.sh && \
|
||||
rm -f *.o *.a 2>/dev/null || true && \
|
||||
./build.sh --nips=1,6,13,17,19,44,59
|
||||
./build.sh --nips=1,4,6,13,17,19,44,59
|
||||
|
||||
# Copy c-relay source files LAST (only this layer rebuilds on source changes)
|
||||
# Copy c-relay-pg source files LAST (only this layer rebuilds on source changes)
|
||||
COPY src/ /build/src/
|
||||
COPY Makefile /build/Makefile
|
||||
|
||||
# Build c-relay with full static linking (only rebuilds when src/ changes)
|
||||
# Build c-relay-pg with full static linking (only rebuilds when src/ changes)
|
||||
# Disable fortification to avoid __*_chk symbols that don't exist in MUSL
|
||||
RUN gcc -static -O2 -Wall -Wextra -std=c99 \
|
||||
# Use conditional compilation flags based on DEBUG_BUILD build arg.
|
||||
# PostgreSQL backend is always used.
|
||||
RUN if [ "$DEBUG_BUILD" = "true" ]; then \
|
||||
CFLAGS="-g -O2 -DDEBUG"; \
|
||||
STRIP_CMD="echo 'Keeping debug symbols'"; \
|
||||
echo "Building with DEBUG symbols enabled (optimized with -O2)"; \
|
||||
else \
|
||||
CFLAGS="-O2"; \
|
||||
STRIP_CMD="strip /build/c_relay_pg_static"; \
|
||||
echo "Building optimized production binary (symbols stripped)"; \
|
||||
fi && \
|
||||
DB_FLAGS="-DDB_BACKEND_POSTGRES -DHAVE_LIBPQ" && \
|
||||
DB_LIBS="-lpq -lpgcommon -lpgport" && \
|
||||
echo "Compiling with PostgreSQL backend" && \
|
||||
gcc -static $CFLAGS $DB_FLAGS -Wall -Wextra -std=c99 \
|
||||
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \
|
||||
-I. -Inostr_core_lib -Inostr_core_lib/nostr_core \
|
||||
-Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket \
|
||||
-I. -Ic_utils_lib/src -Inostr_core_lib -Inostr_core_lib/nostr_core \
|
||||
-Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket -I/usr/include/postgresql \
|
||||
src/main.c src/config.c src/dm_admin.c src/request_validator.c \
|
||||
src/nip009.c src/nip011.c src/nip013.c src/nip040.c src/nip042.c \
|
||||
src/websockets.c src/subscriptions.c src/api.c src/embedded_web_content.c \
|
||||
-o /build/c_relay_static \
|
||||
src/websockets.c src/subscriptions.c src/api.c src/embedded_web_content.c src/ip_ban.c \
|
||||
src/caching_inbox_poller.c src/caching_service_launcher.c \
|
||||
src/db_ops.c src/db_ops_postgres.c src/thread_pool.c \
|
||||
-o /build/c_relay_pg_static \
|
||||
c_utils_lib/libc_utils.a \
|
||||
nostr_core_lib/libnostr_core_x64.a \
|
||||
-lwebsockets -lssl -lcrypto -lsqlite3 -lsecp256k1 \
|
||||
-lcurl -lz -lpthread -lm -ldl
|
||||
|
||||
# Strip binary to reduce size
|
||||
RUN strip /build/c_relay_static
|
||||
-lwebsockets -lssl -lcrypto -lsecp256k1 \
|
||||
-lcurl -lz -lpthread -lm -ldl $DB_LIBS && \
|
||||
eval "$STRIP_CMD"
|
||||
|
||||
# Verify it's truly static
|
||||
RUN echo "=== Binary Information ===" && \
|
||||
file /build/c_relay_static && \
|
||||
ls -lh /build/c_relay_static && \
|
||||
file /build/c_relay_pg_static && \
|
||||
ls -lh /build/c_relay_pg_static && \
|
||||
echo "=== Checking for dynamic dependencies ===" && \
|
||||
(ldd /build/c_relay_static 2>&1 || echo "Binary is static") && \
|
||||
(ldd /build/c_relay_pg_static 2>&1 || echo "Binary is static") && \
|
||||
echo "=== Build complete ==="
|
||||
|
||||
# Output stage - just the binary
|
||||
FROM scratch AS output
|
||||
COPY --from=builder /build/c_relay_static /c_relay_static
|
||||
COPY --from=builder /build/c_relay_pg_static /c_relay_pg_static
|
||||
|
||||
@@ -1,40 +1,72 @@
|
||||
# C-Relay Makefile
|
||||
# C-Relay-PG Makefile
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -std=c99 -g -O2
|
||||
INCLUDES = -I. -Inostr_core_lib -Inostr_core_lib/nostr_core -Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket
|
||||
LIBS = -lsqlite3 -lwebsockets -lz -ldl -lpthread -lm -L/usr/local/lib -lsecp256k1 -lssl -lcrypto -L/usr/local/lib -lcurl
|
||||
CFLAGS = -Wall -Wextra -std=c99 -g -O2 -DDB_BACKEND_POSTGRES -DHAVE_LIBPQ
|
||||
INCLUDES = -I. -Ic_utils_lib/src -Inostr_core_lib -Inostr_core_lib/nostr_core -Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket -I/usr/include/postgresql
|
||||
LIBS = -lwebsockets -lz -ldl -lpthread -lm -L/usr/local/lib -lsecp256k1 -lssl -lcrypto -L/usr/local/lib -lcurl -Lc_utils_lib -lc_utils -lpq
|
||||
|
||||
# Build directory
|
||||
BUILD_DIR = build
|
||||
|
||||
# Source files
|
||||
MAIN_SRC = src/main.c src/config.c src/dm_admin.c src/request_validator.c src/nip009.c src/nip011.c src/nip013.c src/nip040.c src/nip042.c src/websockets.c src/subscriptions.c src/api.c src/embedded_web_content.c
|
||||
MAIN_SRC = src/main.c src/config.c src/dm_admin.c src/request_validator.c src/nip009.c src/nip011.c src/nip013.c src/nip040.c src/nip042.c src/websockets.c src/subscriptions.c src/api.c src/embedded_web_content.c src/ip_ban.c src/thread_pool.c src/caching_inbox_poller.c src/caching_service_launcher.c
|
||||
DB_OPS_SRC = src/db_ops.c src/db_ops_postgres.c
|
||||
|
||||
NOSTR_CORE_LIB = nostr_core_lib/libnostr_core_x64.a
|
||||
C_UTILS_LIB = c_utils_lib/libc_utils.a
|
||||
|
||||
# Architecture detection
|
||||
ARCH = $(shell uname -m)
|
||||
ifeq ($(ARCH),x86_64)
|
||||
TARGET = $(BUILD_DIR)/c_relay_x86
|
||||
TARGET = $(BUILD_DIR)/c_relay_pg_x86
|
||||
else ifeq ($(ARCH),aarch64)
|
||||
TARGET = $(BUILD_DIR)/c_relay_arm64
|
||||
TARGET = $(BUILD_DIR)/c_relay_pg_arm64
|
||||
else ifeq ($(ARCH),arm64)
|
||||
TARGET = $(BUILD_DIR)/c_relay_arm64
|
||||
TARGET = $(BUILD_DIR)/c_relay_pg_arm64
|
||||
else
|
||||
TARGET = $(BUILD_DIR)/c_relay_$(ARCH)
|
||||
TARGET = $(BUILD_DIR)/c_relay_pg_$(ARCH)
|
||||
endif
|
||||
|
||||
# Default target
|
||||
all: $(TARGET)
|
||||
# Default target — refuse direct build, instruct to use build_static.sh
|
||||
# The Makefile is only for submodule builds (nostr_core_lib, c_utils_lib)
|
||||
# and utility targets (clean, install-deps, etc.).
|
||||
# Running 'make' directly produces a dynamically-linked binary that will
|
||||
# silently fall back to SQLite storage while the admin UI connects to
|
||||
# PostgreSQL — causing the admin page to show stale data.
|
||||
all:
|
||||
@echo "============================================"
|
||||
@echo " ERROR: Do not run 'make' directly!"
|
||||
@echo ""
|
||||
@echo " This project requires a static MUSL build"
|
||||
@echo " with PostgreSQL backend. Run:"
|
||||
@echo ""
|
||||
@echo " ./build_static.sh"
|
||||
@echo ""
|
||||
@echo " Or use the full build+restart script:"
|
||||
@echo ""
|
||||
@echo " ./make_and_restart_relay.sh"
|
||||
@echo ""
|
||||
@echo " The Makefile is only for submodule builds"
|
||||
@echo " (nostr_core_lib, c_utils_lib) and utility"
|
||||
@echo " targets (clean, install-deps, etc.)."
|
||||
@echo "============================================"
|
||||
@exit 1
|
||||
|
||||
# Create build directory
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
|
||||
# Check if nostr_core_lib is built
|
||||
# Explicitly specify NIPs to ensure NIP-44 (encryption) is included
|
||||
# NIPs: 1 (basic), 6 (keys), 13 (PoW), 17 (DMs), 19 (bech32), 44 (encryption), 59 (gift wrap)
|
||||
$(NOSTR_CORE_LIB):
|
||||
@echo "Building nostr_core_lib..."
|
||||
cd nostr_core_lib && ./build.sh
|
||||
@echo "Building nostr_core_lib with required NIPs (including NIP-44 for encryption)..."
|
||||
cd nostr_core_lib && ./build.sh --nips=1,6,13,17,19,44,59
|
||||
|
||||
# Check if c_utils_lib is built
|
||||
$(C_UTILS_LIB):
|
||||
@echo "Building c_utils_lib..."
|
||||
cd c_utils_lib && ./build.sh lib
|
||||
|
||||
# Update main.h version information (requires main.h to exist)
|
||||
src/main.h:
|
||||
@@ -72,146 +104,75 @@ force-version:
|
||||
@echo "Force updating main.h version information..."
|
||||
@$(MAKE) src/main.h
|
||||
|
||||
# Build the relay
|
||||
$(TARGET): $(BUILD_DIR) src/main.h src/sql_schema.h $(MAIN_SRC) $(NOSTR_CORE_LIB)
|
||||
@echo "Compiling C-Relay for architecture: $(ARCH)"
|
||||
$(CC) $(CFLAGS) $(INCLUDES) $(MAIN_SRC) -o $(TARGET) $(NOSTR_CORE_LIB) $(LIBS)
|
||||
@echo "Build complete: $(TARGET)"
|
||||
# Build the relay — guarded to prevent accidental use.
|
||||
# Use ./build_static.sh instead.
|
||||
$(TARGET):
|
||||
@echo "ERROR: Do not run 'make $(TARGET)' directly."
|
||||
@echo "Use ./build_static.sh to build the static MUSL binary."
|
||||
@exit 1
|
||||
|
||||
# Build for specific architectures
|
||||
x86: $(BUILD_DIR) src/main.h src/sql_schema.h $(MAIN_SRC) $(NOSTR_CORE_LIB)
|
||||
@echo "Building C-Relay for x86_64..."
|
||||
$(CC) $(CFLAGS) $(INCLUDES) $(MAIN_SRC) -o $(BUILD_DIR)/c_relay_x86 $(NOSTR_CORE_LIB) $(LIBS)
|
||||
@echo "Build complete: $(BUILD_DIR)/c_relay_x86"
|
||||
x86:
|
||||
@echo "ERROR: Do not run 'make x86' directly."
|
||||
@echo "Use ./build_static.sh to build the static MUSL binary."
|
||||
@exit 1
|
||||
|
||||
arm64: $(BUILD_DIR) src/main.h src/sql_schema.h $(MAIN_SRC) $(NOSTR_CORE_LIB)
|
||||
@echo "Cross-compiling C-Relay for ARM64..."
|
||||
arm64:
|
||||
@echo "ERROR: Do not run 'make arm64' directly."
|
||||
@echo "Use ./build_static.sh to build the static MUSL binary."
|
||||
@exit 1
|
||||
@if ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then \
|
||||
echo "ERROR: ARM64 cross-compiler not found."; \
|
||||
echo "Install with: make install-cross-tools"; \
|
||||
echo "Or install manually: sudo apt install gcc-aarch64-linux-gnu"; \
|
||||
echo "ERROR: aarch64-linux-gnu-gcc not found."; \
|
||||
echo "Install the ARM64 cross-compiler:"; \
|
||||
echo " sudo apt install gcc-aarch64-linux-gnu"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "Checking for ARM64 development libraries..."
|
||||
@if ! dpkg -l | grep -q "libssl-dev:arm64\|libsqlite3-dev:arm64"; then \
|
||||
@if ! dpkg -l | grep -q "libssl-dev:arm64\|libpq-dev:arm64"; then \
|
||||
echo "ERROR: ARM64 libraries not found. Cross-compilation requires ARM64 versions of:"; \
|
||||
echo " - libssl-dev:arm64"; \
|
||||
echo " - libsqlite3-dev:arm64"; \
|
||||
echo " - libpq-dev:arm64"; \
|
||||
echo " - libwebsockets-dev:arm64"; \
|
||||
echo " - libsecp256k1-dev:arm64"; \
|
||||
echo " - zlib1g-dev:arm64"; \
|
||||
echo " - libcurl4-openssl-dev:arm64"; \
|
||||
echo " - libcurl-dev:arm64"; \
|
||||
echo ""; \
|
||||
echo "Install ARM64 libraries with: make install-arm64-deps"; \
|
||||
echo "Or use Docker for cross-platform builds."; \
|
||||
echo "Install them with:"; \
|
||||
echo " sudo dpkg --add-architecture arm64"; \
|
||||
echo " sudo apt update"; \
|
||||
echo " sudo apt install gcc-aarch64-linux-gnu \\"; \
|
||||
echo " libssl-dev:arm64 libpq-dev:arm64 \\"; \
|
||||
echo " libwebsockets-dev:arm64 zlib1g-dev:arm64 \\"; \
|
||||
echo " libcurl4-openssl-dev:arm64"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "Using aarch64-linux-gnu-gcc with ARM64 libraries..."
|
||||
PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig \
|
||||
aarch64-linux-gnu-gcc $(CFLAGS) $(INCLUDES) $(MAIN_SRC) -o $(BUILD_DIR)/c_relay_arm64 $(NOSTR_CORE_LIB) \
|
||||
-L/usr/lib/aarch64-linux-gnu $(LIBS)
|
||||
@echo "Build complete: $(BUILD_DIR)/c_relay_arm64"
|
||||
fi; \
|
||||
PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig \
|
||||
PKG_CONFIG_SYSROOT_DIR=/ \
|
||||
aarch64-linux-gnu-gcc -Wall -Wextra -std=c99 -g -O2 \
|
||||
-DDB_BACKEND_POSTGRES -DHAVE_LIBPQ \
|
||||
-I. -Ic_utils_lib/src -Inostr_core_lib -Inostr_core_lib/nostr_core \
|
||||
-Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket \
|
||||
$(MAIN_SRC) $(DB_OPS_SRC) \
|
||||
-o $(BUILD_DIR)/c_relay_pg_arm64 \
|
||||
$(NOSTR_CORE_LIB) $(C_UTILS_LIB) \
|
||||
-lwebsockets -lssl -lcrypto -lz -ldl -lpthread -lm \
|
||||
-lsecp256k1 -lcurl -lpq
|
||||
@echo "Cross-compilation complete: $(BUILD_DIR)/c_relay_pg_arm64"
|
||||
|
||||
# Install ARM64 cross-compilation dependencies
|
||||
# Install dependencies for ARM64 cross-compilation
|
||||
install-arm64-deps:
|
||||
@echo "Installing ARM64 cross-compilation dependencies..."
|
||||
@echo "This requires adding ARM64 architecture and installing cross-libraries..."
|
||||
sudo dpkg --add-architecture arm64
|
||||
sudo apt update
|
||||
sudo apt install -y \
|
||||
gcc-aarch64-linux-gnu \
|
||||
libc6-dev-arm64-cross \
|
||||
libssl-dev:arm64 \
|
||||
libsqlite3-dev:arm64 \
|
||||
zlib1g-dev:arm64 \
|
||||
sudo apt install -y gcc-aarch64-linux-gnu \
|
||||
libssl-dev:arm64 libpq-dev:arm64 \
|
||||
libwebsockets-dev:arm64 zlib1g-dev:arm64 \
|
||||
libcurl4-openssl-dev:arm64
|
||||
@echo "Note: libwebsockets-dev:arm64 and libsecp256k1-dev:arm64 may need manual building"
|
||||
|
||||
# Install cross-compilation tools
|
||||
install-cross-tools:
|
||||
@echo "Installing cross-compilation tools..."
|
||||
# Install dependencies for native build
|
||||
install-deps:
|
||||
sudo apt update
|
||||
sudo apt install -y gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||
|
||||
# Check what architectures we can actually build
|
||||
check-toolchain:
|
||||
@echo "Checking available toolchains:"
|
||||
@echo "Native compiler: $(shell $(CC) --version | head -1)"
|
||||
@if command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then \
|
||||
echo "ARM64 cross-compiler: $(shell aarch64-linux-gnu-gcc --version | head -1)"; \
|
||||
else \
|
||||
echo "ARM64 cross-compiler: NOT INSTALLED (install with 'make install-cross-tools')"; \
|
||||
fi
|
||||
|
||||
# Run tests
|
||||
test: $(TARGET)
|
||||
@echo "Running tests..."
|
||||
./tests/1_nip_test.sh
|
||||
|
||||
# Initialize database (now handled automatically when server starts)
|
||||
init-db:
|
||||
@echo "Database initialization is now handled automatically when the server starts."
|
||||
@echo "The schema is embedded in the binary - no external files needed."
|
||||
@echo "To manually recreate database: rm -f db/c_nostr_relay.db && ./build/c_relay_x86"
|
||||
sudo apt install -y build-essential libpq-dev libssl-dev libcurl4-openssl-dev libsecp256k1-dev zlib1g-dev jq curl
|
||||
|
||||
# Clean build artifacts
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR)
|
||||
@echo "Clean complete"
|
||||
|
||||
# Clean everything including nostr_core_lib
|
||||
clean-all: clean
|
||||
cd nostr_core_lib && make clean 2>/dev/null || true
|
||||
|
||||
# Install dependencies (Ubuntu/Debian)
|
||||
install-deps:
|
||||
@echo "Installing dependencies..."
|
||||
sudo apt update
|
||||
sudo apt install -y build-essential libsqlite3-dev libssl-dev libcurl4-openssl-dev libsecp256k1-dev zlib1g-dev jq curl
|
||||
|
||||
# Help
|
||||
help:
|
||||
@echo "C-Relay Build System"
|
||||
@echo ""
|
||||
@echo "Targets:"
|
||||
@echo " all Build the relay for current architecture (default)"
|
||||
@echo " x86 Build specifically for x86_64"
|
||||
@echo " arm64 Build for ARM64 (requires cross-compilation setup)"
|
||||
@echo " test Build and run tests"
|
||||
@echo " init-db Initialize the database"
|
||||
@echo " clean Clean build artifacts"
|
||||
@echo " clean-all Clean everything including dependencies"
|
||||
@echo " install-deps Install system dependencies"
|
||||
@echo " install-cross-tools Install basic ARM64 cross-compiler"
|
||||
@echo " install-arm64-deps Install ARM64 cross-compilation libraries"
|
||||
@echo " check-toolchain Check available compilers"
|
||||
@echo " help Show this help"
|
||||
@echo ""
|
||||
@echo "Usage:"
|
||||
@echo " make # Build the relay for current arch"
|
||||
@echo " make x86 # Build for x86_64"
|
||||
@echo " make arm64 # Build for ARM64 (fails if cross-compilation not set up)"
|
||||
@echo " make install-arm64-deps # Install full ARM64 cross-compilation setup"
|
||||
@echo " make check-toolchain # Check what compilers are available"
|
||||
@echo " make test # Run tests"
|
||||
@echo " make init-db # Set up database"
|
||||
@echo " make force-version # Force regenerate main.h from git"
|
||||
|
||||
# Build fully static MUSL binaries using Docker
|
||||
static-musl-x86_64:
|
||||
@echo "Building fully static MUSL binary for x86_64..."
|
||||
docker buildx build --platform linux/amd64 -f examples/deployment/static-builder.Dockerfile -t c-relay-static-builder-x86_64 --load .
|
||||
docker run --rm -v $(PWD)/build:/output c-relay-static-builder-x86_64 sh -c "cp /c_relay_static_musl_x86_64 /output/"
|
||||
@echo "Static binary created: build/c_relay_static_musl_x86_64"
|
||||
|
||||
static-musl-arm64:
|
||||
@echo "Building fully static MUSL binary for ARM64..."
|
||||
docker buildx build --platform linux/arm64 -f examples/deployment/static-builder.Dockerfile -t c-relay-static-builder-arm64 --load .
|
||||
docker run --rm -v $(PWD)/build:/output c-relay-static-builder-arm64 sh -c "cp /c_relay_static_musl_x86_64 /output/c_relay_static_musl_arm64"
|
||||
@echo "Static binary created: build/c_relay_static_musl_arm64"
|
||||
|
||||
static-musl: static-musl-x86_64 static-musl-arm64
|
||||
@echo "Built static MUSL binaries for both architectures"
|
||||
|
||||
.PHONY: static-musl-x86_64 static-musl-arm64 static-musl
|
||||
.PHONY: all x86 arm64 test init-db clean clean-all install-deps install-cross-tools install-arm64-deps check-toolchain help force-version
|
||||
.PHONY: all x86 arm64 install-arm64-deps install-deps clean force-version
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# Relay
|
||||
|
||||
I am releasing the code for the nostr relay that I wrote use myself. The code is free for anyone to use in any way that they wish.
|
||||
|
||||
Some of the features of this relay are conventional, and some are unconventional.
|
||||
|
||||
## The conventional
|
||||
|
||||
This relay is written in C99 with a sqlite database.
|
||||
|
||||
It implements the following NIPs.
|
||||
|
||||
- [x] NIP-01: Basic protocol flow implementation
|
||||
- [x] NIP-09: Event deletion
|
||||
- [x] NIP-11: Relay information document
|
||||
- [x] NIP-13: Proof of Work
|
||||
- [x] NIP-15: End of Stored Events Notice
|
||||
- [x] NIP-20: Command Results
|
||||
- [x] NIP-33: Parameterized Replaceable Events
|
||||
- [x] NIP-40: Expiration Timestamp
|
||||
- [x] NIP-42: Authentication of clients to relays
|
||||
- [x] NIP-45: Counting results
|
||||
- [x] NIP-50: Keywords filter
|
||||
- [x] NIP-70: Protected Events
|
||||
|
||||
## The unconventional
|
||||
|
||||
### The binaries are fully self contained.
|
||||
|
||||
It should just run in linux without having to worry about what you have on your system. I want to download and run. No docker. No dependency hell.
|
||||
|
||||
I'm not bothering with other operating systems.
|
||||
|
||||
### The relay is a full nostr citizen with it's own public and private keys.
|
||||
|
||||
For example, you can see my relay's profile (wss://relay.laantungir.net) running here:
|
||||
|
||||
[Primal link](https://primal.net/p/nprofile1qqswn2jsmm8lq8evas0v9vhqkdpn9nuujt90mtz60nqgsxndy66es4qjjnhr7)
|
||||
|
||||
What this means in practice is that when you start the relay, it generates keys for itself, and for it's administrator (You can specify these if you wish)
|
||||
|
||||
Now the program and the administrator can have verifed communication between the two, simply by using nostr events. For example, the administrator can send DMs to the relay, asking it's status, and changing it's configuration through any client that can handle nip17 DMs. The relay can also send notifications to the administrator about it's current status, or it can publish it's status on a regular schedule directly to NOSTR as kind-1 notes.
|
||||
|
||||
Also included is a more standard administrative web front end. This front end communicates to the relay using an extensive api, which again is nostr events signed by the administrator. You can completely control the relay through signed nostr events.
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||
Main page with real time updates.
|
||||
|
||||

|
||||
Set your configuration preferences.
|
||||
|
||||

|
||||
View current subscriptions
|
||||
|
||||

|
||||
Add npubs to white or black lists.
|
||||
|
||||

|
||||
Run sql queries on the database.
|
||||
|
||||

|
||||
Light mode.
|
||||
|
||||
@@ -1,347 +1,285 @@
|
||||
# C-Nostr Relay
|
||||
# C-Relay-PG: High-Performance Nostr Relay
|
||||
|
||||
A high-performance Nostr relay implemented in C with SQLite backend, featuring nostr event-based management.
|
||||
A blazingly fast, production-ready Nostr relay implemented in C with an innovative event-based configuration system. Built for performance, security, and ease of deployment.
|
||||
|
||||
## Supported NIPs
|
||||
## 🚀 Why C-Relay-PG?
|
||||
|
||||
<!--
|
||||
NOTE FOR ASSISTANTS: When updating the NIPs checklist below, ONLY change [ ] to [x] to mark as complete.
|
||||
Do NOT modify the formatting, add emojis, or change the text. Keep the simple format consistent.
|
||||
-->
|
||||
### Event-Based Configuration
|
||||
Unlike traditional relays that require config files, C-Relay-PG uses **cryptographically signed Nostr events** for all configuration. This means:
|
||||
- **Zero config files** - Everything stored in the database
|
||||
- **Real-time updates** - Changes applied instantly without restart
|
||||
- **Cryptographic security** - All changes must be signed by admin
|
||||
- **Complete audit trail** - Every configuration change is timestamped and signed
|
||||
- **Version control built-in** - Configuration history is part of the event stream
|
||||
|
||||
- [x] NIP-01: Basic protocol flow implementation
|
||||
- [x] NIP-09: Event deletion
|
||||
- [x] NIP-11: Relay information document
|
||||
- [x] NIP-13: Proof of Work
|
||||
- [x] NIP-15: End of Stored Events Notice
|
||||
- [x] NIP-20: Command Results
|
||||
- [x] NIP-33: Parameterized Replaceable Events
|
||||
- [x] NIP-40: Expiration Timestamp
|
||||
- [x] NIP-42: Authentication of clients to relays
|
||||
- [x] NIP-45: Counting results
|
||||
- [x] NIP-50: Keywords filter
|
||||
- [x] NIP-70: Protected Events
|
||||
### Built-in Web Admin Interface
|
||||
Access a full-featured web dashboard at `http://localhost:8888/api/` with:
|
||||
- Real-time configuration management
|
||||
- Database statistics and analytics
|
||||
- Auth rules management (whitelist/blacklist)
|
||||
- NIP-42 authentication for secure access
|
||||
- No external dependencies - all files embedded in the binary
|
||||
|
||||
## Quick Start
|
||||
### Direct Message Admin System
|
||||
Control your relay by sending direct messages from any Nostr client:
|
||||
- Send "stats" to get relay statistics
|
||||
- Send "config" to view current configuration
|
||||
- Full Nostr citizen with its own keypair
|
||||
- Works with any NIP-17 compatible client
|
||||
|
||||
Get your C-Relay up and running in minutes with a static binary (no dependencies required):
|
||||
### Performance & Efficiency
|
||||
- **Written in C** - Maximum performance and minimal resource usage
|
||||
- **SQLite backend** - Reliable, fast, and self-contained
|
||||
- **Static binary available** - Single file deployment with zero dependencies
|
||||
- **Efficient memory management** - Optimized for long-running operation
|
||||
- **WebSocket native** - Built on libwebsockets for optimal protocol support
|
||||
|
||||
### 1. Download Static Binary
|
||||
## 📋 Supported NIPs
|
||||
|
||||
Download the latest static release from the [releases page](https://git.laantungir.net/laantungir/c-relay/releases):
|
||||
C-Relay-PG implements a comprehensive set of Nostr Improvement Proposals:
|
||||
|
||||
- ✅ **NIP-01**: Basic protocol flow implementation
|
||||
- ✅ **NIP-09**: Event deletion
|
||||
- ✅ **NIP-11**: Relay information document
|
||||
- ✅ **NIP-13**: Proof of Work
|
||||
- ✅ **NIP-15**: End of Stored Events Notice
|
||||
- ✅ **NIP-20**: Command Results
|
||||
- ✅ **NIP-33**: Parameterized Replaceable Events
|
||||
- ✅ **NIP-40**: Expiration Timestamp
|
||||
- ✅ **NIP-42**: Authentication of clients to relays
|
||||
- ✅ **NIP-45**: Counting results
|
||||
- ✅ **NIP-50**: Keywords filter
|
||||
- ✅ **NIP-70**: Protected Events
|
||||
|
||||
## 🎯 Key Features
|
||||
|
||||
### Security
|
||||
- **NIP-42 Authentication** - Cryptographic client authentication
|
||||
- **Proof of Work** - Configurable PoW requirements (NIP-13)
|
||||
- **Protected Events** - Support for encrypted/protected content (NIP-70)
|
||||
- **Whitelist/Blacklist** - Flexible access control by pubkey
|
||||
- **Admin key security** - Private key shown only once, never stored
|
||||
|
||||
### Flexibility
|
||||
- **Dynamic configuration** - Most settings update without restart
|
||||
- **Subscription management** - Configurable limits per client and globally
|
||||
- **Event expiration** - Automatic cleanup of expired events (NIP-40)
|
||||
- **Parameterized events** - Full support for replaceable events (NIP-33)
|
||||
- **Keyword search** - Built-in full-text search (NIP-50)
|
||||
|
||||
### Monitoring
|
||||
- **Real-time statistics** - Live event distribution and metrics
|
||||
- **Subscription-based monitoring** - Ephemeral events (kind 24567) for dashboards
|
||||
- **SQL query API** - Direct database queries for advanced analytics
|
||||
- **Resource tracking** - CPU, memory, and database size monitoring
|
||||
- **Event broadcast logging** - Complete audit trail of all operations
|
||||
|
||||
### Developer-Friendly
|
||||
- **Comprehensive test suite** - Automated tests for all NIPs
|
||||
- **Clear documentation** - Detailed guides for deployment and configuration
|
||||
- **SystemD integration** - Production-ready service files included
|
||||
- **Docker support** - Container deployment with Alpine Linux
|
||||
- **Cross-platform** - Builds on Linux, macOS, and Windows (WSL)
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Option 1: Static Binary (Recommended)
|
||||
|
||||
Download and run - no dependencies required:
|
||||
|
||||
```bash
|
||||
# Static binary - works on all Linux distributions (no dependencies)
|
||||
wget https://git.laantungir.net/laantungir/c-relay/releases/download/v0.6.0/c-relay-v0.6.0-linux-x86_64-static
|
||||
chmod +x c-relay-v0.6.0-linux-x86_64-static
|
||||
mv c-relay-v0.6.0-linux-x86_64-static c-relay
|
||||
# Download the latest static release
|
||||
wget https://git.laantungir.net/laantungir/c-relay-pg/releases/download/v0.6.0/c-relay-pg-v0.6.0-linux-x86_64-static
|
||||
chmod +x c-relay-pg-v0.6.0-linux-x86_64-static
|
||||
mv c-relay-pg-v0.6.0-linux-x86_64-static c-relay-pg
|
||||
|
||||
# Run the relay
|
||||
./c-relay-pg
|
||||
```
|
||||
|
||||
### 2. Start the Relay
|
||||
**Important**: On first startup, save the **Admin Private Key** displayed in the console. You'll need it for all administrative operations.
|
||||
|
||||
Simply run the binary - no configuration files needed:
|
||||
### Option 2: Build from Source
|
||||
|
||||
```bash
|
||||
./c-relay
|
||||
# Install dependencies (Ubuntu/Debian)
|
||||
sudo apt install -y build-essential git sqlite3 libsqlite3-dev \
|
||||
libwebsockets-dev libssl-dev libsecp256k1-dev libcurl4-openssl-dev zlib1g-dev
|
||||
|
||||
# Clone and build
|
||||
git clone https://github.com/your-org/c-relay-pg.git
|
||||
cd c-relay-pg
|
||||
git submodule update --init --recursive
|
||||
./make_and_restart_relay.sh
|
||||
```
|
||||
|
||||
On first startup, you'll see:
|
||||
- **Admin Private Key**: Save this securely! You'll need it for administration
|
||||
- **Relay Public Key**: Your relay's identity on the Nostr network
|
||||
- **Port Information**: Default is 8888, or the next available port
|
||||
The relay will start on port 8888 (or the next available port).
|
||||
|
||||
### 3. Access the Web Interface
|
||||
## 🌐 Access the Web Interface
|
||||
|
||||
Once running, open your browser to:
|
||||
|
||||
Open your browser and navigate to:
|
||||
```
|
||||
http://localhost:8888/api/
|
||||
```
|
||||
|
||||
The web interface provides:
|
||||
- Real-time configuration management
|
||||
- Database statistics dashboard
|
||||
- Auth rules management
|
||||
- Secure admin authentication with your Nostr identity
|
||||
- Configuration management with live updates
|
||||
- Database statistics and event distribution charts
|
||||
- Auth rules management (whitelist/blacklist)
|
||||
- SQL query interface for advanced analytics
|
||||
- Real-time monitoring dashboard
|
||||
|
||||
### 4. Test Your Relay
|
||||
## 📦 Installation Options
|
||||
|
||||
### Production Deployment (SystemD)
|
||||
|
||||
Test basic connectivity:
|
||||
```bash
|
||||
# Test WebSocket connection
|
||||
curl -H "Accept: application/nostr+json" http://localhost:8888
|
||||
# Clone repository
|
||||
git clone https://github.com/your-org/c-relay-pg.git
|
||||
cd c-relay-pg
|
||||
git submodule update --init --recursive
|
||||
|
||||
# Test with a Nostr client
|
||||
# Add ws://localhost:8888 to your client's relay list
|
||||
# Build
|
||||
make clean && make
|
||||
|
||||
# Install as system service
|
||||
sudo systemd/install-service.sh
|
||||
|
||||
# Start and enable
|
||||
sudo systemctl start c-relay-pg
|
||||
sudo systemctl enable c-relay-pg
|
||||
|
||||
# Capture admin keys from logs
|
||||
sudo journalctl -u c-relay-pg | grep "Admin Private Key"
|
||||
```
|
||||
|
||||
### 5. Configure Your Relay (Optional)
|
||||
### Docker Deployment
|
||||
|
||||
Use the web interface or send admin commands to customize:
|
||||
- Relay name and description
|
||||
- Authentication rules (whitelist/blacklist)
|
||||
- Connection limits
|
||||
- Proof-of-work requirements
|
||||
```bash
|
||||
# Build Docker image
|
||||
docker build -f Dockerfile.alpine-musl -t c-relay-pg .
|
||||
|
||||
**That's it!** Your relay is now running with zero configuration required. The event-based configuration system means you can adjust all settings through the web interface or admin API without editing config files.
|
||||
|
||||
|
||||
## Web Admin Interface
|
||||
|
||||
C-Relay includes a **built-in web-based administration interface** accessible at `http://localhost:8888/api/`. The interface provides:
|
||||
|
||||
- **Real-time Configuration Management**: View and edit all relay settings through a web UI
|
||||
- **Database Statistics Dashboard**: Monitor event counts, storage usage, and performance metrics
|
||||
- **Auth Rules Management**: Configure whitelist/blacklist rules for pubkeys
|
||||
- **NIP-42 Authentication**: Secure access using your Nostr identity
|
||||
- **Event-Based Updates**: All changes are applied as cryptographically signed Nostr events
|
||||
|
||||
The web interface serves embedded static files with no external dependencies and includes proper CORS headers for browser compatibility.
|
||||
|
||||
|
||||
## Administrator API
|
||||
|
||||
C-Relay uses an innovative **event-based administration system** where all configuration and management commands are sent as signed Nostr events using the admin private key generated during first startup. All admin commands use **NIP-44 encrypted command arrays** for security and compatibility.
|
||||
|
||||
### Authentication
|
||||
|
||||
All admin commands require signing with the admin private key displayed during first-time startup. **Save this key securely** - it cannot be recovered and is needed for all administrative operations.
|
||||
|
||||
### Event Structure
|
||||
|
||||
All admin commands use the same unified event structure with NIP-44 encrypted content:
|
||||
|
||||
**Admin Command Event:**
|
||||
```json
|
||||
{
|
||||
"id": "event_id",
|
||||
"pubkey": "admin_public_key",
|
||||
"created_at": 1234567890,
|
||||
"kind": 23456,
|
||||
"content": "AqHBUgcM7dXFYLQuDVzGwMST1G8jtWYyVvYxXhVGEu4nAb4LVw...",
|
||||
"tags": [
|
||||
["p", "relay_public_key"]
|
||||
],
|
||||
"sig": "event_signature"
|
||||
}
|
||||
# Run container
|
||||
docker run -d \
|
||||
--name c-relay-pg \
|
||||
-p 8888:8888 \
|
||||
-v /path/to/data:/data \
|
||||
c-relay-pg
|
||||
```
|
||||
|
||||
The `content` field contains a NIP-44 encrypted JSON array representing the command.
|
||||
### Cloud Deployment
|
||||
|
||||
**Admin Response Event:**
|
||||
```json
|
||||
["EVENT", "temp_sub_id", {
|
||||
"id": "response_event_id",
|
||||
"pubkey": "relay_public_key",
|
||||
"created_at": 1234567890,
|
||||
"kind": 23457,
|
||||
"content": "BpKCVhfN8eYtRmPqSvWxZnMkL2gHjUiOp3rTyEwQaS5dFg...",
|
||||
"tags": [
|
||||
["p", "admin_public_key"]
|
||||
],
|
||||
"sig": "response_event_signature"
|
||||
}]
|
||||
Quick deployment scripts for popular cloud providers:
|
||||
|
||||
```bash
|
||||
# AWS, GCP, DigitalOcean, etc.
|
||||
sudo examples/deployment/simple-vps/deploy.sh
|
||||
```
|
||||
|
||||
The `content` field contains a NIP-44 encrypted JSON response object.
|
||||
See [`docs/deployment_guide.md`](docs/deployment_guide.md) for detailed deployment instructions.
|
||||
|
||||
### Admin Commands
|
||||
## 🔧 Configuration
|
||||
|
||||
All commands are sent as NIP-44 encrypted JSON arrays in the event content. The following table lists all available commands:
|
||||
C-Relay-PG uses an innovative event-based configuration system. All settings are managed through signed Nostr events.
|
||||
|
||||
| Command Type | Command Format | Description |
|
||||
|--------------|----------------|-------------|
|
||||
| **Configuration Management** |
|
||||
| `config_update` | `["config_update", [{"key": "auth_enabled", "value": "true", "data_type": "boolean", "category": "auth"}, {"key": "relay_description", "value": "My Relay", "data_type": "string", "category": "relay"}, ...]]` | Update relay configuration parameters (supports multiple updates) |
|
||||
| `config_query` | `["config_query", "all"]` | Query all configuration parameters |
|
||||
| **Auth Rules Management** |
|
||||
| `auth_add_blacklist` | `["blacklist", "pubkey", "abc123..."]` | Add pubkey to blacklist |
|
||||
| `auth_add_whitelist` | `["whitelist", "pubkey", "def456..."]` | Add pubkey to whitelist |
|
||||
| `auth_delete_rule` | `["delete_auth_rule", "blacklist", "pubkey", "abc123..."]` | Delete specific auth rule |
|
||||
| `auth_query_all` | `["auth_query", "all"]` | Query all auth rules |
|
||||
| `auth_query_type` | `["auth_query", "whitelist"]` | Query specific rule type |
|
||||
| `auth_query_pattern` | `["auth_query", "pattern", "abc123..."]` | Query specific pattern |
|
||||
| **System Commands** |
|
||||
| `system_clear_auth` | `["system_command", "clear_all_auth_rules"]` | Clear all auth rules |
|
||||
| `system_status` | `["system_command", "system_status"]` | Get system status |
|
||||
| `stats_query` | `["stats_query"]` | Get comprehensive database statistics |
|
||||
### Basic Configuration
|
||||
|
||||
### Available Configuration Keys
|
||||
Use the web interface at `http://localhost:8888/api/` or send admin commands via the API.
|
||||
|
||||
**Basic Relay Settings:**
|
||||
- `relay_name`: Relay name (displayed in NIP-11)
|
||||
- `relay_description`: Relay description text
|
||||
- `relay_contact`: Contact information
|
||||
- `relay_software`: Software URL
|
||||
- `relay_version`: Software version
|
||||
- `supported_nips`: Comma-separated list of supported NIP numbers (e.g., "1,2,4,9,11,12,13,15,16,20,22,33,40,42")
|
||||
- `language_tags`: Comma-separated list of supported language tags (e.g., "en,es,fr" or "*" for all)
|
||||
- `relay_countries`: Comma-separated list of supported country codes (e.g., "US,CA,MX" or "*" for all)
|
||||
- `posting_policy`: Posting policy URL or text
|
||||
- `payments_url`: Payment URL for premium features
|
||||
- `max_connections`: Maximum concurrent connections
|
||||
- `max_subscriptions_per_client`: Max subscriptions per client
|
||||
- `max_event_tags`: Maximum tags per event
|
||||
- `max_content_length`: Maximum event content length
|
||||
### Common Settings
|
||||
|
||||
**Authentication & Access Control:**
|
||||
- `auth_enabled`: Enable whitelist/blacklist auth rules (`true`/`false`)
|
||||
- `nip42_auth_required`: Enable NIP-42 cryptographic authentication (`true`/`false`)
|
||||
- `nip42_auth_required_kinds`: Event kinds requiring NIP-42 auth (comma-separated)
|
||||
- `nip42_challenge_timeout`: NIP-42 challenge expiration seconds
|
||||
- **Relay Information**: Name, description, contact info
|
||||
- **Connection Limits**: Max subscriptions per client, total subscriptions
|
||||
- **Authentication**: Enable/disable NIP-42, whitelist/blacklist rules
|
||||
- **Proof of Work**: Minimum difficulty, enforcement mode
|
||||
- **Event Validation**: Max tags, content length, message size
|
||||
- **Expiration**: Enable/disable NIP-40 event expiration
|
||||
|
||||
**Proof of Work & Validation:**
|
||||
- `pow_min_difficulty`: Minimum proof-of-work difficulty
|
||||
- `nip40_expiration_enabled`: Enable event expiration (`true`/`false`)
|
||||
### Dynamic Updates
|
||||
|
||||
### Dynamic Configuration Updates
|
||||
Most configuration changes take effect immediately without restart:
|
||||
- Relay information (NIP-11)
|
||||
- Authentication settings
|
||||
- Subscription limits
|
||||
- Event validation rules
|
||||
- Proof of Work settings
|
||||
|
||||
C-Relay supports **dynamic configuration updates** without requiring a restart for most settings. Configuration parameters are categorized as either **dynamic** (can be updated immediately) or **restart-required** (require relay restart to take effect).
|
||||
See [`docs/configuration_guide.md`](docs/configuration_guide.md) for complete configuration reference.
|
||||
|
||||
**Dynamic Configuration Parameters (No Restart Required):**
|
||||
- All relay information (NIP-11) settings: `relay_name`, `relay_description`, `relay_contact`, `relay_software`, `relay_version`, `supported_nips`, `language_tags`, `relay_countries`, `posting_policy`, `payments_url`
|
||||
- Authentication settings: `auth_enabled`, `nip42_auth_required`, `nip42_auth_required_kinds`, `nip42_challenge_timeout`
|
||||
- Subscription limits: `max_subscriptions_per_client`, `max_total_subscriptions`
|
||||
- Event validation limits: `max_event_tags`, `max_content_length`, `max_message_length`
|
||||
- Proof of Work settings: `pow_min_difficulty`, `pow_mode`
|
||||
- Event expiration settings: `nip40_expiration_enabled`, `nip40_expiration_strict`, `nip40_expiration_filter`, `nip40_expiration_grace_period`
|
||||
## 📚 Documentation
|
||||
|
||||
**Restart-Required Configuration Parameters:**
|
||||
- Connection settings: `max_connections`, `relay_port`
|
||||
- Database and core system settings
|
||||
- **[API Documentation](API.md)** - Complete API reference and advanced features
|
||||
- **[Configuration Guide](docs/configuration_guide.md)** - Detailed configuration options
|
||||
- **[Deployment Guide](docs/deployment_guide.md)** - Production deployment instructions
|
||||
- **[User Guide](docs/user_guide.md)** - End-user documentation
|
||||
- **[NIP-42 Authentication](docs/NIP-42_Authentication.md)** - Authentication setup guide
|
||||
|
||||
When updating configuration, the admin API response will indicate whether a restart is required for each parameter. Dynamic updates take effect immediately and are reflected in NIP-11 relay information documents without restart.
|
||||
## 🧪 Testing
|
||||
|
||||
### Response Format
|
||||
Run the comprehensive test suite:
|
||||
|
||||
All admin commands return **signed EVENT responses** via WebSocket following standard Nostr protocol. Responses use JSON content with structured data.
|
||||
```bash
|
||||
# Run all tests
|
||||
./tests/run_all_tests.sh
|
||||
|
||||
#### Response Examples
|
||||
# Run NIP-specific tests
|
||||
./tests/run_nip_tests.sh
|
||||
|
||||
**Success Response:**
|
||||
```json
|
||||
["EVENT", "temp_sub_id", {
|
||||
"id": "response_event_id",
|
||||
"pubkey": "relay_public_key",
|
||||
"created_at": 1234567890,
|
||||
"kind": 23457,
|
||||
"content": "nip44 encrypted:{\"query_type\": \"config_update\", \"status\": \"success\", \"message\": \"Operation completed successfully\", \"timestamp\": 1234567890}",
|
||||
"tags": [
|
||||
["p", "admin_public_key"]
|
||||
],
|
||||
"sig": "response_event_signature"
|
||||
}]
|
||||
# Test specific NIPs
|
||||
./tests/42_nip_test.sh # NIP-42 authentication
|
||||
./tests/13_nip_test.sh # NIP-13 proof of work
|
||||
```
|
||||
|
||||
**Error Response:**
|
||||
```json
|
||||
["EVENT", "temp_sub_id", {
|
||||
"id": "response_event_id",
|
||||
"pubkey": "relay_public_key",
|
||||
"created_at": 1234567890,
|
||||
"kind": 23457,
|
||||
"content": "nip44 encrypted:{\"query_type\": \"config_update\", \"status\": \"error\", \"error\": \"invalid configuration value\", \"timestamp\": 1234567890}",
|
||||
"tags": [
|
||||
["p", "admin_public_key"]
|
||||
],
|
||||
"sig": "response_event_signature"
|
||||
}]
|
||||
## 🔒 Security
|
||||
|
||||
### Admin Key Management
|
||||
|
||||
The admin private key is displayed **only once** during first startup. Store it securely:
|
||||
|
||||
```bash
|
||||
# Save to secure location
|
||||
echo "ADMIN_PRIVKEY=your_admin_private_key" > ~/.c-relay-pg-admin
|
||||
chmod 600 ~/.c-relay-pg-admin
|
||||
```
|
||||
|
||||
**Auth Rules Query Response:**
|
||||
```json
|
||||
["EVENT", "temp_sub_id", {
|
||||
"id": "response_event_id",
|
||||
"pubkey": "relay_public_key",
|
||||
"created_at": 1234567890,
|
||||
"kind": 23457,
|
||||
"content": "nip44 encrypted:{\"query_type\": \"auth_rules_all\", \"total_results\": 2, \"timestamp\": 1234567890, \"data\": [{\"rule_type\": \"blacklist\", \"pattern_type\": \"pubkey\", \"pattern_value\": \"abc123...\", \"action\": \"allow\"}]}",
|
||||
"tags": [
|
||||
["p", "admin_public_key"]
|
||||
],
|
||||
"sig": "response_event_signature"
|
||||
}]
|
||||
```
|
||||
### Production Security
|
||||
|
||||
**Configuration Query Response:**
|
||||
```json
|
||||
["EVENT", "temp_sub_id", {
|
||||
"id": "response_event_id",
|
||||
"pubkey": "relay_public_key",
|
||||
"created_at": 1234567890,
|
||||
"kind": 23457,
|
||||
"content": "nip44 encrypted:{\"query_type\": \"config_all\", \"total_results\": 27, \"timestamp\": 1234567890, \"data\": [{\"key\": \"auth_enabled\", \"value\": \"false\", \"data_type\": \"boolean\", \"category\": \"auth\", \"description\": \"Enable NIP-42 authentication\"}, {\"key\": \"relay_description\", \"value\": \"My Relay\", \"data_type\": \"string\", \"category\": \"relay\", \"description\": \"Relay description text\"}]}",
|
||||
"tags": [
|
||||
["p", "admin_public_key"]
|
||||
],
|
||||
"sig": "response_event_signature"
|
||||
}]
|
||||
```
|
||||
- Use HTTPS/WSS with reverse proxy (nginx/Apache)
|
||||
- Enable NIP-42 authentication for client verification
|
||||
- Configure whitelist/blacklist for access control
|
||||
- Set up firewall rules to restrict access
|
||||
- Enable Proof of Work to prevent spam
|
||||
- Regular database backups
|
||||
|
||||
**Configuration Update Success Response:**
|
||||
```json
|
||||
["EVENT", "temp_sub_id", {
|
||||
"id": "response_event_id",
|
||||
"pubkey": "relay_public_key",
|
||||
"created_at": 1234567890,
|
||||
"kind": 23457,
|
||||
"content": "nip44 encrypted:{\"query_type\": \"config_update\", \"total_results\": 2, \"timestamp\": 1234567890, \"status\": \"success\", \"data\": [{\"key\": \"auth_enabled\", \"value\": \"true\", \"status\": \"updated\"}, {\"key\": \"relay_description\", \"value\": \"My Updated Relay\", \"status\": \"updated\"}]}",
|
||||
"tags": [
|
||||
["p", "admin_public_key"]
|
||||
],
|
||||
"sig": "response_event_signature"
|
||||
}]
|
||||
```
|
||||
See [`docs/deployment_guide.md`](docs/deployment_guide.md#security-hardening) for security hardening guide.
|
||||
|
||||
**Configuration Update Error Response:**
|
||||
```json
|
||||
["EVENT", "temp_sub_id", {
|
||||
"id": "response_event_id",
|
||||
"pubkey": "relay_public_key",
|
||||
"created_at": 1234567890,
|
||||
"kind": 23457,
|
||||
"content": "nip44 encrypted:{\"query_type\": \"config_update\", \"status\": \"error\", \"error\": \"field validation failed: invalid port number '99999' (must be 1-65535)\", \"timestamp\": 1234567890}",
|
||||
"tags": [
|
||||
["p", "admin_public_key"]
|
||||
],
|
||||
"sig": "response_event_signature"
|
||||
}]
|
||||
```
|
||||
## 🤝 Contributing
|
||||
|
||||
**Database Statistics Query Response:**
|
||||
```json
|
||||
["EVENT", "temp_sub_id", {
|
||||
"id": "response_event_id",
|
||||
"pubkey": "relay_public_key",
|
||||
"created_at": 1234567890,
|
||||
"kind": 23457,
|
||||
"content": "nip44 encrypted:{\"query_type\": \"stats_query\", \"timestamp\": 1234567890, \"database_size_bytes\": 1048576, \"total_events\": 15432, \"database_created_at\": 1234567800, \"latest_event_at\": 1234567890, \"event_kinds\": [{\"kind\": 1, \"count\": 12000, \"percentage\": 77.8}, {\"kind\": 0, \"count\": 2500, \"percentage\": 16.2}], \"time_stats\": {\"total\": 15432, \"last_24h\": 234, \"last_7d\": 1456, \"last_30d\": 5432}, \"top_pubkeys\": [{\"pubkey\": \"abc123...\", \"event_count\": 1234, \"percentage\": 8.0}, {\"pubkey\": \"def456...\", \"event_count\": 987, \"percentage\": 6.4}]}",
|
||||
"tags": [
|
||||
["p", "admin_public_key"]
|
||||
],
|
||||
"sig": "response_event_signature"
|
||||
}]
|
||||
Contributions are welcome! Please:
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch
|
||||
3. Make your changes with tests
|
||||
4. Submit a pull request
|
||||
|
||||
```
|
||||
## 📄 License
|
||||
|
||||
[Add your license here]
|
||||
|
||||
## 🔗 Links
|
||||
|
||||
- **Repository**: [https://github.com/your-org/c-relay-pg](https://github.com/your-org/c-relay-pg)
|
||||
- **Releases**: [https://git.laantungir.net/laantungir/c-relay-pg/releases](https://git.laantungir.net/laantungir/c-relay-pg/releases)
|
||||
- **Issues**: [https://github.com/your-org/c-relay-pg/issues](https://github.com/your-org/c-relay-pg/issues)
|
||||
- **Nostr Protocol**: [https://github.com/nostr-protocol/nostr](https://github.com/nostr-protocol/nostr)
|
||||
|
||||
## 💬 Support
|
||||
|
||||
- Open an issue on GitHub
|
||||
- Join the Nostr community
|
||||
- Contact via Nostr DM (relay pubkey shown on startup)
|
||||
|
||||
## Direct Messaging Admin System
|
||||
|
||||
In addition to the above admin API, c-relay allows the administrator to direct message the relay to get information or control some settings. As long as the administrator is signed in with any nostr client that allows sending nip-17 direct messages (DMs), they can control the relay.
|
||||
|
||||
The is possible because the relay is a full nostr citizen with it's own private and public key, and it knows the administrator's public key.
|
||||
|
||||
|
||||
|
||||
**Available DM commands**
|
||||
|
||||
The intent is not to be strict in the formatting of the DM. So for example if the relay receives any DM from the administrator with the words "stats" or "statistics" in it, it will respond to the administrator with a reply DM with the current relay statistics.
|
||||
|
||||
- `stats`|`statistics`: Relay statistics
|
||||
- `config`|`configuration`: Relay configuration
|
||||
|
||||
---
|
||||
|
||||
**Built with ❤️ for the Nostr protocol**
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
# Real-Time Traffic Monitoring Commands (Direct Server Use)
|
||||
|
||||
Copy and paste these commands directly on your server.
|
||||
|
||||
## Quick Status Checks
|
||||
|
||||
### See IPs visiting in the last few minutes:
|
||||
```bash
|
||||
sudo tail -500 /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
|
||||
```
|
||||
|
||||
### See what status codes they're getting:
|
||||
```bash
|
||||
sudo tail -500 /var/log/nginx/access.log | awk '{print $1, $9}' | grep '216.73.216.38'
|
||||
```
|
||||
|
||||
### Count status codes (200 vs 403):
|
||||
```bash
|
||||
sudo tail -500 /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c
|
||||
```
|
||||
|
||||
## Real-Time Monitoring
|
||||
|
||||
### Watch live traffic (updates every 2 seconds):
|
||||
```bash
|
||||
watch -n 2 'sudo tail -200 /var/log/nginx/access.log | awk "{print \$1}" | sort | uniq -c | sort -rn | head -15'
|
||||
```
|
||||
|
||||
### See live log entries as they happen:
|
||||
```bash
|
||||
sudo tail -f /var/log/nginx/access.log
|
||||
```
|
||||
|
||||
### Live GoAccess dashboard:
|
||||
```bash
|
||||
sudo tail -f /var/log/nginx/access.log | goaccess -
|
||||
```
|
||||
|
||||
## Active Connections
|
||||
|
||||
### See who's connected RIGHT NOW:
|
||||
```bash
|
||||
sudo netstat -tn | grep ':443' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn
|
||||
```
|
||||
|
||||
### Alternative (using ss command):
|
||||
```bash
|
||||
sudo ss -tn | grep ':443' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn
|
||||
```
|
||||
|
||||
## Detailed Analysis
|
||||
|
||||
### Last 100 requests with timestamps:
|
||||
```bash
|
||||
sudo tail -100 /var/log/nginx/access.log | awk '{print $4, $1}' | sed 's/\[//'
|
||||
```
|
||||
|
||||
### See what blocked IPs are trying to access:
|
||||
```bash
|
||||
sudo tail -500 /var/log/nginx/access.log | grep '216.73.216.38' | awk '{print $7}' | head -10
|
||||
```
|
||||
|
||||
### Show all 403 (blocked) requests:
|
||||
```bash
|
||||
sudo tail -500 /var/log/nginx/access.log | awk '$9==403 {print $1}' | sort | uniq -c | sort -rn
|
||||
```
|
||||
|
||||
### Show all successful (200) requests:
|
||||
```bash
|
||||
sudo tail -500 /var/log/nginx/access.log | awk '$9==200 {print $1}' | sort | uniq -c | sort -rn | head -10
|
||||
```
|
||||
|
||||
## Comprehensive Monitoring Script
|
||||
|
||||
### Create a monitoring script:
|
||||
```bash
|
||||
cat > /tmp/monitor-traffic.sh << 'EOF'
|
||||
#!/bin/bash
|
||||
echo "=== Traffic in last 5 minutes ==="
|
||||
echo "Time: $(date)"
|
||||
echo ""
|
||||
echo "Top IPs:"
|
||||
sudo tail -1000 /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
|
||||
echo ""
|
||||
echo "Blocked IPs (403 errors):"
|
||||
sudo tail -1000 /var/log/nginx/access.log | awk '$9==403 {print $1}' | sort | uniq -c | sort -rn
|
||||
echo ""
|
||||
echo "Successful requests (200):"
|
||||
sudo tail -1000 /var/log/nginx/access.log | awk '$9==200 {print $1}' | sort | uniq -c | sort -rn | head -5
|
||||
echo ""
|
||||
echo "Status Code Summary:"
|
||||
sudo tail -1000 /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c | sort -rn
|
||||
EOF
|
||||
chmod +x /tmp/monitor-traffic.sh
|
||||
```
|
||||
|
||||
### Run the monitoring script:
|
||||
```bash
|
||||
/tmp/monitor-traffic.sh
|
||||
```
|
||||
|
||||
## Auto-Refreshing Dashboard
|
||||
|
||||
### Live dashboard (refreshes every 5 seconds):
|
||||
```bash
|
||||
watch -n 5 'echo "=== Last 5 minutes ==="
|
||||
date
|
||||
echo ""
|
||||
echo "Top IPs:"
|
||||
sudo tail -1000 /var/log/nginx/access.log | awk "{print \$1}" | sort | uniq -c | sort -rn | head -10
|
||||
echo ""
|
||||
echo "Status Codes:"
|
||||
sudo tail -1000 /var/log/nginx/access.log | awk "{print \$9}" | sort | uniq -c | sort -rn'
|
||||
```
|
||||
|
||||
Press `Ctrl+C` to exit.
|
||||
|
||||
## GoAccess HTML Report (Live Updating)
|
||||
|
||||
### Generate live HTML report:
|
||||
```bash
|
||||
sudo goaccess /var/log/nginx/access.log -o /var/www/html/live-stats.html --real-time-html --daemonize
|
||||
```
|
||||
|
||||
Then visit: https://git.laantungir.net/live-stats.html
|
||||
|
||||
### Stop the live report:
|
||||
```bash
|
||||
sudo pkill -f "goaccess.*live-stats"
|
||||
```
|
||||
|
||||
## Filter by Time
|
||||
|
||||
### Get timestamp from 5 minutes ago:
|
||||
```bash
|
||||
date -d '5 minutes ago' '+%d/%b/%Y:%H:%M'
|
||||
```
|
||||
|
||||
### Analyze only recent logs (replace timestamp):
|
||||
```bash
|
||||
sudo awk '/01\/Feb\/2026:19:09/,0' /var/log/nginx/access.log | goaccess -
|
||||
```
|
||||
|
||||
## Check Gitea CPU
|
||||
|
||||
### Current CPU usage:
|
||||
```bash
|
||||
ps aux | grep gitea | grep -v grep
|
||||
```
|
||||
|
||||
### Watch CPU in real-time:
|
||||
```bash
|
||||
watch -n 2 'ps aux | grep gitea | grep -v grep'
|
||||
```
|
||||
|
||||
## Most Useful Command for Quick Check
|
||||
|
||||
This one-liner shows everything you need:
|
||||
```bash
|
||||
|
||||
echo "=== Quick Status ===" && \
|
||||
echo "Time: $(date)" && \
|
||||
echo "" && \
|
||||
echo "Top 10 IPs (last 1000 requests):" && \
|
||||
sudo tail -1000 /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10 && \
|
||||
echo "" && \
|
||||
echo "Status Codes:" && \
|
||||
sudo tail -1000 /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c && \
|
||||
echo "" && \
|
||||
echo "Gitea CPU:" && \
|
||||
ps aux | grep gitea | grep -v grep
|
||||
```
|
||||
|
||||
Copy any of these commands and run them directly on your server!
|
||||
@@ -0,0 +1,612 @@
|
||||
# Static MUSL Build Guide for C Programs
|
||||
|
||||
## Overview
|
||||
|
||||
This guide explains how to build truly portable static binaries using Alpine Linux and MUSL libc. These binaries have **zero runtime dependencies** and work on any Linux distribution without modification.
|
||||
|
||||
This guide is specifically tailored for C programs that use:
|
||||
- **nostr_core_lib** - Nostr protocol implementation
|
||||
- **nostr_login_lite** - Nostr authentication library
|
||||
- Common dependencies: libwebsockets, OpenSSL, SQLite, curl, secp256k1
|
||||
|
||||
## Why MUSL Static Binaries?
|
||||
|
||||
### Advantages Over glibc
|
||||
|
||||
| Feature | MUSL Static | glibc Static | glibc Dynamic |
|
||||
|---------|-------------|--------------|---------------|
|
||||
| **Portability** | ✓ Any Linux | ⚠ glibc only | ✗ Requires matching libs |
|
||||
| **Binary Size** | ~7-10 MB | ~12-15 MB | ~2-3 MB |
|
||||
| **Dependencies** | None | NSS libs | Many system libs |
|
||||
| **Deployment** | Single file | Single file + NSS | Binary + libraries |
|
||||
| **Compatibility** | Universal | glibc version issues | Library version hell |
|
||||
|
||||
### Key Benefits
|
||||
|
||||
1. **True Portability**: Works on Alpine, Ubuntu, Debian, CentOS, Arch, etc.
|
||||
2. **No Library Hell**: No `GLIBC_2.XX not found` errors
|
||||
3. **Simple Deployment**: Just copy one file
|
||||
4. **Reproducible Builds**: Same Docker image = same binary
|
||||
5. **Security**: No dependency on system libraries with vulnerabilities
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Docker installed and running
|
||||
- Your C project with source code
|
||||
- Internet connection for downloading dependencies
|
||||
|
||||
### Basic Build Process
|
||||
|
||||
```bash
|
||||
# 1. Copy the Dockerfile template (see below)
|
||||
cp /path/to/c-relay-pg/Dockerfile.alpine-musl ./Dockerfile.static
|
||||
|
||||
# 2. Customize for your project (see Customization section)
|
||||
vim Dockerfile.static
|
||||
|
||||
# 3. Build the static binary
|
||||
docker build --platform linux/amd64 -f Dockerfile.static -t my-app-builder .
|
||||
|
||||
# 4. Extract the binary
|
||||
docker create --name temp-container my-app-builder
|
||||
docker cp temp-container:/build/my_app_static ./my_app_static
|
||||
docker rm temp-container
|
||||
|
||||
# 5. Verify it's static
|
||||
ldd ./my_app_static # Should show "not a dynamic executable"
|
||||
```
|
||||
|
||||
## Dockerfile Template
|
||||
|
||||
Here's a complete Dockerfile template you can customize for your project:
|
||||
|
||||
```dockerfile
|
||||
# Alpine-based MUSL static binary builder
|
||||
# Produces truly portable binaries with zero runtime dependencies
|
||||
|
||||
FROM alpine:3.19 AS builder
|
||||
|
||||
# Install build dependencies
|
||||
RUN apk add --no-cache \
|
||||
build-base \
|
||||
musl-dev \
|
||||
git \
|
||||
cmake \
|
||||
pkgconfig \
|
||||
autoconf \
|
||||
automake \
|
||||
libtool \
|
||||
openssl-dev \
|
||||
openssl-libs-static \
|
||||
zlib-dev \
|
||||
zlib-static \
|
||||
curl-dev \
|
||||
curl-static \
|
||||
sqlite-dev \
|
||||
sqlite-static \
|
||||
linux-headers \
|
||||
wget \
|
||||
bash
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Build libsecp256k1 static (required for Nostr)
|
||||
RUN cd /tmp && \
|
||||
git clone https://github.com/bitcoin-core/secp256k1.git && \
|
||||
cd secp256k1 && \
|
||||
./autogen.sh && \
|
||||
./configure --enable-static --disable-shared --prefix=/usr \
|
||||
CFLAGS="-fPIC" && \
|
||||
make -j$(nproc) && \
|
||||
make install && \
|
||||
rm -rf /tmp/secp256k1
|
||||
|
||||
# Build libwebsockets static (if needed for WebSocket support)
|
||||
RUN cd /tmp && \
|
||||
git clone --depth 1 --branch v4.3.3 https://github.com/warmcat/libwebsockets.git && \
|
||||
cd libwebsockets && \
|
||||
mkdir build && cd build && \
|
||||
cmake .. \
|
||||
-DLWS_WITH_STATIC=ON \
|
||||
-DLWS_WITH_SHARED=OFF \
|
||||
-DLWS_WITH_SSL=ON \
|
||||
-DLWS_WITHOUT_TESTAPPS=ON \
|
||||
-DLWS_WITHOUT_TEST_SERVER=ON \
|
||||
-DLWS_WITHOUT_TEST_CLIENT=ON \
|
||||
-DLWS_WITHOUT_TEST_PING=ON \
|
||||
-DLWS_WITH_HTTP2=OFF \
|
||||
-DLWS_WITH_LIBUV=OFF \
|
||||
-DLWS_WITH_LIBEVENT=OFF \
|
||||
-DLWS_IPV6=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DCMAKE_C_FLAGS="-fPIC" && \
|
||||
make -j$(nproc) && \
|
||||
make install && \
|
||||
rm -rf /tmp/libwebsockets
|
||||
|
||||
# Copy git configuration for submodules
|
||||
COPY .gitmodules /build/.gitmodules
|
||||
COPY .git /build/.git
|
||||
|
||||
# Initialize submodules
|
||||
RUN git submodule update --init --recursive
|
||||
|
||||
# Copy and build nostr_core_lib
|
||||
COPY nostr_core_lib /build/nostr_core_lib/
|
||||
RUN cd nostr_core_lib && \
|
||||
chmod +x build.sh && \
|
||||
sed -i 's/CFLAGS="-Wall -Wextra -std=c99 -fPIC -O2"/CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -Wall -Wextra -std=c99 -fPIC -O2"/' build.sh && \
|
||||
rm -f *.o *.a 2>/dev/null || true && \
|
||||
./build.sh --nips=1,6,13,17,19,44,59
|
||||
|
||||
# Copy and build nostr_login_lite (if used)
|
||||
# COPY nostr_login_lite /build/nostr_login_lite/
|
||||
# RUN cd nostr_login_lite && make static
|
||||
|
||||
# Copy your application source
|
||||
COPY src/ /build/src/
|
||||
COPY Makefile /build/Makefile
|
||||
|
||||
# Build your application with full static linking
|
||||
RUN gcc -static -O2 -Wall -Wextra -std=c99 \
|
||||
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \
|
||||
-I. -Inostr_core_lib -Inostr_core_lib/nostr_core \
|
||||
-Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket \
|
||||
src/*.c \
|
||||
-o /build/my_app_static \
|
||||
nostr_core_lib/libnostr_core_x64.a \
|
||||
-lwebsockets -lssl -lcrypto -lsqlite3 -lsecp256k1 \
|
||||
-lcurl -lz -lpthread -lm -ldl && \
|
||||
strip /build/my_app_static
|
||||
|
||||
# Verify it's truly static
|
||||
RUN echo "=== Binary Information ===" && \
|
||||
file /build/my_app_static && \
|
||||
ls -lh /build/my_app_static && \
|
||||
echo "=== Checking for dynamic dependencies ===" && \
|
||||
(ldd /build/my_app_static 2>&1 || echo "Binary is static")
|
||||
|
||||
# Output stage - just the binary
|
||||
FROM scratch AS output
|
||||
COPY --from=builder /build/my_app_static /my_app_static
|
||||
```
|
||||
|
||||
## Customization Guide
|
||||
|
||||
### 1. Adjust Dependencies
|
||||
|
||||
**Add dependencies** by modifying the `apk add` section:
|
||||
|
||||
```dockerfile
|
||||
RUN apk add --no-cache \
|
||||
build-base \
|
||||
musl-dev \
|
||||
# Add your dependencies here:
|
||||
libpng-dev \
|
||||
libpng-static \
|
||||
libjpeg-turbo-dev \
|
||||
libjpeg-turbo-static
|
||||
```
|
||||
|
||||
**Remove unused dependencies** to speed up builds:
|
||||
- Remove `libwebsockets` section if you don't need WebSocket support
|
||||
- Remove `sqlite` if you don't use databases
|
||||
- Remove `curl` if you don't make HTTP requests
|
||||
|
||||
### 2. Configure nostr_core_lib NIPs
|
||||
|
||||
Specify which NIPs your application needs:
|
||||
|
||||
```bash
|
||||
./build.sh --nips=1,6,19 # Minimal: Basic protocol, keys, bech32
|
||||
./build.sh --nips=1,6,13,17,19,44,59 # Full: All common NIPs
|
||||
./build.sh --nips=all # Everything available
|
||||
```
|
||||
|
||||
**Common NIP combinations:**
|
||||
- **Basic client**: `1,6,19` (events, keys, bech32)
|
||||
- **With encryption**: `1,6,19,44` (add modern encryption)
|
||||
- **With DMs**: `1,6,17,19,44,59` (add private messages)
|
||||
- **Relay/server**: `1,6,13,17,19,42,44,59` (add PoW, auth)
|
||||
|
||||
### 3. Modify Compilation Flags
|
||||
|
||||
**For your application:**
|
||||
|
||||
```dockerfile
|
||||
RUN gcc -static -O2 -Wall -Wextra -std=c99 \
|
||||
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \ # REQUIRED for MUSL
|
||||
-I. -Inostr_core_lib \ # Include paths
|
||||
src/*.c \ # Your source files
|
||||
-o /build/my_app_static \ # Output binary
|
||||
nostr_core_lib/libnostr_core_x64.a \ # Nostr library
|
||||
-lwebsockets -lssl -lcrypto \ # Link libraries
|
||||
-lsqlite3 -lsecp256k1 -lcurl \
|
||||
-lz -lpthread -lm -ldl
|
||||
```
|
||||
|
||||
**Debug build** (with symbols, no optimization):
|
||||
|
||||
```dockerfile
|
||||
RUN gcc -static -g -O0 -DDEBUG \
|
||||
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \
|
||||
# ... rest of flags
|
||||
```
|
||||
|
||||
### 4. Multi-Architecture Support
|
||||
|
||||
Build for different architectures:
|
||||
|
||||
```bash
|
||||
# x86_64 (Intel/AMD)
|
||||
docker build --platform linux/amd64 -f Dockerfile.static -t my-app-x86 .
|
||||
|
||||
# ARM64 (Apple Silicon, Raspberry Pi 4+)
|
||||
docker build --platform linux/arm64 -f Dockerfile.static -t my-app-arm64 .
|
||||
```
|
||||
|
||||
## Build Script Template
|
||||
|
||||
Create a `build_static.sh` script for convenience:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BUILD_DIR="$SCRIPT_DIR/build"
|
||||
DOCKERFILE="$SCRIPT_DIR/Dockerfile.static"
|
||||
|
||||
# Detect architecture
|
||||
ARCH=$(uname -m)
|
||||
case "$ARCH" in
|
||||
x86_64)
|
||||
PLATFORM="linux/amd64"
|
||||
OUTPUT_NAME="my_app_static_x86_64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
PLATFORM="linux/arm64"
|
||||
OUTPUT_NAME="my_app_static_arm64"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown architecture: $ARCH"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Building for platform: $PLATFORM"
|
||||
mkdir -p "$BUILD_DIR"
|
||||
|
||||
# Build Docker image
|
||||
docker build \
|
||||
--platform "$PLATFORM" \
|
||||
-f "$DOCKERFILE" \
|
||||
-t my-app-builder:latest \
|
||||
--progress=plain \
|
||||
.
|
||||
|
||||
# Extract binary
|
||||
CONTAINER_ID=$(docker create my-app-builder:latest)
|
||||
docker cp "$CONTAINER_ID:/build/my_app_static" "$BUILD_DIR/$OUTPUT_NAME"
|
||||
docker rm "$CONTAINER_ID"
|
||||
|
||||
chmod +x "$BUILD_DIR/$OUTPUT_NAME"
|
||||
|
||||
echo "✓ Build complete: $BUILD_DIR/$OUTPUT_NAME"
|
||||
echo "✓ Size: $(du -h "$BUILD_DIR/$OUTPUT_NAME" | cut -f1)"
|
||||
|
||||
# Verify
|
||||
if ldd "$BUILD_DIR/$OUTPUT_NAME" 2>&1 | grep -q "not a dynamic executable"; then
|
||||
echo "✓ Binary is fully static"
|
||||
else
|
||||
echo "⚠ Warning: Binary may have dynamic dependencies"
|
||||
fi
|
||||
```
|
||||
|
||||
Make it executable:
|
||||
|
||||
```bash
|
||||
chmod +x build_static.sh
|
||||
./build_static.sh
|
||||
```
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### Issue 1: Fortification Errors
|
||||
|
||||
**Error:**
|
||||
```
|
||||
undefined reference to '__snprintf_chk'
|
||||
undefined reference to '__fprintf_chk'
|
||||
```
|
||||
|
||||
**Cause**: GCC's `-O2` enables fortification by default, which uses glibc-specific functions.
|
||||
|
||||
**Solution**: Add these flags to **all** compilation commands:
|
||||
```bash
|
||||
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0
|
||||
```
|
||||
|
||||
This must be applied to:
|
||||
1. nostr_core_lib build.sh
|
||||
2. Your application compilation
|
||||
3. Any other libraries you build
|
||||
|
||||
### Issue 2: Missing Symbols from nostr_core_lib
|
||||
|
||||
**Error:**
|
||||
```
|
||||
undefined reference to 'nostr_create_event'
|
||||
undefined reference to 'nostr_sign_event'
|
||||
```
|
||||
|
||||
**Cause**: Required NIPs not included in nostr_core_lib build.
|
||||
|
||||
**Solution**: Add missing NIPs:
|
||||
```bash
|
||||
./build.sh --nips=1,6,19 # Add the NIPs you need
|
||||
```
|
||||
|
||||
### Issue 3: Docker Permission Denied
|
||||
|
||||
**Error:**
|
||||
```
|
||||
permission denied while trying to connect to the Docker daemon socket
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
sudo usermod -aG docker $USER
|
||||
newgrp docker # Or logout and login
|
||||
```
|
||||
|
||||
### Issue 4: Binary Won't Run on Target System
|
||||
|
||||
**Checks**:
|
||||
```bash
|
||||
# 1. Verify it's static
|
||||
ldd my_app_static # Should show "not a dynamic executable"
|
||||
|
||||
# 2. Check architecture
|
||||
file my_app_static # Should match target system
|
||||
|
||||
# 3. Test on different distributions
|
||||
docker run --rm -v $(pwd):/app alpine:latest /app/my_app_static --version
|
||||
docker run --rm -v $(pwd):/app ubuntu:latest /app/my_app_static --version
|
||||
```
|
||||
|
||||
## Project Structure Example
|
||||
|
||||
Organize your project for easy static builds:
|
||||
|
||||
```
|
||||
my-nostr-app/
|
||||
├── src/
|
||||
│ ├── main.c
|
||||
│ ├── handlers.c
|
||||
│ └── utils.c
|
||||
├── nostr_core_lib/ # Git submodule
|
||||
├── nostr_login_lite/ # Git submodule (if used)
|
||||
├── Dockerfile.static # Static build Dockerfile
|
||||
├── build_static.sh # Build script
|
||||
├── Makefile # Regular build
|
||||
└── README.md
|
||||
```
|
||||
|
||||
### Makefile Integration
|
||||
|
||||
Add static build targets to your Makefile:
|
||||
|
||||
```makefile
|
||||
# Regular dynamic build
|
||||
all: my_app
|
||||
|
||||
my_app: src/*.c
|
||||
gcc -O2 src/*.c -o my_app \
|
||||
nostr_core_lib/libnostr_core_x64.a \
|
||||
-lssl -lcrypto -lsecp256k1 -lz -lpthread -lm
|
||||
|
||||
# Static MUSL build via Docker
|
||||
static:
|
||||
./build_static.sh
|
||||
|
||||
# Clean
|
||||
clean:
|
||||
rm -f my_app build/my_app_static_*
|
||||
|
||||
.PHONY: all static clean
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
### Single Binary Deployment
|
||||
|
||||
```bash
|
||||
# Copy to server
|
||||
scp build/my_app_static_x86_64 user@server:/opt/my-app/
|
||||
|
||||
# Run (no dependencies needed!)
|
||||
ssh user@server
|
||||
/opt/my-app/my_app_static_x86_64
|
||||
```
|
||||
|
||||
### SystemD Service
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=My Nostr Application
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=myapp
|
||||
WorkingDirectory=/opt/my-app
|
||||
ExecStart=/opt/my-app/my_app_static_x86_64
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### Docker Container (Minimal)
|
||||
|
||||
```dockerfile
|
||||
FROM scratch
|
||||
COPY my_app_static_x86_64 /app
|
||||
ENTRYPOINT ["/app"]
|
||||
```
|
||||
|
||||
Build and run:
|
||||
```bash
|
||||
docker build -t my-app:latest .
|
||||
docker run --rm my-app:latest --help
|
||||
```
|
||||
|
||||
## Reusing c-relay-pg Files
|
||||
|
||||
You can directly copy these files from c-relay-pg:
|
||||
|
||||
### 1. Dockerfile.alpine-musl
|
||||
```bash
|
||||
cp /path/to/c-relay-pg/Dockerfile.alpine-musl ./Dockerfile.static
|
||||
```
|
||||
|
||||
Then customize:
|
||||
- Change binary name (line 125)
|
||||
- Adjust source files (line 122-124)
|
||||
- Modify include paths (line 120-121)
|
||||
|
||||
### 2. build_static.sh
|
||||
```bash
|
||||
cp /path/to/c-relay-pg/build_static.sh ./
|
||||
```
|
||||
|
||||
Then customize:
|
||||
- Change `OUTPUT_NAME` variable (lines 66, 70)
|
||||
- Update Docker image name (line 98)
|
||||
- Modify verification commands (lines 180-184)
|
||||
|
||||
### 3. .dockerignore (Optional)
|
||||
```bash
|
||||
cp /path/to/c-relay-pg/.dockerignore ./
|
||||
```
|
||||
|
||||
Helps speed up Docker builds by excluding unnecessary files.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Version Control**: Commit your Dockerfile and build script
|
||||
2. **Tag Builds**: Include git commit hash in binary version
|
||||
3. **Test Thoroughly**: Verify on multiple distributions
|
||||
4. **Document Dependencies**: List required NIPs and libraries
|
||||
5. **Automate**: Use CI/CD to build on every commit
|
||||
6. **Archive Binaries**: Keep old versions for rollback
|
||||
|
||||
## Performance Comparison
|
||||
|
||||
| Metric | MUSL Static | glibc Dynamic |
|
||||
|--------|-------------|---------------|
|
||||
| Binary Size | 7-10 MB | 2-3 MB + libs |
|
||||
| Startup Time | ~50ms | ~40ms |
|
||||
| Memory Usage | Similar | Similar |
|
||||
| Portability | ✓ Universal | ✗ System-dependent |
|
||||
| Deployment | Single file | Binary + libraries |
|
||||
|
||||
## References
|
||||
|
||||
- [MUSL libc](https://musl.libc.org/)
|
||||
- [Alpine Linux](https://alpinelinux.org/)
|
||||
- [nostr_core_lib](https://github.com/chebizarro/nostr_core_lib)
|
||||
- [Static Linking Best Practices](https://www.musl-libc.org/faq.html)
|
||||
- [c-relay-pg Implementation](./docs/musl_static_build.md)
|
||||
|
||||
## Example: Minimal Nostr Client
|
||||
|
||||
Here's a complete example of building a minimal Nostr client:
|
||||
|
||||
```c
|
||||
// minimal_client.c
|
||||
#include "nostr_core/nostr_core.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
// Generate keypair
|
||||
char nsec[64], npub[64];
|
||||
nostr_generate_keypair(nsec, npub);
|
||||
|
||||
printf("Generated keypair:\n");
|
||||
printf("Private key (nsec): %s\n", nsec);
|
||||
printf("Public key (npub): %s\n", npub);
|
||||
|
||||
// Create event
|
||||
cJSON *event = nostr_create_event(1, "Hello, Nostr!", NULL);
|
||||
nostr_sign_event(event, nsec);
|
||||
|
||||
char *json = cJSON_Print(event);
|
||||
printf("\nSigned event:\n%s\n", json);
|
||||
|
||||
free(json);
|
||||
cJSON_Delete(event);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**Dockerfile.static:**
|
||||
```dockerfile
|
||||
FROM alpine:3.19 AS builder
|
||||
RUN apk add --no-cache build-base musl-dev git autoconf automake libtool \
|
||||
openssl-dev openssl-libs-static zlib-dev zlib-static
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Build secp256k1
|
||||
RUN cd /tmp && git clone https://github.com/bitcoin-core/secp256k1.git && \
|
||||
cd secp256k1 && ./autogen.sh && \
|
||||
./configure --enable-static --disable-shared --prefix=/usr CFLAGS="-fPIC" && \
|
||||
make -j$(nproc) && make install
|
||||
|
||||
# Copy and build nostr_core_lib
|
||||
COPY nostr_core_lib /build/nostr_core_lib/
|
||||
RUN cd nostr_core_lib && \
|
||||
sed -i 's/CFLAGS="-Wall/CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -Wall/' build.sh && \
|
||||
./build.sh --nips=1,6,19
|
||||
|
||||
# Build application
|
||||
COPY minimal_client.c /build/
|
||||
RUN gcc -static -O2 -Wall -std=c99 \
|
||||
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \
|
||||
-Inostr_core_lib -Inostr_core_lib/nostr_core -Inostr_core_lib/cjson \
|
||||
minimal_client.c -o /build/minimal_client_static \
|
||||
nostr_core_lib/libnostr_core_x64.a \
|
||||
-lssl -lcrypto -lsecp256k1 -lz -lpthread -lm -ldl && \
|
||||
strip /build/minimal_client_static
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /build/minimal_client_static /minimal_client_static
|
||||
```
|
||||
|
||||
**Build and run:**
|
||||
```bash
|
||||
docker build -f Dockerfile.static -t minimal-client .
|
||||
docker create --name temp minimal-client
|
||||
docker cp temp:/minimal_client_static ./
|
||||
docker rm temp
|
||||
|
||||
./minimal_client_static
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
Static MUSL binaries provide the best portability for C applications. While they're slightly larger than dynamic binaries, the benefits of zero dependencies and universal compatibility make them ideal for:
|
||||
|
||||
- Server deployments across different Linux distributions
|
||||
- Embedded systems and IoT devices
|
||||
- Docker containers (FROM scratch)
|
||||
- Distribution to users without dependency management
|
||||
- Long-term archival and reproducibility
|
||||
|
||||
Follow this guide to create portable, self-contained binaries for your Nostr applications!
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/** admin2/api/auth.php — Auth rules + WoT status. */
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
$pdo = db();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$action = $input['action'] ?? '';
|
||||
try {
|
||||
if ($action === 'add') {
|
||||
$pdo->prepare("INSERT INTO auth_rules (rule_type, pattern_type, pattern_value) VALUES (?, 'pubkey', ?)")->execute([$input['rule_type'], $input['pattern_value']]);
|
||||
json_response(['message' => 'Rule added']);
|
||||
} elseif ($action === 'remove') {
|
||||
$pdo->prepare("DELETE FROM auth_rules WHERE id = ?")->execute([intval($input['id'])]);
|
||||
json_response(['message' => 'Rule removed']);
|
||||
} elseif ($action === 'set_wot_level') {
|
||||
$pdo->prepare("UPDATE config SET value = ? WHERE key = 'wot_level'")->execute([strval($input['level'])]);
|
||||
json_response(['message' => 'WoT level set']);
|
||||
} elseif ($action === 'sync_wot') {
|
||||
json_response(['message' => 'WoT sync not available via PHP (requires relay)']);
|
||||
}
|
||||
} catch (PDOException $e) { json_response(['error' => $e->getMessage()]); }
|
||||
}
|
||||
|
||||
// GET: WoT status
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'wot') {
|
||||
$level = $pdo->query("SELECT value FROM config WHERE key = 'wot_level'")->fetchColumn() ?: '0';
|
||||
$wl_count = 0;
|
||||
try { $wl_count = intval($pdo->query("SELECT count(*) FROM auth_rules WHERE rule_type = 'whitelist'")->fetchColumn()); } catch (PDOException $e) {}
|
||||
$descriptions = ['0' => 'Level 0: Open relay — anyone can read and write', '1' => 'Level 1: Write only — WoT users can write', '2' => 'Level 2: Full — WoT users only'];
|
||||
json_response(['kind3_status' => 'N/A (PHP admin)', 'whitelist_count' => $wl_count, 'level_description' => $descriptions[$level] ?? $descriptions['0']]);
|
||||
}
|
||||
|
||||
// GET: auth rules
|
||||
$rules = [];
|
||||
try { $rules = $pdo->query("SELECT id, rule_type, pattern_type, pattern_value FROM auth_rules ORDER BY id")->fetchAll(); } catch (PDOException $e) {}
|
||||
json_response(['rules' => $rules]);
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
/** admin2/api/caching.php — Caching service status + follows + reset actions. */
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
$pdo = db();
|
||||
|
||||
// --- POST actions: reset backfill (all or per-user) ---
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$input = json_decode(file_get_contents('php://input'), true) ?: [];
|
||||
$action = $input['action'] ?? '';
|
||||
$pubkey = $input['pubkey'] ?? '';
|
||||
|
||||
if ($action === 'reset_all') {
|
||||
// Reset backfill progress for ALL followed authors, then bump config
|
||||
// generation so the running caching service hot-reloads and re-drains.
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
$pdo->exec("UPDATE caching_followed_pubkeys
|
||||
SET until_cursor = 0, backfill_complete = FALSE,
|
||||
events_fetched = 0,
|
||||
updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT");
|
||||
// Also reset per-relay progress rows
|
||||
$pdo->exec("UPDATE caching_backfill_relay_progress
|
||||
SET complete = FALSE, events_fetched = 0,
|
||||
until_cursor = 0, last_status = 'reset',
|
||||
consecutive_errors = 0,
|
||||
updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT");
|
||||
// Bump config generation to trigger hot-reload
|
||||
$pdo->exec("UPDATE config SET value = (COALESCE(value::int, 0) + 1)::text
|
||||
WHERE key = 'caching_config_generation'");
|
||||
$pdo->commit();
|
||||
json_response(['ok' => true, 'message' => 'All backfill progress reset. Caching service will re-drain.']);
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
json_response(['ok' => false, 'error' => $e->getMessage()], 500);
|
||||
}
|
||||
} elseif ($action === 'reset_user' && $pubkey) {
|
||||
// Reset backfill progress for a single followed author.
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
$stmt = $pdo->prepare("UPDATE caching_followed_pubkeys
|
||||
SET until_cursor = 0, backfill_complete = FALSE,
|
||||
events_fetched = 0,
|
||||
updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT
|
||||
WHERE pubkey = ?");
|
||||
$stmt->execute([$pubkey]);
|
||||
// Also reset per-relay progress for this author
|
||||
$stmt2 = $pdo->prepare("UPDATE caching_backfill_relay_progress
|
||||
SET complete = FALSE, events_fetched = 0,
|
||||
until_cursor = 0, last_status = 'reset',
|
||||
consecutive_errors = 0,
|
||||
updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT
|
||||
WHERE author_pubkey = ?");
|
||||
$stmt2->execute([$pubkey]);
|
||||
// Bump config generation to trigger hot-reload
|
||||
$pdo->exec("UPDATE config SET value = (COALESCE(value::int, 0) + 1)::text
|
||||
WHERE key = 'caching_config_generation'");
|
||||
$pdo->commit();
|
||||
json_response(['ok' => true, 'message' => "Backfill reset for pubkey. Caching service will re-fetch."]);
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
json_response(['ok' => false, 'error' => $e->getMessage()], 500);
|
||||
}
|
||||
} else {
|
||||
json_response(['ok' => false, 'error' => 'Unknown action'], 400);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Caching config values (for toggle controls)
|
||||
$config = [];
|
||||
try {
|
||||
$cfg_rows = $pdo->query("SELECT key, value FROM config WHERE key IN ('caching_enabled','caching_inbox_enabled','caching_live_enabled','caching_backfill_enabled')")->fetchAll();
|
||||
foreach ($cfg_rows as $r) { $config[$r['key']] = $r['value']; }
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// Service state
|
||||
$state = [];
|
||||
try { $state = $pdo->query("SELECT * FROM caching_service_state WHERE id = 1")->fetch() ?: []; } catch (PDOException $e) {}
|
||||
|
||||
// Active target
|
||||
$active = ['pubkey' => '', 'relay' => ''];
|
||||
try { $active = $pdo->query("SELECT active_pubkey AS pubkey, active_relay AS relay FROM caching_backfill_active WHERE id = 1")->fetch() ?: $active; } catch (PDOException $e) {}
|
||||
|
||||
// Inbox
|
||||
$inbox = ['pending' => 0, 'live' => 0, 'backfill' => 0];
|
||||
try {
|
||||
$inbox = $pdo->query("SELECT COUNT(*) AS pending, COUNT(*) FILTER (WHERE source_class='live') AS live, COUNT(*) FILTER (WHERE source_class='backfill') AS backfill FROM caching_event_inbox")->fetch() ?: $inbox;
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// Upstream relay status (per-relay connection state)
|
||||
$upstreamRelays = [];
|
||||
try {
|
||||
$upstreamRelays = $pdo->query("
|
||||
SELECT relay_url, status_code, status_text, updated_at
|
||||
FROM caching_upstream_relays
|
||||
ORDER BY relay_url
|
||||
")->fetchAll();
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// Follows (paginated, with names from profiles cache + per-relay progress)
|
||||
$page = max(1, (int)($_GET['page'] ?? 1));
|
||||
$perPage = 50;
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
$follows = [];
|
||||
$totalFollows = 0;
|
||||
try {
|
||||
$totalFollows = (int)$pdo->query("SELECT COUNT(*) FROM caching_followed_pubkeys")->fetchColumn();
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
try {
|
||||
$follows = $pdo->query("
|
||||
SELECT fp.pubkey, fp.is_root, fp.backfill_complete, fp.events_fetched,
|
||||
fp.last_event_at,
|
||||
p.name, p.display_name,
|
||||
(SELECT count(*) FROM events WHERE pubkey = fp.pubkey) AS total_events,
|
||||
(SELECT count(*) FROM caching_backfill_relay_progress WHERE author_pubkey = fp.pubkey) AS relay_count,
|
||||
(SELECT count(*) FROM caching_backfill_relay_progress WHERE author_pubkey = fp.pubkey AND complete = false) AS relay_incomplete
|
||||
FROM caching_followed_pubkeys fp
|
||||
LEFT JOIN profiles p ON p.pubkey = fp.pubkey
|
||||
ORDER BY fp.is_root DESC, fp.events_fetched DESC
|
||||
LIMIT $perPage OFFSET $offset
|
||||
")->fetchAll();
|
||||
// Fetch per-relay progress for all followed pubkeys in one query
|
||||
$relayProgress = [];
|
||||
try {
|
||||
$rpRows = $pdo->query("
|
||||
SELECT author_pubkey, relay_url, complete, events_fetched, until_cursor, last_status, updated_at
|
||||
FROM caching_backfill_relay_progress
|
||||
ORDER BY author_pubkey, events_fetched DESC
|
||||
")->fetchAll();
|
||||
foreach ($rpRows as $rp) {
|
||||
$relayProgress[$rp['author_pubkey']][] = $rp;
|
||||
}
|
||||
} catch (PDOException $e) {}
|
||||
foreach ($follows as &$f) {
|
||||
$f['name'] = profile_display_name($f);
|
||||
$f['npub'] = function_exists('hex_to_npub') ? hex_to_npub($f['pubkey']) : substr($f['pubkey'], 0, 20);
|
||||
$f['relays'] = $relayProgress[$f['pubkey']] ?? [];
|
||||
}
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
json_response([
|
||||
'state' => $state,
|
||||
'active' => $active,
|
||||
'inbox' => $inbox,
|
||||
'follows' => $follows,
|
||||
'config' => $config,
|
||||
'upstreamRelays' => $upstreamRelays,
|
||||
'totalFollows' => $totalFollows,
|
||||
'page' => $page,
|
||||
'perPage' => $perPage,
|
||||
]);
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* admin/api/chart.php — Standalone ASCII chart endpoint.
|
||||
*
|
||||
* Returns a plain-text ASCII X-bar chart of event counts over time.
|
||||
* Works in both the browser (injected into a <div>) and the terminal:
|
||||
*
|
||||
* curl http://localhost:8088/api/chart.php?range=hour
|
||||
* curl http://localhost:8088/api/chart.php?range=day
|
||||
* curl http://localhost:8088/api/chart.php?range=month
|
||||
* curl http://localhost:8088/api/chart.php?range=year
|
||||
*
|
||||
* This endpoint is read-only (a fixed aggregate COUNT query with the only
|
||||
* user input being the `range` selector, which is validated against a
|
||||
* whitelist). It is safe to expose publicly and is served without auth at:
|
||||
*
|
||||
* https://<domain>/relay/api/chart.php?range=day
|
||||
*
|
||||
* It is also reachable (behind Basic Auth) from the admin UI at:
|
||||
*
|
||||
* https://<domain>/relay/admin/api/chart.php?range=day
|
||||
*
|
||||
* Caching: the hour chart is never cached (live). Day/month/year are
|
||||
* cached to file with TTLs to avoid expensive queries on every request.
|
||||
*
|
||||
* NOTE: Uses first_seen (not created_at) for binning, because some events
|
||||
* have corrupted created_at timestamps (far-future values) that would
|
||||
* place them outside the visible chart range.
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
require_once __DIR__ . '/../lib/ascii_chart.php';
|
||||
|
||||
// --- Range configuration ---
|
||||
$ranges = [
|
||||
'hour' => ['span' => 3600, 'bin' => 45, 'bins' => 80, 'ttl' => 0, 'title' => 'New Events — Last Hour'],
|
||||
'day' => ['span' => 86400, 'bin' => 1080, 'bins' => 80, 'ttl' => 3600, 'title' => 'New Events — Last 24 Hours'],
|
||||
'month' => ['span' => 2592000, 'bin' => 32400, 'bins' => 80, 'ttl' => 86400, 'title' => 'New Events — Last 30 Days'],
|
||||
'year' => ['span' => 31536000, 'bin' => 394200, 'bins' => 80, 'ttl' => 2592000, 'title' => 'New Events — Last Year'],
|
||||
];
|
||||
|
||||
$range = $_GET['range'] ?? 'hour';
|
||||
if (!isset($ranges[$range])) {
|
||||
http_response_code(400);
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
echo "Invalid range. Use: hour, day, month, or year.\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$cfg = $ranges[$range];
|
||||
|
||||
// --- Set content type ---
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
|
||||
// --- Check cache ---
|
||||
if ($cfg['ttl'] > 0) {
|
||||
$cached = get_cached_chart($range, $cfg['ttl']);
|
||||
if ($cached !== null) {
|
||||
echo $cached;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Run binning query ---
|
||||
$pdo = db();
|
||||
$now = time();
|
||||
$epoch = $now - $cfg['span'];
|
||||
$bin_size = $cfg['bin'];
|
||||
$num_bins = $cfg['bins'];
|
||||
|
||||
try {
|
||||
// Calculate the bin offset so the rightmost bin aligns with "now"
|
||||
// bin index 0 = oldest, bin index (num_bins-1) = newest
|
||||
$base_bin = (int)floor($epoch / $bin_size);
|
||||
|
||||
// Use first_seen (not created_at) for binning, because some events
|
||||
// have corrupted created_at timestamps (far-future values) that
|
||||
// would place them outside the visible chart range.
|
||||
$sql = "SELECT FLOOR(first_seen / {$bin_size})::BIGINT - {$base_bin} AS bin, COUNT(*) AS cnt
|
||||
FROM events
|
||||
WHERE first_seen >= {$epoch}
|
||||
GROUP BY bin
|
||||
ORDER BY bin";
|
||||
$rows = $pdo->query($sql)->fetchAll();
|
||||
} catch (PDOException $e) {
|
||||
echo "Chart query failed: " . $e->getMessage() . "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
// --- Build bin array (zero-filled, fixed length) ---
|
||||
// Index 0 = oldest, index N-1 = newest (natural time order from SQL)
|
||||
$bins = build_bin_array($rows, $num_bins);
|
||||
|
||||
// Reverse so newest bin is at index 0 (leftmost) and oldest at right.
|
||||
// This matches the original text_graph.js display: new data enters
|
||||
// from the left and proceeds rightward as it ages.
|
||||
$bins = array_reverse($bins);
|
||||
|
||||
// --- Render ASCII chart ---
|
||||
$ascii = render_ascii_chart($bins, [
|
||||
'title' => $cfg['title'],
|
||||
'max_height' => 11,
|
||||
'bin_duration' => $bin_size,
|
||||
'label_interval' => max(1, (int)floor($num_bins / 15)), // ~15 labels across
|
||||
]);
|
||||
|
||||
// --- Write to cache (if TTL > 0) ---
|
||||
if ($cfg['ttl'] > 0) {
|
||||
set_cached_chart($range, $ascii);
|
||||
}
|
||||
|
||||
echo $ascii;
|
||||
|
||||
|
||||
// ================================
|
||||
// CACHE HELPERS
|
||||
// ================================
|
||||
|
||||
function get_cache_dir(): string {
|
||||
return __DIR__ . '/../cache';
|
||||
}
|
||||
|
||||
function get_cached_chart(string $range, int $ttl): ?string {
|
||||
$file = get_cache_dir() . "/chart_{$range}.txt";
|
||||
if (!file_exists($file)) return null;
|
||||
if (filemtime($file) < (time() - $ttl)) return null;
|
||||
$content = @file_get_contents($file);
|
||||
return ($content !== false) ? $content : null;
|
||||
}
|
||||
|
||||
function set_cached_chart(string $range, string $ascii): void {
|
||||
$dir = get_cache_dir();
|
||||
if (!is_dir($dir)) {
|
||||
@mkdir($dir, 0775, true);
|
||||
}
|
||||
@file_put_contents($dir . "/chart_{$range}.txt", $ascii);
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
/**
|
||||
* admin2/api/cleanup.php — Event Cleanup: Preview & Execute.
|
||||
*
|
||||
* GET — Preview a cleanup query (count + size estimate, no delete).
|
||||
* POST — Execute a cleanup query (dry_run=true for preview, false for delete).
|
||||
*/
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
|
||||
$pdo = db();
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
// ── Shared filter builder ──────────────────────────────────────────────
|
||||
// Returns [sql_conditions[], params[]] for the WHERE clauses.
|
||||
function build_filters(array $opts): array {
|
||||
$conds = [];
|
||||
$params = [];
|
||||
|
||||
// Kinds filter
|
||||
if (!empty($opts['kinds'])) {
|
||||
$kinds = is_array($opts['kinds']) ? $opts['kinds'] : explode(',', $opts['kinds']);
|
||||
$kinds = array_map('intval', $kinds);
|
||||
$kinds = array_filter($kinds, fn($v) => $v > 0);
|
||||
if (!empty($kinds)) {
|
||||
$placeholders = [];
|
||||
foreach ($kinds as $i => $k) {
|
||||
$key = ':kind_' . $i;
|
||||
$placeholders[] = $key;
|
||||
$params[$key] = $k;
|
||||
}
|
||||
$conds[] = 'e.kind IN (' . implode(',', $placeholders) . ')';
|
||||
}
|
||||
}
|
||||
|
||||
// Max age filter
|
||||
$max_age_days = intval($opts['max_age_days'] ?? 0);
|
||||
if ($max_age_days > 0) {
|
||||
$conds[] = 'e.created_at < EXTRACT(EPOCH FROM NOW())::BIGINT - :max_age_seconds';
|
||||
$params[':max_age_seconds'] = $max_age_days * 86400;
|
||||
}
|
||||
|
||||
// Follows filter
|
||||
$follows_filter = $opts['follows_filter'] ?? 'all';
|
||||
if ($follows_filter === 'follows') {
|
||||
$conds[] = 'e.pubkey IN (SELECT pubkey FROM caching_followed_pubkeys)';
|
||||
} elseif ($follows_filter === 'non_follows') {
|
||||
$conds[] = 'e.pubkey NOT IN (SELECT pubkey FROM caching_followed_pubkeys)';
|
||||
}
|
||||
|
||||
return [$conds, $params];
|
||||
}
|
||||
|
||||
// ── Build a WHERE clause string from conditions ────────────────────────
|
||||
function where_clause(array $conds): string {
|
||||
if (empty($conds)) return '';
|
||||
return 'AND ' . implode("\n AND ", $conds);
|
||||
}
|
||||
|
||||
// ── Format bytes as human-readable ─────────────────────────────────────
|
||||
function format_bytes(int $bytes): string {
|
||||
if ($bytes < 1024) return $bytes . ' B';
|
||||
if ($bytes < 1048576) return round($bytes / 1024, 1) . ' KB';
|
||||
if ($bytes < 1073741824) return round($bytes / 1048576, 1) . ' MB';
|
||||
return round($bytes / 1073741824, 2) . ' GB';
|
||||
}
|
||||
|
||||
// ── GET: Preview ───────────────────────────────────────────────────────
|
||||
if ($method === 'GET') {
|
||||
$opts = [
|
||||
'follows_filter' => $_GET['follows_filter'] ?? 'all',
|
||||
'kinds' => $_GET['kinds'] ?? '',
|
||||
'max_age_days' => intval($_GET['max_age_days'] ?? 0),
|
||||
'max_events' => intval($_GET['max_events'] ?? 0),
|
||||
];
|
||||
|
||||
list($conds, $params) = build_filters($opts);
|
||||
$where = where_clause($conds);
|
||||
|
||||
// Preview SQL (for display)
|
||||
$sql_preview = "SELECT COUNT(*) AS match_count,\n"
|
||||
. " COALESCE(SUM(pg_column_size(event_json)), 0) AS total_size_bytes\n"
|
||||
. "FROM events e\n"
|
||||
. "WHERE 1=1\n"
|
||||
. ($where ? " $where\n" : '');
|
||||
|
||||
// Count + size query
|
||||
$count_sql = "SELECT COUNT(*) AS match_count,\n"
|
||||
. " COALESCE(SUM(pg_column_size(event_json)), 0) AS total_size_bytes\n"
|
||||
. "FROM events e\n"
|
||||
. "WHERE 1=1 $where";
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare($count_sql);
|
||||
$stmt->execute($params);
|
||||
$row = $stmt->fetch();
|
||||
$match_count = intval($row['match_count'] ?? 0);
|
||||
$total_size_bytes = intval($row['total_size_bytes'] ?? 0);
|
||||
} catch (PDOException $e) {
|
||||
json_response(['error' => 'Preview query failed: ' . $e->getMessage()]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Kind breakdown
|
||||
$breakdown = [];
|
||||
if ($match_count > 0) {
|
||||
$breakdown_sql = "SELECT e.kind,\n"
|
||||
. " COUNT(*) AS count,\n"
|
||||
. " COALESCE(SUM(pg_column_size(e.event_json)), 0) AS size_bytes\n"
|
||||
. "FROM events e\n"
|
||||
. "WHERE 1=1 $where\n"
|
||||
. "GROUP BY e.kind\n"
|
||||
. "ORDER BY count DESC\n"
|
||||
. "LIMIT 50";
|
||||
try {
|
||||
$stmt = $pdo->prepare($breakdown_sql);
|
||||
$stmt->execute($params);
|
||||
$rows = $stmt->fetchAll();
|
||||
foreach ($rows as $r) {
|
||||
$breakdown[] = [
|
||||
'kind' => intval($r['kind']),
|
||||
'count' => intval($r['count']),
|
||||
'size_bytes' => intval($r['size_bytes']),
|
||||
];
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Breakdown is non-critical
|
||||
}
|
||||
}
|
||||
|
||||
// If a query_id was provided, update last_preview_count and last_preview_size_bytes
|
||||
$query_id = intval($_GET['query_id'] ?? 0);
|
||||
if ($query_id > 0) {
|
||||
try {
|
||||
$pdo->prepare(
|
||||
"UPDATE cleanup_saved_queries\n"
|
||||
. " SET last_preview_count = :count,\n"
|
||||
. " last_preview_size_bytes = :size\n"
|
||||
. " WHERE id = :id"
|
||||
)->execute([
|
||||
':id' => $query_id,
|
||||
':count' => $match_count,
|
||||
':size' => $total_size_bytes,
|
||||
]);
|
||||
} catch (PDOException $e) {}
|
||||
}
|
||||
|
||||
json_response([
|
||||
'match_count' => $match_count,
|
||||
'total_size_bytes' => $total_size_bytes,
|
||||
'total_size_human' => format_bytes($total_size_bytes),
|
||||
'avg_size_per_event' => $match_count > 0 ? intval($total_size_bytes / $match_count) : 0,
|
||||
'kinds_breakdown' => $breakdown,
|
||||
'sql_preview' => $sql_preview,
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// ── POST: Execute (or dry-run) ─────────────────────────────────────────
|
||||
if ($method === 'POST') {
|
||||
$body = json_decode(file_get_contents('php://input'), true);
|
||||
if (!$body) {
|
||||
json_response(['error' => 'Invalid JSON body']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$dry_run = !empty($body['dry_run']);
|
||||
$opts = [
|
||||
'follows_filter' => $body['follows_filter'] ?? 'all',
|
||||
'kinds' => $body['kinds'] ?? [],
|
||||
'max_age_days' => intval($body['max_age_days'] ?? 0),
|
||||
'max_events' => intval($body['max_events'] ?? 0),
|
||||
];
|
||||
|
||||
list($conds, $params) = build_filters($opts);
|
||||
$where = where_clause($conds);
|
||||
|
||||
// If dry_run, return preview (same as GET)
|
||||
if ($dry_run) {
|
||||
$count_sql = "SELECT COUNT(*) AS match_count,\n"
|
||||
. " COALESCE(SUM(pg_column_size(event_json)), 0) AS total_size_bytes\n"
|
||||
. "FROM events e\n"
|
||||
. "WHERE 1=1 $where";
|
||||
try {
|
||||
$stmt = $pdo->prepare($count_sql);
|
||||
$stmt->execute($params);
|
||||
$row = $stmt->fetch();
|
||||
$match_count = intval($row['match_count'] ?? 0);
|
||||
$total_size_bytes = intval($row['total_size_bytes'] ?? 0);
|
||||
} catch (PDOException $e) {
|
||||
json_response(['error' => 'Preview query failed: ' . $e->getMessage()]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Kind breakdown
|
||||
$breakdown = [];
|
||||
if ($match_count > 0) {
|
||||
$breakdown_sql = "SELECT e.kind, COUNT(*) AS count,\n"
|
||||
. " COALESCE(SUM(pg_column_size(e.event_json)), 0) AS size_bytes\n"
|
||||
. "FROM events e\n"
|
||||
. "WHERE 1=1 $where\n"
|
||||
. "GROUP BY e.kind\n"
|
||||
. "ORDER BY count DESC\n"
|
||||
. "LIMIT 50";
|
||||
try {
|
||||
$stmt = $pdo->prepare($breakdown_sql);
|
||||
$stmt->execute($params);
|
||||
foreach ($stmt->fetchAll() as $r) {
|
||||
$breakdown[] = [
|
||||
'kind' => intval($r['kind']),
|
||||
'count' => intval($r['count']),
|
||||
'size_bytes' => intval($r['size_bytes']),
|
||||
];
|
||||
}
|
||||
} catch (PDOException $e) {}
|
||||
}
|
||||
|
||||
json_response([
|
||||
'match_count' => $match_count,
|
||||
'total_size_bytes' => $total_size_bytes,
|
||||
'total_size_human' => format_bytes($total_size_bytes),
|
||||
'avg_size_per_event' => $match_count > 0 ? intval($total_size_bytes / $match_count) : 0,
|
||||
'kinds_breakdown' => $breakdown,
|
||||
'dry_run' => true,
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// ── Actual DELETE ──────────────────────────────────────────────────
|
||||
$max_events = intval($body['max_events'] ?? 0);
|
||||
$limit_clause = $max_events > 0 ? 'LIMIT :max_events' : '';
|
||||
|
||||
// First, get the count and size of what will be deleted
|
||||
$preview_sql = "SELECT COUNT(*) AS match_count,\n"
|
||||
. " COALESCE(SUM(pg_column_size(event_json)), 0) AS total_size_bytes\n"
|
||||
. "FROM events e\n"
|
||||
. "WHERE 1=1 $where";
|
||||
try {
|
||||
$stmt = $pdo->prepare($preview_sql);
|
||||
$stmt->execute($params);
|
||||
$row = $stmt->fetch();
|
||||
$expected_count = intval($row['match_count'] ?? 0);
|
||||
$expected_bytes = intval($row['total_size_bytes'] ?? 0);
|
||||
} catch (PDOException $e) {
|
||||
json_response(['error' => 'Pre-delete count failed: ' . $e->getMessage()]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Build the DELETE using id IN (subquery) for safe LIMIT + ORDER BY
|
||||
$delete_sql = "DELETE FROM events e\n"
|
||||
. "WHERE e.id IN (\n"
|
||||
. " SELECT e2.id FROM events e2\n"
|
||||
. " WHERE 1=1 $where\n"
|
||||
. " ORDER BY e2.created_at ASC\n"
|
||||
. " $limit_clause\n"
|
||||
. ")";
|
||||
|
||||
$start_time = microtime(true);
|
||||
try {
|
||||
$stmt = $pdo->prepare($delete_sql);
|
||||
if ($max_events > 0) {
|
||||
$params[':max_events'] = $max_events;
|
||||
}
|
||||
$stmt->execute($params);
|
||||
$deleted_count = $stmt->rowCount();
|
||||
} catch (PDOException $e) {
|
||||
json_response(['error' => 'Delete query failed: ' . $e->getMessage()]);
|
||||
exit;
|
||||
}
|
||||
$duration_ms = round((microtime(true) - $start_time) * 1000);
|
||||
|
||||
// If we deleted fewer than expected, the actual freed bytes are proportional
|
||||
$freed_bytes = $expected_count > 0
|
||||
? intval($expected_bytes * ($deleted_count / $expected_count))
|
||||
: 0;
|
||||
|
||||
json_response([
|
||||
'deleted_count' => $deleted_count,
|
||||
'freed_bytes' => $freed_bytes,
|
||||
'freed_human' => format_bytes($freed_bytes),
|
||||
'duration_ms' => $duration_ms,
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Unsupported method
|
||||
json_response(['error' => 'Method not allowed']);
|
||||
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
/**
|
||||
* admin2/api/cleanup_queries.php — Saved Cleanup Query CRUD.
|
||||
*
|
||||
* GET — List all saved queries.
|
||||
* POST — Create/update/delete/execute saved queries.
|
||||
*/
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
|
||||
$pdo = db();
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
/** Format bytes as human-readable. */
|
||||
function fmt_bytes(int $bytes): string {
|
||||
if ($bytes < 1024) return $bytes . ' B';
|
||||
if ($bytes < 1048576) return round($bytes / 1024, 1) . ' KB';
|
||||
if ($bytes < 1073741824) return round($bytes / 1048576, 1) . ' MB';
|
||||
return round($bytes / 1073741824, 2) . ' GB';
|
||||
}
|
||||
|
||||
// ── GET: List all saved queries ────────────────────────────────────────
|
||||
if ($method === 'GET') {
|
||||
try {
|
||||
$rows = $pdo->query(
|
||||
"SELECT id, name, follows_filter, kinds, max_age_days, max_events,\n"
|
||||
. " last_preview_count, last_preview_size_bytes,\n"
|
||||
. " last_executed_at, created_at, updated_at\n"
|
||||
. " FROM cleanup_saved_queries\n"
|
||||
. " ORDER BY updated_at DESC"
|
||||
)->fetchAll();
|
||||
} catch (PDOException $e) {
|
||||
// Table may not exist yet
|
||||
json_response(['queries' => []]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$queries = [];
|
||||
foreach ($rows as $r) {
|
||||
$kinds = $r['kinds'];
|
||||
if (is_string($kinds)) {
|
||||
// PostgreSQL returns {1,7} format — parse it
|
||||
$kinds = trim($kinds, '{}');
|
||||
$kinds = $kinds !== '' ? array_map('intval', explode(',', $kinds)) : [];
|
||||
} elseif (is_resource($kinds)) {
|
||||
$kinds = [];
|
||||
}
|
||||
|
||||
$queries[] = [
|
||||
'id' => intval($r['id']),
|
||||
'name' => $r['name'],
|
||||
'follows_filter' => $r['follows_filter'],
|
||||
'kinds' => $kinds,
|
||||
'max_age_days' => intval($r['max_age_days']),
|
||||
'max_events' => intval($r['max_events']),
|
||||
'last_preview_count' => intval($r['last_preview_count']),
|
||||
'last_preview_size_human' => fmt_bytes(intval($r['last_preview_size_bytes'])),
|
||||
'last_executed_at' => intval($r['last_executed_at']) > 0
|
||||
? date('Y-m-d H:i:s', intval($r['last_executed_at']))
|
||||
: null,
|
||||
'created_at' => date('Y-m-d H:i:s', intval($r['created_at'])),
|
||||
'updated_at' => date('Y-m-d H:i:s', intval($r['updated_at'])),
|
||||
];
|
||||
}
|
||||
|
||||
json_response(['queries' => $queries]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// ── POST: Actions ──────────────────────────────────────────────────────
|
||||
if ($method === 'POST') {
|
||||
$body = json_decode(file_get_contents('php://input'), true);
|
||||
if (!$body || empty($body['action'])) {
|
||||
json_response(['error' => 'Missing action']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$action = $body['action'];
|
||||
|
||||
// ── Save (create or update) ────────────────────────────────────────
|
||||
if ($action === 'save') {
|
||||
$id = $body['id'] ?? null;
|
||||
$name = trim($body['name'] ?? '');
|
||||
if ($name === '') {
|
||||
json_response(['error' => 'Name is required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$follows_filter = $body['follows_filter'] ?? 'all';
|
||||
if (!in_array($follows_filter, ['all', 'follows', 'non_follows'])) {
|
||||
$follows_filter = 'all';
|
||||
}
|
||||
|
||||
$kinds = $body['kinds'] ?? [];
|
||||
if (is_array($kinds)) {
|
||||
$kinds = array_map('intval', $kinds);
|
||||
$kinds = array_filter($kinds, fn($v) => $v > 0);
|
||||
$kinds = array_values($kinds);
|
||||
} else {
|
||||
$kinds = [];
|
||||
}
|
||||
// PostgreSQL array literal
|
||||
$kinds_pg = '{' . implode(',', $kinds) . '}';
|
||||
|
||||
$max_age_days = intval($body['max_age_days'] ?? 0);
|
||||
$max_events = intval($body['max_events'] ?? 0);
|
||||
|
||||
try {
|
||||
if ($id) {
|
||||
// Update existing
|
||||
$stmt = $pdo->prepare(
|
||||
"UPDATE cleanup_saved_queries\n"
|
||||
. " SET name = :name,\n"
|
||||
. " follows_filter = :follows_filter,\n"
|
||||
. " kinds = :kinds::integer[],\n"
|
||||
. " max_age_days = :max_age_days,\n"
|
||||
. " max_events = :max_events,\n"
|
||||
. " updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT\n"
|
||||
. " WHERE id = :id"
|
||||
);
|
||||
$stmt->execute([
|
||||
':id' => $id,
|
||||
':name' => $name,
|
||||
':follows_filter' => $follows_filter,
|
||||
':kinds' => $kinds_pg,
|
||||
':max_age_days' => $max_age_days,
|
||||
':max_events' => $max_events,
|
||||
]);
|
||||
} else {
|
||||
// Insert new
|
||||
$stmt = $pdo->prepare(
|
||||
"INSERT INTO cleanup_saved_queries\n"
|
||||
. " (name, follows_filter, kinds, max_age_days, max_events)\n"
|
||||
. "VALUES (:name, :follows_filter, :kinds::integer[],\n"
|
||||
. " :max_age_days, :max_events)\n"
|
||||
. "ON CONFLICT (name) DO UPDATE SET\n"
|
||||
. " follows_filter = EXCLUDED.follows_filter,\n"
|
||||
. " kinds = EXCLUDED.kinds,\n"
|
||||
. " max_age_days = EXCLUDED.max_age_days,\n"
|
||||
. " max_events = EXCLUDED.max_events,\n"
|
||||
. " updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT"
|
||||
);
|
||||
$stmt->execute([
|
||||
':name' => $name,
|
||||
':follows_filter' => $follows_filter,
|
||||
':kinds' => $kinds_pg,
|
||||
':max_age_days' => $max_age_days,
|
||||
':max_events' => $max_events,
|
||||
]);
|
||||
$id = $pdo->lastInsertId();
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
json_response(['error' => 'Save failed: ' . $e->getMessage()]);
|
||||
exit;
|
||||
}
|
||||
|
||||
json_response(['ok' => true, 'id' => intval($id)]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// ── Delete ─────────────────────────────────────────────────────────
|
||||
if ($action === 'delete') {
|
||||
$id = intval($body['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
json_response(['error' => 'Invalid id']);
|
||||
exit;
|
||||
}
|
||||
try {
|
||||
$stmt = $pdo->prepare("DELETE FROM cleanup_saved_queries WHERE id = :id");
|
||||
$stmt->execute([':id' => $id]);
|
||||
} catch (PDOException $e) {
|
||||
json_response(['error' => 'Delete failed: ' . $e->getMessage()]);
|
||||
exit;
|
||||
}
|
||||
json_response(['ok' => true]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// ── Execute (run a saved query as non-dry-run DELETE) ──────────────
|
||||
if ($action === 'execute') {
|
||||
$id = intval($body['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
json_response(['error' => 'Invalid id']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Load the saved query
|
||||
try {
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT id, name, follows_filter, kinds, max_age_days, max_events\n"
|
||||
. " FROM cleanup_saved_queries\n"
|
||||
. " WHERE id = :id"
|
||||
);
|
||||
$stmt->execute([':id' => $id]);
|
||||
$query = $stmt->fetch();
|
||||
} catch (PDOException $e) {
|
||||
json_response(['error' => 'Query load failed: ' . $e->getMessage()]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!$query) {
|
||||
json_response(['error' => 'Saved query not found']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Parse kinds from PG array
|
||||
$kinds_raw = $query['kinds'];
|
||||
if (is_string($kinds_raw)) {
|
||||
$kinds_raw = trim($kinds_raw, '{}');
|
||||
$kinds = $kinds_raw !== '' ? array_map('intval', explode(',', $kinds_raw)) : [];
|
||||
} else {
|
||||
$kinds = [];
|
||||
}
|
||||
|
||||
// Build filters (same logic as cleanup.php)
|
||||
$conds = [];
|
||||
$params = [];
|
||||
|
||||
if (!empty($kinds)) {
|
||||
$kind_placeholders = [];
|
||||
foreach ($kinds as $i => $k) {
|
||||
$key = ':kind_' . $i;
|
||||
$kind_placeholders[] = $key;
|
||||
$params[$key] = $k;
|
||||
}
|
||||
$conds[] = 'e.kind IN (' . implode(',', $kind_placeholders) . ')';
|
||||
}
|
||||
|
||||
$max_age_days = intval($query['max_age_days']);
|
||||
if ($max_age_days > 0) {
|
||||
$conds[] = 'e.created_at < EXTRACT(EPOCH FROM NOW())::BIGINT - :max_age_seconds';
|
||||
$params[':max_age_seconds'] = $max_age_days * 86400;
|
||||
}
|
||||
|
||||
$follows_filter = $query['follows_filter'];
|
||||
if ($follows_filter === 'follows') {
|
||||
$conds[] = 'e.pubkey IN (SELECT pubkey FROM caching_followed_pubkeys)';
|
||||
} elseif ($follows_filter === 'non_follows') {
|
||||
$conds[] = 'e.pubkey NOT IN (SELECT pubkey FROM caching_followed_pubkeys)';
|
||||
}
|
||||
|
||||
$where = !empty($conds) ? 'AND ' . implode("\n AND ", $conds) : '';
|
||||
|
||||
$max_events = intval($query['max_events']);
|
||||
$limit_clause = $max_events > 0 ? 'LIMIT :max_events' : '';
|
||||
|
||||
// Pre-delete count
|
||||
$preview_sql = "SELECT COUNT(*) AS match_count,\n"
|
||||
. " COALESCE(SUM(pg_column_size(event_json)), 0) AS total_size_bytes\n"
|
||||
. "FROM events e\n"
|
||||
. "WHERE 1=1 $where";
|
||||
try {
|
||||
$stmt = $pdo->prepare($preview_sql);
|
||||
$stmt->execute($params);
|
||||
$row = $stmt->fetch();
|
||||
$expected_count = intval($row['match_count'] ?? 0);
|
||||
$expected_bytes = intval($row['total_size_bytes'] ?? 0);
|
||||
} catch (PDOException $e) {
|
||||
json_response(['error' => 'Pre-delete count failed: ' . $e->getMessage()]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Execute DELETE
|
||||
$delete_sql = "DELETE FROM events e\n"
|
||||
. "WHERE e.id IN (\n"
|
||||
. " SELECT e2.id FROM events e2\n"
|
||||
. " WHERE 1=1 $where\n"
|
||||
. " ORDER BY e2.created_at ASC\n"
|
||||
. " $limit_clause\n"
|
||||
. ")";
|
||||
|
||||
$start_time = microtime(true);
|
||||
try {
|
||||
$stmt = $pdo->prepare($delete_sql);
|
||||
if ($max_events > 0) {
|
||||
$params[':max_events'] = $max_events;
|
||||
}
|
||||
$stmt->execute($params);
|
||||
$deleted_count = $stmt->rowCount();
|
||||
} catch (PDOException $e) {
|
||||
json_response(['error' => 'Delete failed: ' . $e->getMessage()]);
|
||||
exit;
|
||||
}
|
||||
$duration_ms = round((microtime(true) - $start_time) * 1000);
|
||||
|
||||
$freed_bytes = $expected_count > 0
|
||||
? intval($expected_bytes * ($deleted_count / $expected_count))
|
||||
: 0;
|
||||
|
||||
// Update last_preview_count, last_preview_size_bytes, last_executed_at
|
||||
try {
|
||||
$pdo->prepare(
|
||||
"UPDATE cleanup_saved_queries\n"
|
||||
. " SET last_preview_count = :count,\n"
|
||||
. " last_preview_size_bytes = :size,\n"
|
||||
. " last_executed_at = EXTRACT(EPOCH FROM NOW())::BIGINT\n"
|
||||
. " WHERE id = :id"
|
||||
)->execute([
|
||||
':id' => $id,
|
||||
':count' => $expected_count,
|
||||
':size' => $expected_bytes,
|
||||
]);
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
json_response([
|
||||
'deleted_count' => $deleted_count,
|
||||
'freed_bytes' => $freed_bytes,
|
||||
'freed_human' => fmt_bytes($freed_bytes),
|
||||
'duration_ms' => $duration_ms,
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
json_response(['error' => 'Unknown action: ' . $action]);
|
||||
exit;
|
||||
}
|
||||
|
||||
json_response(['error' => 'Method not allowed']);
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/** admin2/api/config.php — Config table read/edit (all keys). */
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
$pdo = db();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$key = $input['key'] ?? '';
|
||||
$value = $input['value'] ?? '';
|
||||
if (!$key) json_response(['error' => 'Missing key']);
|
||||
try {
|
||||
$pdo->prepare("UPDATE config SET value = ? WHERE key = ?")->execute([$value, $key]);
|
||||
json_response(['message' => "Updated $key"]);
|
||||
} catch (PDOException $e) {
|
||||
json_response(['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
$rows = $pdo->query("SELECT key, value FROM config ORDER BY key")->fetchAll();
|
||||
json_response(['config' => $rows]);
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/** admin2/api/dm.php — Direct messages (kind 4/14/15). */
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
$pdo = db();
|
||||
|
||||
$limit = min(200, intval($_GET['limit'] ?? 50));
|
||||
$rows = $pdo->prepare("SELECT id, pubkey, kind, created_at, content FROM events WHERE kind IN (4, 14, 15) ORDER BY created_at DESC LIMIT $limit");
|
||||
$rows->execute();
|
||||
$messages = $rows->fetchAll();
|
||||
|
||||
foreach ($messages as &$m) {
|
||||
$m['created_at'] = date('Y-m-d H:i:s', intval($m['created_at']));
|
||||
$m['content'] = substr($m['content'] ?? '', 0, 300);
|
||||
}
|
||||
|
||||
json_response(['messages' => $messages]);
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/** admin2/api/events.php — Recent relay events (paginated). */
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
$pdo = db();
|
||||
|
||||
$limit = min(200, intval($_GET['limit'] ?? 50));
|
||||
$offset = intval($_GET['offset'] ?? 0);
|
||||
$kind = $_GET['kind'] ?? '';
|
||||
|
||||
$where = [];
|
||||
$params = [];
|
||||
if ($kind !== '') { $where[] = 'kind = ?'; $params[] = intval($kind); }
|
||||
$where_sql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||||
|
||||
// Order by first_seen DESC to show most recently received events first,
|
||||
// avoiding corrupted created_at timestamps (e.g. far-future values) that
|
||||
// would otherwise dominate the ordering.
|
||||
$rows = $pdo->prepare("SELECT e.id, e.pubkey, e.kind, e.created_at, e.first_seen, e.content,
|
||||
p.name, p.display_name
|
||||
FROM events e
|
||||
LEFT JOIN profiles p ON p.pubkey = e.pubkey
|
||||
$where_sql
|
||||
ORDER BY e.first_seen DESC LIMIT $limit OFFSET $offset");
|
||||
$rows->execute($params);
|
||||
$events = $rows->fetchAll();
|
||||
|
||||
foreach ($events as &$e) {
|
||||
$e['created_at'] = date('Y-m-d H:i:s', intval($e['created_at']));
|
||||
$e['first_seen'] = date('Y-m-d H:i:s', intval($e['first_seen']));
|
||||
$e['content'] = substr($e['content'] ?? '', 0, 200);
|
||||
// Resolve display name from profiles cache; fall back to truncated pubkey.
|
||||
$best = profile_display_name($e);
|
||||
$e['display_name'] = $best !== '' ? $best : substr($e['pubkey'] ?? '', 0, 16) . '…';
|
||||
}
|
||||
|
||||
json_response(['events' => $events]);
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/** admin2/api/ipbans.php — IP ban management. */
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
$pdo = db();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$action = $input['action'] ?? '';
|
||||
try {
|
||||
if ($action === 'add') {
|
||||
$until = time() + intval($input['duration'] ?? 86400);
|
||||
$pdo->prepare("INSERT INTO ip_bans (ip, banned_until, ban_count) VALUES (?, ?, 1) ON CONFLICT (ip) DO UPDATE SET banned_until = ?, ban_count = ip_bans.ban_count + 1")->execute([$input['ip'], $until, $until]);
|
||||
json_response(['message' => 'IP banned']);
|
||||
} elseif ($action === 'remove') {
|
||||
$pdo->prepare("DELETE FROM ip_bans WHERE ip = ?")->execute([$input['ip']]);
|
||||
json_response(['message' => 'Ban removed']);
|
||||
}
|
||||
} catch (PDOException $e) { json_response(['error' => $e->getMessage()]); }
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$total = 0; $active = 0; $issued = 0;
|
||||
$bans = [];
|
||||
try {
|
||||
$total = intval($pdo->query("SELECT count(*) FROM ip_bans")->fetchColumn());
|
||||
$active = intval($pdo->query("SELECT count(*) FROM ip_bans WHERE banned_until > $now")->fetchColumn());
|
||||
$issued = intval($pdo->query("SELECT COALESCE(sum(ban_count),0) FROM ip_bans")->fetchColumn());
|
||||
$bans = $pdo->query("SELECT ip, banned_until, ban_count, failures, authed_successfully, connection_attempts FROM ip_bans ORDER BY banned_until DESC LIMIT 100")->fetchAll();
|
||||
foreach ($bans as &$b) {
|
||||
$b['status'] = intval($b['banned_until']) > $now ? 'banned' : 'expired';
|
||||
$b['banned_until'] = date('Y-m-d H:i:s', intval($b['banned_until']));
|
||||
}
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
json_response(['total' => $total, 'active' => $active, 'issued' => $issued, 'bans' => $bans]);
|
||||
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
/**
|
||||
* admin/api/kind_1_report.php — Markdown relay status report.
|
||||
*
|
||||
* Returns a markdown-formatted relay status report suitable for use as
|
||||
* a kind 1 event content. Includes:
|
||||
* - Relay name header
|
||||
* - 1H ASCII chart (event rate)
|
||||
* - Database overview
|
||||
* - Top 10 event kinds
|
||||
* - Time-based statistics
|
||||
* - Top pubkeys
|
||||
*
|
||||
* Accessible at: /relay/admin/api/kind_1_report.php
|
||||
*/
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
require_once __DIR__ . '/../lib/ascii_chart.php';
|
||||
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
|
||||
$pdo = db();
|
||||
|
||||
// --- Relay info ---
|
||||
$relay_name = 'C-Relay-PG';
|
||||
$relay_version = '';
|
||||
try {
|
||||
$relay_name = $pdo->query("SELECT value FROM config WHERE key = 'relay_name'")->fetchColumn() ?: 'C-Relay-PG';
|
||||
$relay_version = $pdo->query("SELECT value FROM config WHERE key = 'relay_version'")->fetchColumn() ?: '';
|
||||
} catch (PDOException $e) {}
|
||||
$display_name = $relay_version ? "$relay_name v$relay_version" : $relay_name;
|
||||
|
||||
// --- Total events ---
|
||||
$total_events = 0;
|
||||
try {
|
||||
$total_events = intval($pdo->query("SELECT COUNT(*) FROM events")->fetchColumn());
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// --- Database size ---
|
||||
$db_size = '-';
|
||||
try {
|
||||
$bytes = intval($pdo->query("SELECT pg_database_size(current_database())")->fetchColumn());
|
||||
if ($bytes < 1073741824) {
|
||||
$db_size = round($bytes / 1048576, 1) . ' MB';
|
||||
} else {
|
||||
$db_size = round($bytes / 1073741824, 2) . ' GB';
|
||||
}
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// --- Process ID ---
|
||||
$process_id = '-';
|
||||
try {
|
||||
$pid = $pdo->query("SELECT pg_backend_pid()")->fetchColumn();
|
||||
$process_id = strval($pid);
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// --- WebSocket connections (estimate from pg_class) ---
|
||||
$ws_connections = 0;
|
||||
try {
|
||||
$est = intval($pdo->query("SELECT reltuples FROM pg_class WHERE relname = 'subscriptions'")->fetchColumn());
|
||||
$ws_connections = max(0, intval($est * 0.2));
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// --- Active subscriptions (same estimate) ---
|
||||
$active_subscriptions = $ws_connections;
|
||||
|
||||
// --- Memory usage ---
|
||||
$memory_usage = '-';
|
||||
$mem_total = 0;
|
||||
$mem_avail = 0;
|
||||
$meminfo = @file_get_contents('/proc/meminfo');
|
||||
if ($meminfo !== false) {
|
||||
// /proc/meminfo uses "Key: Value kB" format (colon, not equals sign)
|
||||
foreach (explode("\n", $meminfo) as $line) {
|
||||
if (preg_match('/^MemTotal:\s+(\d+)\s+kB/i', $line, $m)) {
|
||||
$mem_total = intval($m[1]) * 1024;
|
||||
} elseif (preg_match('/^MemAvailable:\s+(\d+)\s+kB/i', $line, $m)) {
|
||||
$mem_avail = intval($m[1]) * 1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($mem_total > 0) {
|
||||
$used = $mem_total - $mem_avail;
|
||||
if ($used < 1073741824) {
|
||||
$memory_usage = round($used / 1048576, 1) . ' MB / ' . round($mem_total / 1073741824, 2) . ' GB';
|
||||
} else {
|
||||
$memory_usage = round($used / 1073741824, 2) . ' GB / ' . round($mem_total / 1073741824, 2) . ' GB';
|
||||
}
|
||||
}
|
||||
|
||||
// --- CPU ---
|
||||
$cpu_usage = '-';
|
||||
$cpu_core = '-';
|
||||
if (is_readable('/proc/cpuinfo')) {
|
||||
$cores = intval(@shell_exec('nproc 2>/dev/null') ?: 1);
|
||||
$cpu_core = strval($cores) . ' cores';
|
||||
}
|
||||
$load = @file_get_contents('/proc/loadavg');
|
||||
if ($load !== false) {
|
||||
$cpu_usage = trim(explode(' ', $load)[0] ?? '-');
|
||||
}
|
||||
|
||||
// --- Oldest / newest event ---
|
||||
$oldest_event = '-';
|
||||
$newest_event = '-';
|
||||
try {
|
||||
$row = $pdo->query("SELECT MIN(created_at) AS oldest, MAX(created_at) AS newest FROM events")->fetch();
|
||||
if ($row && $row['oldest']) $oldest_event = date('Y-m-d H:i:s', intval($row['oldest']));
|
||||
if ($row && $row['newest']) $newest_event = date('Y-m-d H:i:s', intval($row['newest']));
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// --- Time-based stats ---
|
||||
$now = time();
|
||||
$events_24h = 0; $events_7d = 0; $events_30d = 0;
|
||||
try {
|
||||
$events_24h = intval($pdo->query("SELECT COUNT(*) FROM events WHERE created_at >= $now - 86400")->fetchColumn());
|
||||
$events_7d = intval($pdo->query("SELECT COUNT(*) FROM events WHERE created_at >= $now - 604800")->fetchColumn());
|
||||
$events_30d = intval($pdo->query("SELECT COUNT(*) FROM events WHERE created_at >= $now - 2592000")->fetchColumn());
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// --- Kind distribution (top 10) ---
|
||||
$kinds = [];
|
||||
try {
|
||||
$rows = $pdo->query("SELECT kind, COUNT(*) AS cnt FROM events GROUP BY kind ORDER BY cnt DESC LIMIT 10")->fetchAll();
|
||||
foreach ($rows as $r) {
|
||||
$kinds[] = ['kind' => intval($r['kind']), 'count' => intval($r['cnt']), 'pct' => $total_events > 0 ? round(intval($r['cnt']) / $total_events * 100, 1) : 0];
|
||||
}
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// --- Top pubkeys (top 20) ---
|
||||
$top_pubkeys = [];
|
||||
try {
|
||||
$rows = $pdo->query("
|
||||
SELECT pubkey, COUNT(*) AS cnt
|
||||
FROM events
|
||||
GROUP BY pubkey
|
||||
ORDER BY cnt DESC LIMIT 20
|
||||
")->fetchAll();
|
||||
$pubkeys = array_column($rows, 'pubkey');
|
||||
$pmap = profile_map($pubkeys);
|
||||
foreach ($rows as $r) {
|
||||
$pk = $r['pubkey'];
|
||||
$prof = $pmap[$pk] ?? null;
|
||||
$top_pubkeys[] = [
|
||||
'pubkey' => $pk,
|
||||
'name' => $prof ? $prof['best_name'] : '',
|
||||
'count' => intval($r['cnt']),
|
||||
'pct' => $total_events > 0 ? round(intval($r['cnt']) / $total_events * 100, 1) : 0,
|
||||
];
|
||||
}
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// --- 1H ASCII chart (30 bins of 2 minutes each) ---
|
||||
$chart = '';
|
||||
try {
|
||||
$span = 3600;
|
||||
$bin_size = 120; // 2 minutes
|
||||
$num_bins = 30;
|
||||
$epoch = $now - $span;
|
||||
$base_bin = (int)floor($epoch / $bin_size);
|
||||
$sql = "SELECT FLOOR(created_at / {$bin_size})::BIGINT - {$base_bin} AS bin, COUNT(*) AS cnt
|
||||
FROM events
|
||||
WHERE created_at >= {$epoch}
|
||||
GROUP BY bin
|
||||
ORDER BY bin";
|
||||
$rows = $pdo->query($sql)->fetchAll();
|
||||
$bins = build_bin_array($rows, $num_bins);
|
||||
$bins = array_reverse($bins);
|
||||
$chart = render_ascii_chart($bins, [
|
||||
'title' => 'Event Rate (Last Hour)',
|
||||
'max_height' => 11,
|
||||
'bin_duration' => $bin_size,
|
||||
'label_interval' => 5, // label every 5 bins (10 min)
|
||||
]);
|
||||
} catch (PDOException $e) {
|
||||
$chart = "Chart unavailable\n";
|
||||
}
|
||||
|
||||
// ================================
|
||||
// BUILD MARKDOWN OUTPUT
|
||||
// ================================
|
||||
|
||||
$output = '';
|
||||
|
||||
// Chart
|
||||
$output .= "## laantungir.net/relay\n\n";
|
||||
$output .= "```\n$chart```\n";
|
||||
|
||||
// Database Overview
|
||||
$output .= "## Database Overview\n\n";
|
||||
$output .= "| Metric | Value |\n";
|
||||
$output .= "|--------|-------|\n";
|
||||
$output .= "| Database Size | $db_size |\n";
|
||||
$output .= "| Total Events | " . number_format($total_events) . " |\n";
|
||||
$output .= "| Process ID | $process_id |\n";
|
||||
$output .= "| WebSocket Connections | " . number_format($ws_connections) . " |\n";
|
||||
$output .= "| Active Subscriptions | " . number_format($active_subscriptions) . " |\n";
|
||||
$output .= "| Memory Usage | $memory_usage |\n";
|
||||
$output .= "| CPU Usage | $cpu_usage |\n";
|
||||
$output .= "| CPU Core | $cpu_core |\n";
|
||||
$output .= "| Oldest Event | $oldest_event |\n";
|
||||
$output .= "| Newest Event | $newest_event |\n\n";
|
||||
|
||||
// Event Kinds (Top 10)
|
||||
$output .= "## Event Kinds (Top 10)\n\n";
|
||||
$output .= "| Kind | Count | % |\n";
|
||||
$output .= "|------|-------|---|\n";
|
||||
foreach ($kinds as $k) {
|
||||
$output .= "| {$k['kind']} | " . number_format($k['count']) . " | {$k['pct']}% |\n";
|
||||
}
|
||||
$output .= "\n";
|
||||
|
||||
// Time-Based Statistics
|
||||
$output .= "## Time-Based Statistics\n\n";
|
||||
$output .= "| Period | Events |\n";
|
||||
$output .= "|--------|-------|\n";
|
||||
$output .= "| 24 Hours | " . number_format($events_24h) . " |\n";
|
||||
$output .= "| 7 Days | " . number_format($events_7d) . " |\n";
|
||||
$output .= "| 30 Days | " . number_format($events_30d) . " |\n\n";
|
||||
|
||||
// Top Pubkeys
|
||||
$output .= "## Top Pubkeys\n\n";
|
||||
$output .= "| Name | Events | % |\n";
|
||||
$output .= "|------|-------|---|\n";
|
||||
foreach ($top_pubkeys as $p) {
|
||||
if ($p['name']) {
|
||||
$name = $p['name'];
|
||||
} else {
|
||||
$name = substr($p['pubkey'], 0, 4) . '..' . substr($p['pubkey'], -4);
|
||||
}
|
||||
$output .= "| $name | " . number_format($p['count']) . " | {$p['pct']}% |\n";
|
||||
}
|
||||
$output .= "\n";
|
||||
|
||||
// Footer
|
||||
$output .= "---\n";
|
||||
$output .= "_Report generated: " . date('Y-m-d H:i:s T') . "_\n";
|
||||
|
||||
echo $output;
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* admin/api/profile.php — Single-profile lookup from the profiles cache.
|
||||
* Returns cached kind-0 metadata for a given pubkey.
|
||||
*
|
||||
* Usage: profile.php?pubkey=<64-char-hex>
|
||||
* Returns: { "pubkey": "...", "name": "...", "display_name": "...",
|
||||
* "best_name": "...", "picture": "...", "nip05": "...",
|
||||
* "about": "...", "website": "...", "lud16": "..." }
|
||||
* or { "error": "not found" } with HTTP 404 if no profile is cached.
|
||||
*/
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
|
||||
$pubkey = trim($_GET['pubkey'] ?? '');
|
||||
if (!preg_match('/^[0-9a-fA-F]{64}$/', $pubkey)) {
|
||||
http_response_code(400);
|
||||
json_response(['error' => 'Invalid pubkey']);
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
try {
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT pubkey, name, display_name, about, picture, banner,
|
||||
nip05, website, lud16, lud06
|
||||
FROM profiles WHERE pubkey = ?"
|
||||
);
|
||||
$stmt->execute([$pubkey]);
|
||||
$row = $stmt->fetch();
|
||||
if (!$row) {
|
||||
http_response_code(404);
|
||||
json_response(['error' => 'not found']);
|
||||
}
|
||||
$row['best_name'] = profile_display_name($row);
|
||||
json_response($row);
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
json_response(['error' => 'Database error']);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/** admin2/api/query.php — Direct SQL query (SELECT only, admin only). */
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
$pdo = db();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
json_response(['error' => 'POST only']);
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$sql = trim($input['sql'] ?? '');
|
||||
|
||||
if (!$sql) json_response(['error' => 'No query provided']);
|
||||
if (!preg_match('/^\s*SELECT/i', $sql)) json_response(['error' => 'Only SELECT queries are allowed']);
|
||||
|
||||
$start = microtime(true);
|
||||
try {
|
||||
$stmt = $pdo->query($sql);
|
||||
$rows = $stmt->fetchAll();
|
||||
$time_ms = round((microtime(true) - $start) * 1000, 1);
|
||||
json_response(['rows' => $rows, 'row_count' => count($rows), 'time_ms' => $time_ms]);
|
||||
} catch (PDOException $e) {
|
||||
json_response(['error' => $e->getMessage()]);
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
/**
|
||||
* admin2/api/stats.php — Statistics page data.
|
||||
* Returns DB size, event counts, kind distribution, top pubkeys,
|
||||
* time-based stats, and event-rate delta (for the chart).
|
||||
*/
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
|
||||
$pdo = db();
|
||||
|
||||
// Database size
|
||||
$db_size = '-';
|
||||
try {
|
||||
$bytes = $pdo->query("SELECT pg_database_size(current_database())")->fetchColumn();
|
||||
$db_size = format_bytes(intval($bytes));
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// Total events
|
||||
$total_events = intval($pdo->query("SELECT COUNT(*) FROM events")->fetchColumn());
|
||||
|
||||
// Event rate: events with first_seen in last 10 seconds
|
||||
$events_delta = 0;
|
||||
try {
|
||||
$events_delta = intval($pdo->query("SELECT COUNT(*) FROM events WHERE first_seen >= EXTRACT(EPOCH FROM NOW())::BIGINT - 10")->fetchColumn());
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// Process info
|
||||
$process_id = '-';
|
||||
try {
|
||||
$pid = $pdo->query("SELECT pg_backend_pid()")->fetchColumn();
|
||||
$process_id = strval($pid);
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// WebSocket connections: tracked in-memory by the relay (g_connection_count).
|
||||
// The subscriptions table is a 32M-row historical log, not a live state table.
|
||||
// Use pg_class for an instant estimate (updated by autovacuum).
|
||||
$ws_connections = 0;
|
||||
try {
|
||||
$est = intval($pdo->query("SELECT reltuples FROM pg_class WHERE relname = 'subscriptions'")->fetchColumn());
|
||||
// ~60% are 'created', ~40% are 'closed' — active ≈ created - closed
|
||||
$ws_connections = max(0, intval($est * 0.2));
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// Active subscriptions: same estimate approach.
|
||||
$active_subscriptions = $ws_connections;
|
||||
|
||||
// Memory/CPU (from /proc on Linux)
|
||||
$memory_usage = '-';
|
||||
$cpu_usage = '-';
|
||||
$cpu_core = '-';
|
||||
$mem_total = 0;
|
||||
$mem_avail = 0;
|
||||
$meminfo = @file_get_contents('/proc/meminfo');
|
||||
if ($meminfo !== false) {
|
||||
// /proc/meminfo uses "Key: Value kB" format (colon, not equals sign)
|
||||
foreach (explode("\n", $meminfo) as $line) {
|
||||
if (preg_match('/^MemTotal:\s+(\d+)\s+kB/i', $line, $m)) {
|
||||
$mem_total = intval($m[1]) * 1024;
|
||||
} elseif (preg_match('/^MemAvailable:\s+(\d+)\s+kB/i', $line, $m)) {
|
||||
$mem_avail = intval($m[1]) * 1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($mem_total > 0 && $mem_avail > 0) {
|
||||
$memory_usage = format_bytes($mem_total - $mem_avail) . ' / ' . format_bytes($mem_total);
|
||||
} elseif ($mem_total > 0) {
|
||||
$memory_usage = format_bytes($mem_total);
|
||||
}
|
||||
if (is_readable('/proc/cpuinfo')) {
|
||||
$cores = intval(@shell_exec('nproc 2>/dev/null') ?: 1);
|
||||
$cpu_core = strval($cores) . ' cores';
|
||||
}
|
||||
$cpu_usage = @file_get_contents('/proc/loadavg');
|
||||
if ($cpu_usage !== false) $cpu_usage = trim(explode(' ', $cpu_usage)[0] ?? '-');
|
||||
|
||||
// Oldest / newest event (single query)
|
||||
$oldest_event = '-';
|
||||
$newest_event = '-';
|
||||
try {
|
||||
$row = $pdo->query("SELECT MIN(created_at) AS oldest, MAX(created_at) AS newest FROM events")->fetch();
|
||||
if ($row && $row['oldest']) {
|
||||
$oldest_event = date('Y-m-d H:i:s', intval($row['oldest']));
|
||||
}
|
||||
if ($row && $row['newest']) {
|
||||
$newest_event = date('Y-m-d H:i:s', intval($row['newest']));
|
||||
}
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// Time-based stats
|
||||
$now = time();
|
||||
$events_24h = 0; $events_7d = 0; $events_30d = 0;
|
||||
try {
|
||||
$events_24h = intval($pdo->query("SELECT COUNT(*) FROM events WHERE created_at >= $now - 86400")->fetchColumn());
|
||||
$events_7d = intval($pdo->query("SELECT COUNT(*) FROM events WHERE created_at >= $now - 604800")->fetchColumn());
|
||||
$events_30d = intval($pdo->query("SELECT COUNT(*) FROM events WHERE created_at >= $now - 2592000")->fetchColumn());
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// Kind distribution — cached to file, refreshed every 5 minutes
|
||||
$kinds = [];
|
||||
$cache_dir = __DIR__ . '/../cache';
|
||||
if (!is_dir($cache_dir)) @mkdir($cache_dir, 0755, true);
|
||||
$kinds_cache = $cache_dir . '/stats_kinds.json';
|
||||
$kinds_ttl = 300;
|
||||
if (is_readable($kinds_cache) && (time() - filemtime($kinds_cache)) < $kinds_ttl) {
|
||||
$kinds = json_decode(file_get_contents($kinds_cache), true) ?: [];
|
||||
} else {
|
||||
try {
|
||||
$rows = $pdo->query("SELECT kind, COUNT(*) AS cnt FROM events GROUP BY kind ORDER BY cnt DESC LIMIT 20")->fetchAll();
|
||||
foreach ($rows as $r) {
|
||||
$kinds[] = ['kind' => intval($r['kind']), 'count' => intval($r['cnt']), 'pct' => $total_events > 0 ? round(intval($r['cnt']) / $total_events * 100, 1) : 0];
|
||||
}
|
||||
@file_put_contents($kinds_cache, json_encode($kinds));
|
||||
} catch (PDOException $e) {}
|
||||
}
|
||||
|
||||
// Top pubkeys — cached to file, refreshed every 5 minutes
|
||||
$top_pubkeys = [];
|
||||
$pubkeys_cache = $cache_dir . '/stats_pubkeys.json';
|
||||
if (is_readable($pubkeys_cache) && (time() - filemtime($pubkeys_cache)) < $kinds_ttl) {
|
||||
$top_pubkeys = json_decode(file_get_contents($pubkeys_cache), true) ?: [];
|
||||
} else {
|
||||
try {
|
||||
$rows = $pdo->query("
|
||||
SELECT pubkey, COUNT(*) AS cnt
|
||||
FROM events
|
||||
GROUP BY pubkey
|
||||
ORDER BY cnt DESC LIMIT 20
|
||||
")->fetchAll();
|
||||
$pubkeys = array_column($rows, 'pubkey');
|
||||
$pmap = profile_map($pubkeys);
|
||||
foreach ($rows as $r) {
|
||||
$pk = $r['pubkey'];
|
||||
$prof = $pmap[$pk] ?? null;
|
||||
$top_pubkeys[] = [
|
||||
'pubkey' => $pk,
|
||||
'name' => $prof ? $prof['best_name'] : '',
|
||||
'count' => intval($r['cnt']),
|
||||
'pct' => $total_events > 0 ? round(intval($r['cnt']) / $total_events * 100, 1) : 0,
|
||||
];
|
||||
}
|
||||
@file_put_contents($pubkeys_cache, json_encode($top_pubkeys));
|
||||
} catch (PDOException $e) {}
|
||||
}
|
||||
|
||||
// Name-field usage stats (from profiles cache)
|
||||
$name_field_usage = ['both' => 0, 'name_only' => 0, 'display_only' => 0, 'neither' => 0, 'both_differ' => 0, 'total' => 0];
|
||||
try {
|
||||
$row = $pdo->query("
|
||||
SELECT count(*) FILTER (WHERE name <> '' AND display_name <> '') AS both,
|
||||
count(*) FILTER (WHERE name <> '' AND display_name = '') AS name_only,
|
||||
count(*) FILTER (WHERE name = '' AND display_name <> '') AS display_only,
|
||||
count(*) FILTER (WHERE name = '' AND display_name = '') AS neither,
|
||||
count(*) FILTER (WHERE name <> '' AND display_name <> '' AND name <> display_name) AS both_differ,
|
||||
count(*) AS total
|
||||
FROM profiles
|
||||
")->fetch();
|
||||
if ($row) {
|
||||
$name_field_usage = array_map('intval', $row);
|
||||
}
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
json_response([
|
||||
'db_size' => $db_size,
|
||||
'total_events' => $total_events,
|
||||
'events_delta' => $events_delta,
|
||||
'process_id' => $process_id,
|
||||
'ws_connections' => $ws_connections,
|
||||
'active_subscriptions' => $active_subscriptions,
|
||||
'memory_usage' => $memory_usage,
|
||||
'cpu_usage' => $cpu_usage,
|
||||
'cpu_core' => $cpu_core,
|
||||
'oldest_event' => $oldest_event,
|
||||
'newest_event' => $newest_event,
|
||||
'events_24h' => $events_24h,
|
||||
'events_7d' => $events_7d,
|
||||
'events_30d' => $events_30d,
|
||||
'kinds' => $kinds,
|
||||
'top_pubkeys' => $top_pubkeys,
|
||||
'name_field_usage' => $name_field_usage,
|
||||
]);
|
||||
|
||||
/** Format bytes as human-readable. */
|
||||
function format_bytes(int $bytes): string {
|
||||
if ($bytes < 1024) return $bytes . ' B';
|
||||
if ($bytes < 1048576) return round($bytes / 1024, 1) . ' KB';
|
||||
if ($bytes < 1073741824) return round($bytes / 1048576, 1) . ' MB';
|
||||
return round($bytes / 1073741824, 2) . ' GB';
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
/** admin2/api/subscriptions.php — Active subscription details. */
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
$pdo = db();
|
||||
|
||||
$subs = [];
|
||||
try {
|
||||
$subs = $pdo->query("SELECT id, sub_id, pubkey, filters, created_at, events_sent FROM subscriptions ORDER BY created_at DESC LIMIT 100")->fetchAll();
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
json_response(['subscriptions' => $subs]);
|
||||
+1328
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
New Events — Last 24 Hours
|
||||
|
||||
21 |
|
||||
19 |
|
||||
17 |
|
||||
15 |
|
||||
13 |
|
||||
11 | X
|
||||
9 | X
|
||||
7 | X
|
||||
5 | X
|
||||
3 | X X X
|
||||
1 | X X X X X XX X X XX X X X X X X X X XX X X X XX X X
|
||||
+--------------------------------------------------------------------------------
|
||||
0s 1h 3h 4h 6h 7h 9h 10h 12h 13h 15h 16h 18h 19h 21h 22h
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
New Events — Last 30 Days
|
||||
|
||||
81 | X
|
||||
73 | XX X
|
||||
65 | XX X
|
||||
57 | XX X X X
|
||||
49 | X X XX XX X X X
|
||||
41 | X X X XX X X X XXX XXX XXX X X X X
|
||||
33 | X X X XXXX XX X X X XX XXX XXXXXXXX XX X X X X X XX
|
||||
25 |X XX XX XX XXXX XX XXX X XX XXXXXXXXXXXXXXXXXXXX XX XXX X XX XX XXXXX
|
||||
17 |X XXXXX XX XXXXXXXXXXXXXXX X XX XXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXX XX XXXXXXXX
|
||||
9 |XXX XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXX
|
||||
1 |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
+--------------------------------------------------------------------------------
|
||||
0s 1d 3d 5d 7d 9d 11d 13d 15d 16d 18d 20d 22d 24d 26d 28d
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
New Events — Last Year
|
||||
|
||||
531 | X XX
|
||||
478 | X X X XXX X
|
||||
425 | X X XX X XX XXX X
|
||||
372 | XXX XX X XX XXX X
|
||||
319 |XXXXXXXXXXX X X X XXXXXXX X
|
||||
266 |XXXXXXXXXXXX X XX XXX XXXXXXXXX X
|
||||
213 |XXXXXXXXXXXXXX XXX XXXXXXXXXXXXX XX X
|
||||
160 |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X X XXXX X
|
||||
107 |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XX XX XX X X X XX XXX X XXXXXXX X
|
||||
54 |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXX
|
||||
1 |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
+--------------------------------------------------------------------------------
|
||||
0s 22d 45d 68d 91d 114d 136d 159d 182d 205d 228d 250d 273d 296d 319d 342d
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
[]
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
[]
|
||||
+523
@@ -0,0 +1,523 @@
|
||||
<?php
|
||||
/**
|
||||
* admin2 — Full PHP admin for C-Relay-PG.
|
||||
* Recreates the original api/ admin interface with a PHP/PDO backend
|
||||
* instead of Nostr WebSocket admin commands.
|
||||
*/
|
||||
require_once __DIR__ . '/lib/helpers.php';
|
||||
$pdo = db();
|
||||
|
||||
// Fetch relay info for the header (from config table)
|
||||
$relay_name = '';
|
||||
$relay_desc = '';
|
||||
$relay_pubkey = '';
|
||||
$relay_version = '';
|
||||
try {
|
||||
$relay_name = $pdo->query("SELECT value FROM config WHERE key = 'relay_name'")->fetchColumn() ?: 'C-Relay-PG';
|
||||
$relay_desc = $pdo->query("SELECT value FROM config WHERE key = 'relay_description'")->fetchColumn() ?: '';
|
||||
$relay_pubkey = $pdo->query("SELECT value FROM config WHERE key = 'relay_pubkey'")->fetchColumn() ?: '';
|
||||
$relay_version = $pdo->query("SELECT value FROM config WHERE key = 'relay_version'")->fetchColumn() ?: '';
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// Convert relay pubkey (hex) to npub and format into 3 lines of 3 groups of 7 chars
|
||||
$relay_npub = $relay_pubkey;
|
||||
if ($relay_pubkey && preg_match('/^[0-9a-fA-F]{64}$/', $relay_pubkey)) {
|
||||
$relay_npub = hex_to_npub($relay_pubkey);
|
||||
}
|
||||
// Format npub (63 chars) into 3 lines of "xxxxxxx xxxxxxx xxxxxxx"
|
||||
$formatted_npub = $relay_npub;
|
||||
if (strlen($relay_npub) === 63) {
|
||||
$line1 = substr($relay_npub, 0, 7) . ' ' . substr($relay_npub, 7, 7) . ' ' . substr($relay_npub, 14, 7);
|
||||
$line2 = substr($relay_npub, 21, 7) . ' ' . substr($relay_npub, 28, 7) . ' ' . substr($relay_npub, 35, 7);
|
||||
$line3 = substr($relay_npub, 42, 7) . ' ' . substr($relay_npub, 49, 7) . ' ' . substr($relay_npub, 56, 7);
|
||||
$formatted_npub = $line1 . "\n" . $line2 . "\n" . $line3;
|
||||
}
|
||||
$display_name = $relay_version ? ($relay_name . ' ' . $relay_version) : $relay_name;
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>C-Relay-PG Admin</title>
|
||||
<link rel="stylesheet" href="assets/index.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Side Navigation Menu -->
|
||||
<nav class="side-nav" id="side-nav">
|
||||
<ul class="nav-menu">
|
||||
<li><button class="nav-item" data-page="statistics">Statistics</button></li>
|
||||
<li><button class="nav-item" data-page="subscriptions">Subscriptions</button></li>
|
||||
<li><button class="nav-item" data-page="configuration">Configuration</button></li>
|
||||
<li><button class="nav-item" data-page="authorization">Authorization</button></li>
|
||||
<li><button class="nav-item" data-page="ip-bans">IP BAN</button></li>
|
||||
<li><button class="nav-item" data-page="relay-events">Relay Events</button></li>
|
||||
<li><button class="nav-item" data-page="caching">Caching</button></li>
|
||||
<li><button class="nav-item" data-page="dm">DM</button></li>
|
||||
<li><button class="nav-item" data-page="cleanup">Cleanup</button></li>
|
||||
<li><button class="nav-item" data-page="database">Database Query</button></li>
|
||||
</ul>
|
||||
<div class="nav-footer">
|
||||
<button class="nav-footer-btn" id="nav-dark-mode-btn">DARK MODE</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Side Navigation Overlay -->
|
||||
<div class="side-nav-overlay" id="side-nav-overlay"></div>
|
||||
|
||||
<!-- Header with title and profile display -->
|
||||
<div class="section">
|
||||
<div class="header-content">
|
||||
<div class="header-title clickable" id="header-title" onclick="toggleNav()">
|
||||
<span class="relay-letter" data-letter="R">R</span>
|
||||
<span class="relay-letter" data-letter="E">E</span>
|
||||
<span class="relay-letter" data-letter="L">L</span>
|
||||
<span class="relay-letter" data-letter="A">A</span>
|
||||
<span class="relay-letter" data-letter="Y">Y</span>
|
||||
</div>
|
||||
<div class="relay-info">
|
||||
<div id="relay-name" class="relay-name"><?= e($display_name) ?></div>
|
||||
<div id="relay-description" class="relay-description"><?= e($relay_desc) ?></div>
|
||||
<div id="relay-pubkey-container" class="relay-pubkey-container" title="Click to copy npub">
|
||||
<div id="relay-pubkey" class="relay-pubkey"><?= e($formatted_npub) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="profile-area" id="profile-area" style="display: none;">
|
||||
<div class="admin-label">admin</div>
|
||||
<div class="profile-container">
|
||||
<img id="header-user-image" class="header-user-image" alt="Profile" style="display: none;">
|
||||
<span id="header-user-name" class="header-user-name">Loading...</span>
|
||||
</div>
|
||||
<!-- Logout dropdown (under admin picture) -->
|
||||
<div class="logout-dropdown" id="logout-dropdown" style="display: none;">
|
||||
<button type="button" class="logout-btn" onclick="logout()">LOGOUT</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Login Modal Overlay (nostr_login_lite) -->
|
||||
<div id="login-modal" class="login-modal-overlay" style="display: none;">
|
||||
<div class="login-modal-content">
|
||||
<div id="login-modal-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Access Denied Overlay (shown when non-admin user logs in) -->
|
||||
<div id="access-denied-overlay" class="access-denied-overlay" style="display: none;">
|
||||
<div class="access-denied-content">
|
||||
<div class="access-denied-icon">⛔</div>
|
||||
<h2>ACCESS DENIED</h2>
|
||||
<p class="access-denied-message">This interface is restricted to the relay administrator.</p>
|
||||
<p class="access-denied-submessage">The logged-in account does not have admin privileges.</p>
|
||||
<button type="button" class="access-denied-logout-btn" onclick="logout()">LOGOUT</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DATABASE STATISTICS Section -->
|
||||
<div class="section flex-section" id="databaseStatisticsSection">
|
||||
<div class="section-header">DATABASE STATISTICS</div>
|
||||
|
||||
<!-- Event Rate Graph — range selector tabs + ASCII chart (server-rendered) -->
|
||||
<div class="chart-range-tabs">
|
||||
<button class="chart-tab active" data-range="hour">1H</button>
|
||||
<button class="chart-tab" data-range="day">1D</button>
|
||||
<button class="chart-tab" data-range="month">1M</button>
|
||||
<button class="chart-tab" data-range="year">1Y</button>
|
||||
</div>
|
||||
<div id="event-rate-chart" class="event-rate-chart-container">Loading chart...</div>
|
||||
|
||||
<!-- Database Overview Table -->
|
||||
<div class="input-group">
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="stats-overview-table">
|
||||
<thead><tr><th>Metric</th><th>Value</th></tr></thead>
|
||||
<tbody id="stats-overview-table-body">
|
||||
<tr><td>Database Size</td><td id="db-size">-</td></tr>
|
||||
<tr><td>Total Events</td><td id="total-events">-</td></tr>
|
||||
<tr><td>Process ID</td><td id="process-id">-</td></tr>
|
||||
<tr><td>WebSocket Connections</td><td id="websocket-connections">-</td></tr>
|
||||
<tr><td>Active Subscriptions</td><td id="active-subscriptions">-</td></tr>
|
||||
<tr><td>Memory Usage</td><td id="memory-usage">-</td></tr>
|
||||
<tr><td>CPU Usage</td><td id="cpu-usage">-</td></tr>
|
||||
<tr><td>CPU Core</td><td id="cpu-core">-</td></tr>
|
||||
<tr><td>Oldest Event</td><td id="oldest-event">-</td></tr>
|
||||
<tr><td>Newest Event</td><td id="newest-event">-</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Event Kind Distribution Table -->
|
||||
<div class="input-group">
|
||||
<label>Event Kind Distribution:</label>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="stats-kinds-table">
|
||||
<thead><tr><th>Event Kind</th><th>Count</th><th>Percentage</th></tr></thead>
|
||||
<tbody id="stats-kinds-table-body">
|
||||
<tr><td colspan="3" style="text-align: center; font-style: italic;">Loading...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Time-based Statistics Table -->
|
||||
<div class="input-group">
|
||||
<label>Time-based Statistics:</label>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="stats-time-table">
|
||||
<thead><tr><th>Period</th><th>Events</th></tr></thead>
|
||||
<tbody id="stats-time-table-body">
|
||||
<tr><td>Last 24 Hours</td><td id="events-24h">-</td></tr>
|
||||
<tr><td>Last 7 Days</td><td id="events-7d">-</td></tr>
|
||||
<tr><td>Last 30 Days</td><td id="events-30d">-</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top Pubkeys Table -->
|
||||
<div class="input-group">
|
||||
<label>Top Pubkeys by Event Count:</label>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="stats-pubkeys-table">
|
||||
<thead><tr><th>Rank</th><th>Name</th><th>Pubkey</th><th>Event Count</th><th>Percentage</th></tr></thead>
|
||||
<tbody id="stats-pubkeys-table-body">
|
||||
<tr><td colspan="5" style="text-align: center; font-style: italic;">Loading...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Name-field usage stats (from profiles cache) -->
|
||||
<div class="input-group" id="name-field-usage" style="display:none;"></div>
|
||||
</div>
|
||||
|
||||
<!-- SUBSCRIPTION DETAILS Section -->
|
||||
<div class="section flex-section" id="subscriptionDetailsSection" style="display: none;">
|
||||
<div class="section-header">ACTIVE SUBSCRIPTION DETAILS</div>
|
||||
<div class="input-group">
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="subscription-details-table">
|
||||
<thead><tr><th>Sub ID</th><th>Pubkey</th><th>Filters</th><th>Created</th><th>Events Sent</th></tr></thead>
|
||||
<tbody id="subscription-details-table-body">
|
||||
<tr><td colspan="5" style="text-align: center; font-style: italic;">Loading...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CONFIGURATION Section -->
|
||||
<div id="div_config" class="section flex-section" style="display: none;">
|
||||
<div class="section-header">RELAY CONFIGURATION</div>
|
||||
<div id="config-display">
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="config-table">
|
||||
<thead><tr><th>Parameter</th><th>Value</th><th>Actions</th></tr></thead>
|
||||
<tbody id="config-table-body">
|
||||
<tr><td colspan="3" style="text-align: center; font-style: italic;">Loading...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="fetch-config-btn" onclick="loadConfig()">REFRESH</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AUTH RULES Section -->
|
||||
<div class="section flex-section" id="authRulesSection" style="display: none;">
|
||||
<div class="section-header">AUTH RULES MANAGEMENT</div>
|
||||
<div id="authRulesTableContainer">
|
||||
<table class="config-table" id="authRulesTable">
|
||||
<thead><tr><th>Rule Type</th><th>Pattern Type</th><th>Pattern Value</th><th>Status</th><th>Actions</th></tr></thead>
|
||||
<tbody id="authRulesTableBody">
|
||||
<tr><td colspan="5" style="text-align: center; font-style: italic;">Loading...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="authRuleInputSections" style="display: block;">
|
||||
<div class="input-group">
|
||||
<label for="authRulePubkey">Public Key (npub or hex):</label>
|
||||
<input type="text" id="authRulePubkey" placeholder="npub1... or 64-character hex pubkey">
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" onclick="addAuthRule('whitelist')">ADD TO WHITELIST</button>
|
||||
<button type="button" onclick="addAuthRule('blacklist')">ADD TO BLACKLIST</button>
|
||||
<button type="button" onclick="loadAuthRules()">REFRESH</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- WEB OF TRUST Section -->
|
||||
<div class="section flex-section" id="wotSection" style="display: none;">
|
||||
<div class="section-header">WEB OF TRUST</div>
|
||||
<div id="wotKind3Status" class="wot-status-row">
|
||||
<span>Admin Contact List (kind 3):</span>
|
||||
<span id="wotKind3Indicator" class="wot-indicator wot-unknown">Loading...</span>
|
||||
</div>
|
||||
<div class="wot-level-selector">
|
||||
<label>WoT Level:</label>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" class="wot-level-btn" onclick="setWotLevel(0)">OFF</button>
|
||||
<button type="button" class="wot-level-btn" onclick="setWotLevel(1)">WRITE ONLY</button>
|
||||
<button type="button" class="wot-level-btn" onclick="setWotLevel(2)">FULL</button>
|
||||
</div>
|
||||
<div class="wot-level-description" id="wotLevelDescription">Loading...</div>
|
||||
</div>
|
||||
<div class="wot-stats-row">
|
||||
<span>Whitelisted Pubkeys:</span>
|
||||
<span id="wotWhitelistCount">—</span>
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" onclick="syncWot()">SYNC FROM KIND 3</button>
|
||||
<button type="button" onclick="loadWotStatus()">REFRESH STATUS</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- NIP-17 DIRECT MESSAGES Section -->
|
||||
<div class="section" id="nip17DMSection" style="display: none;">
|
||||
<div class="section-header"><h2>NIP-17 DIRECT MESSAGES</h2></div>
|
||||
<div class="input-group">
|
||||
<label>Received Messages (kind 4/14/15):</label>
|
||||
<div id="dm-inbox" class="log-panel" style="height: 300px; overflow-y: auto;">
|
||||
<div class="log-entry">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- IP BANS Section -->
|
||||
<div class="section" id="ipBansSection" style="display: none;">
|
||||
<div class="section-header">IP BAN MANAGEMENT</div>
|
||||
<div class="input-group">
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="ip-bans-stats-table">
|
||||
<thead><tr><th>Total IPs Tracked</th><th>Currently Banned</th><th>Total Bans Issued</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td id="ip-bans-total">-</td><td id="ip-bans-active">-</td><td id="ip-bans-issued">-</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<h3>Manually Ban IP Address</h3>
|
||||
<div class="form-group">
|
||||
<label for="ban-ip-input">IP Address:</label>
|
||||
<input type="text" id="ban-ip-input" placeholder="192.168.1.100">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="ban-duration-select">Ban Duration:</label>
|
||||
<select id="ban-duration-select">
|
||||
<option value="3600">1 Hour</option>
|
||||
<option value="86400" selected>24 Hours</option>
|
||||
<option value="604800">7 Days</option>
|
||||
<option value="2592000">30 Days</option>
|
||||
<option value="31536000">1 Year</option>
|
||||
<option value="999999999">Permanent</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" onclick="addBan()">BAN IP</button>
|
||||
<button type="button" onclick="loadIpBans()">REFRESH</button>
|
||||
</div>
|
||||
<div id="add-ban-status" class="status-message"></div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label>Banned IP Addresses:</label>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="ip-bans-table">
|
||||
<thead><tr><th>IP Address</th><th>Status</th><th>Banned Until</th><th>Failures</th><th>Actions</th></tr></thead>
|
||||
<tbody id="ip-bans-tbody">
|
||||
<tr><td colspan="5" style="text-align: center;">Loading...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RELAY EVENTS Section -->
|
||||
<div class="section" id="relayEventsSection" style="display: none;">
|
||||
<div class="section-header">RELAY EVENTS MANAGEMENT</div>
|
||||
<div class="input-group">
|
||||
<h3>Recent Events</h3>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" onclick="loadEvents()">REFRESH</button>
|
||||
</div>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="live-relay-events-table">
|
||||
<thead><tr><th>Time</th><th>Kind</th><th>Name</th><th>ID</th><th>Content Preview</th></tr></thead>
|
||||
<tbody id="live-relay-events-table-body">
|
||||
<tr><td colspan="5" style="text-align: center;">Loading...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CACHING Section -->
|
||||
<div class="section" id="cachingSection" style="display: none;">
|
||||
<div class="section-header">CACHING</div>
|
||||
<div class="input-group">
|
||||
<h3>Caching Controls</h3>
|
||||
<div id="caching-controls" class="inline-buttons">
|
||||
<span id="caching-enabled-label">Caching: ?</span>
|
||||
<button type="button" id="caching-toggle-btn" onclick="toggleCachingEnabled()">Toggle Caching</button>
|
||||
<span id="caching-inbox-enabled-label">Inbox: ?</span>
|
||||
<button type="button" id="caching-inbox-toggle-btn" onclick="toggleCachingInboxEnabled()">Toggle Inbox</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<h3>Caching Service Status</h3>
|
||||
<div id="caching-service-status" class="status-display">
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
<div class="inline-buttons" style="margin-top:8px">
|
||||
<button type="button" id="caching-rerun-all-btn" onclick="rerunAllCaching()">Re-run All Caching</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<h3>Relay Inbox Status</h3>
|
||||
<div id="caching-inbox-status" class="status-display">
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<h3>Upstream Relay Status <span style="font-size:11px;font-weight:normal;color:var(--text-muted,#888)">(live connection state, updated every 15s)</span></h3>
|
||||
<div id="caching-relay-status" class="status-display">
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<h3>Followed Pubkeys <span style="font-size:11px;font-weight:normal;color:var(--text-muted,#888)">(click a row for per-relay details)</span></h3>
|
||||
<div id="caching-follows-status" class="status-message"></div>
|
||||
<div id="caching-follows-pagination" class="pagination-bar"></div>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="caching-follows-table">
|
||||
<thead><tr><th>Name</th><th>npub</th><th>Root?</th><th>Events in DB</th><th>Backfill</th><th>Relays</th></tr></thead>
|
||||
<tbody id="caching-follows-table-body">
|
||||
<tr><td colspan="6" style="text-align: center; font-style: italic;">Loading...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" onclick="loadCaching()">REFRESH</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- EVENT CLEANUP Section -->
|
||||
<div class="section" id="cleanupSection" style="display: none;">
|
||||
<div class="section-header"><h2>EVENT CLEANUP</h2></div>
|
||||
|
||||
<!-- Saved Queries Table -->
|
||||
<div class="input-group" id="saved-queries-group">
|
||||
<label>Saved Queries</label>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="cleanup-saved-queries-table">
|
||||
<thead><tr><th>Name</th><th>Filters</th><th>Last Preview</th><th>Last Executed</th><th>Actions</th></tr></thead>
|
||||
<tbody id="cleanup-saved-queries-body">
|
||||
<tr><td colspan="5" style="text-align: center; font-style: italic;">Loading...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="inline-buttons" style="margin-top:8px">
|
||||
<button type="button" onclick="newCleanupQuery()">New Query</button>
|
||||
<button type="button" onclick="loadCleanupQueries()">Refresh</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Query Builder -->
|
||||
<div class="input-group" id="cleanup-builder-group">
|
||||
<label>Query Builder</label>
|
||||
<div class="form-group">
|
||||
<label for="cleanup-name">Query Name:</label>
|
||||
<input type="text" id="cleanup-name" placeholder="My Cleanup Query" style="width:100%;max-width:400px">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Follows Filter:</label>
|
||||
<div class="radio-group">
|
||||
<label><input type="radio" name="cleanup-follows" value="all" checked> All</label>
|
||||
<label><input type="radio" name="cleanup-follows" value="follows"> Follows only</label>
|
||||
<label><input type="radio" name="cleanup-follows" value="non_follows"> Non-follows only</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cleanup-kinds">Event Kinds (comma-separated, empty = all):</label>
|
||||
<input type="text" id="cleanup-kinds" placeholder="e.g. 1, 7, 9734" style="width:100%;max-width:400px">
|
||||
<div style="font-size:11px;color:var(--text-muted,#888);margin-top:2px">
|
||||
Common kinds: 0 (profiles), 1 (text), 3 (contacts), 4 (DM), 5 (delete),
|
||||
6 (repost), 7 (reaction), 9734 (zap request), 9735 (zap receipt), 10002 (relay list)
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cleanup-max-age">Max Age (days, 0 = no limit):</label>
|
||||
<input type="number" id="cleanup-max-age" value="0" min="0" style="width:120px">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cleanup-max-events">Max Events (0 = no limit):</label>
|
||||
<input type="number" id="cleanup-max-events" value="0" min="0" style="width:120px">
|
||||
</div>
|
||||
<div class="inline-buttons" style="margin-top:8px">
|
||||
<button type="button" onclick="previewCleanup()">Preview</button>
|
||||
<button type="button" onclick="saveCleanupQuery()">Save Query</button>
|
||||
<button type="button" onclick="executeCleanup()" style="background:#c0392b;color:#fff">Execute Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Results Area -->
|
||||
<div class="input-group" id="cleanup-results-group" style="display:none;">
|
||||
<label>Results</label>
|
||||
<div id="cleanup-results-summary" class="info-box"></div>
|
||||
<div id="cleanup-results-breakdown" class="config-table-container" style="margin-top:8px"></div>
|
||||
<div id="cleanup-results-sql" style="margin-top:8px">
|
||||
<details>
|
||||
<summary style="cursor:pointer;font-size:12px;color:var(--text-muted,#888)">SQL Preview</summary>
|
||||
<pre id="cleanup-sql-preview" style="background:var(--bg-code,#f5f5f5);padding:8px;border-radius:4px;overflow-x:auto;font-size:11px;margin-top:4px;white-space:pre-wrap"></pre>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Confirmation Dialog -->
|
||||
<div id="cleanup-confirm-dialog" class="modal-overlay" style="display:none;">
|
||||
<div class="modal-content" style="background:var(--bg-card,#fff);border:1px solid var(--border,#ccc);border-radius:8px;padding:20px;max-width:480px;margin:10% auto;box-shadow:0 4px 20px rgba(0,0,0,0.3)">
|
||||
<h3 style="margin-top:0">Confirm Delete</h3>
|
||||
<p id="cleanup-confirm-msg">Are you sure you want to delete these events?</p>
|
||||
<p style="color:#c0392b;font-weight:bold">This action cannot be undone.</p>
|
||||
<div class="inline-buttons" style="margin-top:12px">
|
||||
<button type="button" id="cleanup-confirm-btn" onclick="executeCleanupConfirmed()" style="background:#c0392b;color:#fff">Delete</button>
|
||||
<button type="button" onclick="document.getElementById('cleanup-confirm-dialog').style.display='none'">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SQL QUERY Section -->
|
||||
<div class="section" id="sqlQuerySection" style="display: none;">
|
||||
<div class="section-header"><h2>SQL QUERY CONSOLE</h2></div>
|
||||
<div class="input-group">
|
||||
<label for="sql-input">SQL Query (SELECT only):</label>
|
||||
<textarea id="sql-input" rows="5" placeholder="SELECT * FROM events LIMIT 10"></textarea>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="inline-buttons">
|
||||
<button type="button" onclick="executeQuery()">EXECUTE QUERY</button>
|
||||
<button type="button" onclick="document.getElementById('sql-input').value=''">CLEAR</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label>Query Results:</label>
|
||||
<div id="query-info" class="info-box"></div>
|
||||
<div id="query-table" class="config-table-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nostr libraries for nostr_login_lite auth modal -->
|
||||
<script src="assets/nostr.bundle.js"></script>
|
||||
<script src="assets/nostr-lite.js"></script>
|
||||
<script src="assets/app.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
/**
|
||||
* admin2/lib/ascii_chart.php — Server-side ASCII X-bar chart renderer.
|
||||
*
|
||||
* Produces a monospaced ASCII bar chart (using 'X' characters) from an
|
||||
* array of bin counts. Mirrors the layout of the original text_graph.js
|
||||
* ASCIIBarChart: Y-axis count labels, X-bar columns, X-axis with
|
||||
* elapsed-time labels.
|
||||
*
|
||||
* The output is a plain text string suitable for both browser <div>
|
||||
* injection (white-space: pre) and terminal display via curl.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Render an ASCII bar chart from an array of bin counts.
|
||||
*
|
||||
* @param array $bins Array of integer counts (one per time bin, left=oldest)
|
||||
* @param array $options {
|
||||
* @var string $title Chart title (centered at top)
|
||||
* @var int $max_height Chart height in rows (default 11)
|
||||
* @var string $x_axis_label Label below the X-axis (default '')
|
||||
* @var int $bin_duration Seconds per bin — for X-axis elapsed labels
|
||||
* @var int $label_interval Label every N bins (default 5)
|
||||
* }
|
||||
* @return string The ASCII chart as a multi-line string.
|
||||
*/
|
||||
function render_ascii_chart(array $bins, array $options = []): string {
|
||||
$title = $options['title'] ?? 'New Events';
|
||||
$max_height = $options['max_height'] ?? 11;
|
||||
$x_axis_label = $options['x_axis_label'] ?? '';
|
||||
$bin_duration = $options['bin_duration'] ?? 10;
|
||||
$label_interval = $options['label_interval'] ?? 5;
|
||||
|
||||
$num_bins = count($bins);
|
||||
if ($num_bins === 0) {
|
||||
return "No data available.\n";
|
||||
}
|
||||
|
||||
$max_count = max($bins);
|
||||
if ($max_count < 1) $max_count = 1; // Avoid division by zero for all-empty bins
|
||||
|
||||
// Scaling: each X represents scale_factor counts
|
||||
$scale_factor = max(1, (int)ceil($max_count / $max_height));
|
||||
$scaled_max = (int)ceil($max_count / $scale_factor) * $scale_factor;
|
||||
|
||||
$output = '';
|
||||
|
||||
// --- Title (centered) ---
|
||||
$chart_width = 4 + $num_bins; // 4 = Y-axis number width (3) + separator (1)
|
||||
if ($title !== '') {
|
||||
$title_padding = (int)floor(($chart_width - strlen($title)) / 2);
|
||||
if ($title_padding < 0) $title_padding = 0;
|
||||
$output .= str_repeat(' ', $title_padding) . $title . "\n\n";
|
||||
}
|
||||
|
||||
// --- Bar rows (top to bottom) ---
|
||||
for ($row = $max_height; $row > 0; $row--) {
|
||||
$row_count = ($row - 1) * $scale_factor + 1;
|
||||
$line = str_pad((string)$row_count, 3, ' ', STR_PAD_LEFT) . ' |';
|
||||
|
||||
for ($i = 0; $i < $num_bins; $i++) {
|
||||
$count = $bins[$i];
|
||||
$scaled_height = ($count > 0) ? (int)ceil($count / $scale_factor) : 0;
|
||||
$line .= ($scaled_height >= $row) ? 'X' : ' ';
|
||||
}
|
||||
$output .= $line . "\n";
|
||||
}
|
||||
|
||||
// --- X-axis line ---
|
||||
$output .= ' +' . str_repeat('-', $num_bins) . "\n";
|
||||
|
||||
// --- X-axis labels (elapsed time every label_interval bins) ---
|
||||
$label_line = ' ';
|
||||
$labels = [];
|
||||
for ($i = 0; $i < $num_bins; $i++) {
|
||||
if ($i % $label_interval === 0) {
|
||||
$elapsed_sec = $i * $bin_duration;
|
||||
$labels[] = format_elapsed_time($elapsed_sec);
|
||||
}
|
||||
}
|
||||
// Build label line with spacing
|
||||
for ($i = 0; $i < count($labels); $i++) {
|
||||
$label_line .= $labels[$i];
|
||||
if ($i < count($labels) - 1) {
|
||||
$spacing = $label_interval - strlen($labels[$i]);
|
||||
if ($spacing < 1) $spacing = 1;
|
||||
$label_line .= str_repeat(' ', $spacing);
|
||||
}
|
||||
}
|
||||
// Pad to match X-axis dash line length
|
||||
$min_label_len = 4 + $num_bins;
|
||||
if (strlen($label_line) < $min_label_len) {
|
||||
$label_line .= str_repeat(' ', $min_label_len - strlen($label_line));
|
||||
}
|
||||
$output .= $label_line . "\n";
|
||||
|
||||
// --- X-axis label (if provided) ---
|
||||
if ($x_axis_label !== '') {
|
||||
$label_pad = (int)floor(($num_bins - strlen($x_axis_label)) / 2);
|
||||
if ($label_pad < 0) $label_pad = 0;
|
||||
$output .= "\n" . ' ' . str_repeat(' ', $label_pad) . $x_axis_label . "\n";
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an elapsed time in seconds as a compact label.
|
||||
* < 60s → "Ns"
|
||||
* < 1h → "Nm"
|
||||
* < 1d → "Nh"
|
||||
* else → "Nd"
|
||||
*/
|
||||
function format_elapsed_time(int $seconds): string {
|
||||
if ($seconds < 60) {
|
||||
return $seconds . 's';
|
||||
} elseif ($seconds < 3600) {
|
||||
return (int)floor($seconds / 60) . 'm';
|
||||
} elseif ($seconds < 86400) {
|
||||
return (int)floor($seconds / 3600) . 'h';
|
||||
} else {
|
||||
return (int)floor($seconds / 86400) . 'd';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a fixed-length bin array from SQL query rows.
|
||||
*
|
||||
* The query returns only non-empty bins. This function creates a
|
||||
* zero-filled array of $num_bins length and overlays the counts
|
||||
* at the correct positions, so empty time slots show as blank
|
||||
* columns — the chart always advances in time.
|
||||
*
|
||||
* @param array $rows Query rows with 'bin' (int) and 'cnt' (int)
|
||||
* @param int $num_bins Total number of bins (fixed length)
|
||||
* @return array Zero-filled array of counts
|
||||
*/
|
||||
function build_bin_array(array $rows, int $num_bins): array {
|
||||
$bins = array_fill(0, $num_bins, 0);
|
||||
foreach ($rows as $r) {
|
||||
$idx = (int)$r['bin'];
|
||||
if ($idx >= 0 && $idx < $num_bins) {
|
||||
$bins[$idx] = (int)$r['cnt'];
|
||||
}
|
||||
}
|
||||
return $bins;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* C-Relay-PG Admin — Database connection configuration.
|
||||
*
|
||||
* This file is NOT web-accessible (denied by nginx location block).
|
||||
* It contains the PostgreSQL connection string used by all admin pages.
|
||||
*
|
||||
* Edit these values to match your relay's PostgreSQL credentials.
|
||||
*/
|
||||
|
||||
// PostgreSQL connection parameters.
|
||||
// These should match the --db-* flags passed to the c-relay-pg binary
|
||||
// or the connection string passed to caching_relay -p "...".
|
||||
return [
|
||||
'db_host' => 'localhost',
|
||||
'db_port' => '5432',
|
||||
'db_name' => 'crelay',
|
||||
'db_user' => 'crelay',
|
||||
'db_password' => 'crelay',
|
||||
|
||||
// Page sizes for paginated tables.
|
||||
'follows_per_page' => 50,
|
||||
'relays_per_page' => 50,
|
||||
|
||||
// Auto-refresh interval for dashboard polling (milliseconds).
|
||||
'refresh_ms' => 10000,
|
||||
];
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* C-Relay-PG Admin — PDO database connection helper.
|
||||
*
|
||||
* Provides a singleton PDO connection to the relay's PostgreSQL database.
|
||||
* All admin pages use db() to get the connection.
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
function db(): PDO {
|
||||
static $pdo = null;
|
||||
if ($pdo === null) {
|
||||
$cfg = require __DIR__ . '/config.php';
|
||||
// Build DSN — supports both TCP (host=localhost) and Unix socket
|
||||
// (host=/var/run/postgresql). Omit password if empty (peer auth).
|
||||
$dsn = sprintf(
|
||||
'pgsql:host=%s;port=%d;dbname=%s;user=%s',
|
||||
$cfg['db_host'],
|
||||
$cfg['db_port'],
|
||||
$cfg['db_name'],
|
||||
$cfg['db_user']
|
||||
);
|
||||
if (!empty($cfg['db_password'])) {
|
||||
$dsn .= ';password=' . $cfg['db_password'];
|
||||
}
|
||||
try {
|
||||
$pdo = new PDO($dsn, null, null, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
]);
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
die('Database connection failed: ' . htmlspecialchars($e->getMessage()));
|
||||
}
|
||||
}
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
/** Get a config value from the admin config file. */
|
||||
function cfg(string $key, $default = null) {
|
||||
static $cfg = null;
|
||||
if ($cfg === null) {
|
||||
$cfg = require __DIR__ . '/config.php';
|
||||
}
|
||||
return $cfg[$key] ?? $default;
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
/**
|
||||
* C-Relay-PG Admin — Shared helper functions.
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/db.php';
|
||||
|
||||
/** HTML-escape a string. */
|
||||
function e(?string $s): string {
|
||||
return htmlspecialchars($s ?? '', ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
/** Format a Unix timestamp as a human-readable relative time. */
|
||||
function time_ago(int $ts): string {
|
||||
if ($ts <= 0) return 'never';
|
||||
$diff = time() - $ts;
|
||||
if ($diff < 60) return $diff . 's ago';
|
||||
if ($diff < 3600) return floor($diff / 60) . 'm ago';
|
||||
if ($diff < 86400) return floor($diff / 3600) . 'h ago';
|
||||
return floor($diff / 86400) . 'd ago';
|
||||
}
|
||||
|
||||
/** Format a Unix timestamp as a date/time string. */
|
||||
function fmt_date(int $ts): string {
|
||||
if ($ts <= 0) return '-';
|
||||
return date('Y-m-d H:i:s', $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a 64-char hex pubkey to npub (bech32).
|
||||
* Uses the standard bech32 encoding (NIP-19).
|
||||
*/
|
||||
function hex_to_npub(string $hex): string {
|
||||
if (!preg_match('/^[0-9a-fA-F]{64}$/', $hex)) return $hex;
|
||||
$hex = strtolower($hex);
|
||||
|
||||
// Bech32 constants
|
||||
$charset = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
|
||||
$data = [];
|
||||
for ($i = 0; $i < strlen($hex); $i += 2) {
|
||||
$data[] = intval(substr($hex, $i, 2), 16);
|
||||
}
|
||||
// Convert 8-bit groups to 5-bit groups
|
||||
$conv = [];
|
||||
$buffer = 0;
|
||||
$bits = 0;
|
||||
foreach ($data as $byte) {
|
||||
$buffer = ($buffer << 8) | $byte;
|
||||
$bits += 8;
|
||||
while ($bits >= 5) {
|
||||
$conv[] = ($buffer >> ($bits - 5)) & 31;
|
||||
$bits -= 5;
|
||||
}
|
||||
}
|
||||
if ($bits > 0) {
|
||||
$conv[] = ($buffer << (5 - $bits)) & 31;
|
||||
}
|
||||
|
||||
// Compute checksum — HRP values are positions of each char in the charset.
|
||||
$values = array_merge(
|
||||
array_map(function($c) {
|
||||
return strpos('qpzry9x8gf2tvdw0s3jn54khce6mua7l', $c);
|
||||
}, str_split('npub')),
|
||||
$conv
|
||||
);
|
||||
$gen = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
|
||||
$chk = 1;
|
||||
foreach ($values as $v) {
|
||||
$top = $chk >> 25;
|
||||
$chk = (($chk & 0x1ffffff) << 5) ^ $v;
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
if (($top >> $i) & 1) $chk ^= $gen[$i];
|
||||
}
|
||||
}
|
||||
$chk ^= 1;
|
||||
$checksum = [];
|
||||
for ($i = 0; $i < 6; $i++) {
|
||||
$checksum[] = ($chk >> (5 * (5 - $i))) & 31;
|
||||
}
|
||||
|
||||
$result = 'npub1';
|
||||
foreach (array_merge($conv, $checksum) as $v) {
|
||||
$result .= $charset[$v];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/** Truncate a string to $len chars with ellipsis. */
|
||||
function trunc(string $s, int $len = 16): string {
|
||||
if (strlen($s) <= $len) return $s;
|
||||
return substr($s, 0, $len) . '…';
|
||||
}
|
||||
|
||||
/** Build pagination links HTML. */
|
||||
function pagination(int $page, int $per_page, int $total, string $base_url): string {
|
||||
$total_pages = max(1, ceil($total / $per_page));
|
||||
if ($total_pages <= 1) return '';
|
||||
|
||||
$html = '<div class="pagination">';
|
||||
if ($page > 1) {
|
||||
$html .= '<a href="' . e($base_url) . '?page=' . ($page - 1) . '">← Prev</a>';
|
||||
}
|
||||
$html .= '<span>Page ' . $page . ' of ' . $total_pages . ' (' . $total . ' total)</span>';
|
||||
if ($page < $total_pages) {
|
||||
$html .= '<a href="' . e($base_url) . '?page=' . ($page + 1) . '">Next →</a>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
/** Get the current page number from the query string. */
|
||||
function current_page(): int {
|
||||
$p = intval($_GET['page'] ?? 1);
|
||||
return max(1, $p);
|
||||
}
|
||||
|
||||
/** JSON response helper for AJAX endpoints. */
|
||||
function json_response($data): void {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
/** Get a query parameter with a default. */
|
||||
function query_param(string $key, $default = null) {
|
||||
return $_GET[$key] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch-resolve profiles from the profiles cache table.
|
||||
* Returns [pubkey_hex => ['name'=>..., 'display_name'=>...,
|
||||
* 'best_name'=>..., 'picture'=>..., 'nip05'=>...]].
|
||||
* Pubkeys with no cached profile are absent from the result.
|
||||
*/
|
||||
function profile_map(array $pubkeys): array {
|
||||
if (empty($pubkeys)) return [];
|
||||
$pdo = db();
|
||||
$map = [];
|
||||
try {
|
||||
// Build parameterized IN clause: WHERE pubkey = ANY(?)
|
||||
// PDO PostgreSQL supports passing an array as a string literal.
|
||||
$placeholders = implode(',', array_fill(0, count($pubkeys), '?'));
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT pubkey, name, display_name, picture, nip05 FROM profiles "
|
||||
. "WHERE pubkey IN ($placeholders)"
|
||||
);
|
||||
$stmt->execute(array_values($pubkeys));
|
||||
$rows = $stmt->fetchAll();
|
||||
foreach ($rows as $r) {
|
||||
$map[$r['pubkey']] = [
|
||||
'name' => $r['name'] ?? '',
|
||||
'display_name' => $r['display_name'] ?? '',
|
||||
'best_name' => profile_display_name($r),
|
||||
'picture' => $r['picture'] ?? '',
|
||||
'nip05' => $r['nip05'] ?? '',
|
||||
];
|
||||
}
|
||||
} catch (PDOException $e) {}
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the profile_name_preference config key to resolve the display name.
|
||||
* Never returns null. Returns '' if neither field is set.
|
||||
*/
|
||||
function profile_display_name(array $profile): string {
|
||||
$name = $profile['name'] ?? '';
|
||||
$display_name = $profile['display_name'] ?? '';
|
||||
static $pref = null;
|
||||
if ($pref === null) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$pref = $pdo->query("SELECT value FROM config WHERE key = 'profile_name_preference'")->fetchColumn() ?: 'display_name';
|
||||
} catch (PDOException $e) {
|
||||
$pref = 'display_name';
|
||||
}
|
||||
}
|
||||
if ($pref === 'name') {
|
||||
return $name !== '' ? $name : $display_name;
|
||||
}
|
||||
// Default: prefer display_name, fall back to name.
|
||||
return $display_name !== '' ? $display_name : $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the shared HTML header with side navigation.
|
||||
* Pass the active page name to highlight the current nav item.
|
||||
*/
|
||||
function admin_header(string $active = '', string $title = 'C-Relay-PG Admin'): void {
|
||||
$pages = [
|
||||
'dashboard' => ['index.php', 'Dashboard'],
|
||||
'follows' => ['follows.php', 'Follows'],
|
||||
'relays' => ['relays.php', 'Relays'],
|
||||
'config' => ['config-edit.php', 'Config'],
|
||||
'inbox' => ['inbox.php', 'Inbox'],
|
||||
];
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= e($title) ?></title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Side Navigation -->
|
||||
<nav class="side-nav" id="side-nav">
|
||||
<ul class="nav-menu">
|
||||
<?php foreach ($pages as $key => [$url, $label]): ?>
|
||||
<li><a class="nav-item<?= $active === $key ? ' active' : '' ?>" href="<?= e($url) ?>"><?= e($label) ?></a></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="side-nav-overlay" id="side-nav-overlay" onclick="closeNav()"></div>
|
||||
|
||||
<!-- Header -->
|
||||
<div class="main-header">
|
||||
<div class="header-content">
|
||||
<button class="menu-btn" onclick="openNav()">☰</button>
|
||||
<div class="header-title" onclick="location.href='index.php'">
|
||||
<span class="relay-letter">R</span><span class="relay-letter">E</span><span class="relay-letter">L</span><span class="relay-letter">A</span><span class="relay-letter">Y</span>
|
||||
</div>
|
||||
<div style="width:40px"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function openNav() {
|
||||
document.getElementById('side-nav').classList.add('open');
|
||||
document.getElementById('side-nav-overlay').classList.add('show');
|
||||
}
|
||||
function closeNav() {
|
||||
document.getElementById('side-nav').classList.remove('open');
|
||||
document.getElementById('side-nav-overlay').classList.remove('show');
|
||||
}
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/** Render the shared HTML footer. */
|
||||
function admin_footer(): void {
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
/**
|
||||
* admin/public/index.php — Public relay stats page.
|
||||
*
|
||||
* Served at https://<domain>/relay/stats/ (no authentication required).
|
||||
*
|
||||
* Shows the relay name/description/pubkey (read-only, from the config table)
|
||||
* and the server-rendered ASCII event-rate chart. The chart is fetched from
|
||||
* the public endpoint at /relay/api/chart.php?range=...
|
||||
*
|
||||
* This page exposes ONLY read-only, non-sensitive information:
|
||||
* - relay_name, relay_description, relay_pubkey, relay_version (from config)
|
||||
* - the event-rate chart (aggregate COUNT query, no user data)
|
||||
*
|
||||
* All sensitive admin endpoints (config edits, auth rules, IP bans, DMs,
|
||||
* raw SQL queries) remain behind Basic Auth at /relay/admin/.
|
||||
*/
|
||||
require_once __DIR__ . '/../lib/helpers.php';
|
||||
$pdo = db();
|
||||
|
||||
// Fetch relay info for the header (from config table).
|
||||
$relay_name = '';
|
||||
$relay_desc = '';
|
||||
$relay_pubkey = '';
|
||||
$relay_version = '';
|
||||
try {
|
||||
$relay_name = $pdo->query("SELECT value FROM config WHERE key = 'relay_name'")->fetchColumn() ?: 'C-Relay-PG';
|
||||
$relay_desc = $pdo->query("SELECT value FROM config WHERE key = 'relay_description'")->fetchColumn() ?: '';
|
||||
$relay_pubkey = $pdo->query("SELECT value FROM config WHERE key = 'relay_pubkey'")->fetchColumn() ?: '';
|
||||
$relay_version = $pdo->query("SELECT value FROM config WHERE key = 'relay_version'")->fetchColumn() ?: '';
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// Convert relay pubkey (hex) to npub and format into 3 lines of 3 groups of 7 chars.
|
||||
$relay_npub = $relay_pubkey;
|
||||
if ($relay_pubkey && preg_match('/^[0-9a-fA-F]{64}$/', $relay_pubkey)) {
|
||||
$relay_npub = hex_to_npub($relay_pubkey);
|
||||
}
|
||||
$formatted_npub = $relay_npub;
|
||||
if (strlen($relay_npub) === 63) {
|
||||
$line1 = substr($relay_npub, 0, 7) . ' ' . substr($relay_npub, 7, 7) . ' ' . substr($relay_npub, 14, 7);
|
||||
$line2 = substr($relay_npub, 21, 7) . ' ' . substr($relay_npub, 28, 7) . ' ' . substr($relay_npub, 35, 7);
|
||||
$line3 = substr($relay_npub, 42, 7) . ' ' . substr($relay_npub, 49, 7) . ' ' . substr($relay_npub, 56, 7);
|
||||
$formatted_npub = $line1 . "\n" . $line2 . "\n" . $line3;
|
||||
}
|
||||
$display_name = $relay_version ? ($relay_name . ' ' . $relay_version) : $relay_name;
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= e($display_name) ?></title>
|
||||
<link rel="stylesheet" href="/relay/assets/index.css">
|
||||
<style>
|
||||
/* Public page uses the admin theme but hides the nav and centers content. */
|
||||
.side-nav, .side-nav-overlay { display: none !important; }
|
||||
.public-wrap { max-width: 1100px; margin: 0 auto; padding: 20px; }
|
||||
.public-chart-box {
|
||||
background: var(--secondary-color);
|
||||
border: var(--border-width) solid var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 12px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
.public-footer {
|
||||
margin-top: 24px;
|
||||
padding-top: 12px;
|
||||
border-top: var(--border-width) solid var(--border-color);
|
||||
font-size: 12px;
|
||||
color: var(--muted-color);
|
||||
text-align: center;
|
||||
}
|
||||
.public-footer a { color: var(--accent-color); text-decoration: none; }
|
||||
.event-rate-chart-container {
|
||||
white-space: pre;
|
||||
font-family: var(--font-family);
|
||||
font-size: 12px;
|
||||
line-height: 1.2;
|
||||
overflow-x: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Header with title and relay info (read-only) -->
|
||||
<div class="section">
|
||||
<div class="header-content">
|
||||
<div class="header-title">
|
||||
<span class="relay-letter" data-letter="R">R</span>
|
||||
<span class="relay-letter" data-letter="E">E</span>
|
||||
<span class="relay-letter" data-letter="L">L</span>
|
||||
<span class="relay-letter" data-letter="A">A</span>
|
||||
<span class="relay-letter" data-letter="Y">Y</span>
|
||||
</div>
|
||||
<div class="relay-info">
|
||||
<div id="relay-name" class="relay-name"><?= e($display_name) ?></div>
|
||||
<div id="relay-description" class="relay-description"><?= e($relay_desc) ?></div>
|
||||
<div id="relay-pubkey-container" class="relay-pubkey-container" title="Click to copy npub">
|
||||
<div id="relay-pubkey" class="relay-pubkey"><?= e($formatted_npub) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="public-wrap">
|
||||
<div class="section-header">EVENT RATE</div>
|
||||
|
||||
<!-- Range selector tabs -->
|
||||
<div class="chart-range-tabs">
|
||||
<button class="chart-tab active" data-range="hour">1H</button>
|
||||
<button class="chart-tab" data-range="day">1D</button>
|
||||
<button class="chart-tab" data-range="month">1M</button>
|
||||
<button class="chart-tab" data-range="year">1Y</button>
|
||||
</div>
|
||||
|
||||
<!-- Server-rendered ASCII chart (fetched from the public chart endpoint) -->
|
||||
<div class="public-chart-box">
|
||||
<div id="event-rate-chart" class="event-rate-chart-container">Loading chart...</div>
|
||||
</div>
|
||||
|
||||
<div class="public-footer">
|
||||
Public relay statistics ·
|
||||
<a href="wss://<?= e($_SERVER['HTTP_HOST'] ?? '') ?>">wss://<?= e($_SERVER['HTTP_HOST'] ?? '') ?></a>
|
||||
· Admin? visit <a href="/relay/admin/">/relay/admin/</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Minimal chart loader — fetches the public ASCII chart endpoint and
|
||||
// injects the plain-text response into the chart container. No auth.
|
||||
const chartEl = document.getElementById('event-rate-chart');
|
||||
let currentRange = 'hour';
|
||||
let chartTimer = null;
|
||||
|
||||
async function loadChart(range) {
|
||||
currentRange = range;
|
||||
if (!chartEl) return;
|
||||
chartEl.textContent = 'Loading chart...';
|
||||
try {
|
||||
const res = await fetch('/relay/api/chart.php?range=' + encodeURIComponent(range));
|
||||
if (!res.ok) { chartEl.textContent = 'Chart load failed (HTTP ' + res.status + ')'; return; }
|
||||
const text = await res.text();
|
||||
chartEl.textContent = text || '(no data)';
|
||||
} catch (e) {
|
||||
chartEl.textContent = 'Chart load failed: ' + e.message;
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll('.chart-tab').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
document.querySelectorAll('.chart-tab').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
const range = btn.getAttribute('data-range');
|
||||
loadChart(range);
|
||||
// Hour chart is live — auto-refresh every 30s. Others are cached server-side.
|
||||
if (chartTimer) { clearInterval(chartTimer); chartTimer = null; }
|
||||
if (range === 'hour') {
|
||||
chartTimer = setInterval(() => loadChart(currentRange), 30000);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Initial load + live refresh for the default (hour) range.
|
||||
loadChart('hour');
|
||||
chartTimer = setInterval(() => loadChart(currentRange), 30000);
|
||||
|
||||
// Click-to-copy the relay npub.
|
||||
const pkContainer = document.getElementById('relay-pubkey-container');
|
||||
if (pkContainer) {
|
||||
pkContainer.style.cursor = 'pointer';
|
||||
pkContainer.addEventListener('click', () => {
|
||||
const txt = (document.getElementById('relay-pubkey').textContent || '').replace(/\s+/g, '');
|
||||
if (txt && navigator.clipboard) navigator.clipboard.writeText(txt);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
# Launch the admin2 PHP built-in server, fully detached from the calling shell.
|
||||
# Usage: ./admin2/serve.sh [port] (default port 8088)
|
||||
PORT="${1:-8088}"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# Kill any existing instance on this port.
|
||||
pkill -f "php -S 127.0.0.1:$PORT" 2>/dev/null
|
||||
sleep 1
|
||||
|
||||
# Start fully detached in its own session so SIGTERM to the launcher
|
||||
# does not propagate to the PHP server.
|
||||
setsid php -S 127.0.0.1:$PORT -t "$SCRIPT_DIR" > "$SCRIPT_DIR/php_server.log" 2>&1 < /dev/null &
|
||||
PHP_PID=$!
|
||||
disown $PHP_PID 2>/dev/null
|
||||
|
||||
# Give it a moment to bind, then report.
|
||||
sleep 1
|
||||
if kill -0 "$PHP_PID" 2>/dev/null; then
|
||||
echo "admin PHP server started on http://127.0.0.1:$PORT (PID $PHP_PID)"
|
||||
echo "Serving from: $SCRIPT_DIR"
|
||||
echo "Log: $SCRIPT_DIR/php_server.log"
|
||||
else
|
||||
echo "ERROR: PHP server failed to start. Log:"
|
||||
cat "$SCRIPT_DIR/php_server.log" 2>/dev/null
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Embedded NOSTR_LOGIN_LITE</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
margin: 0;
|
||||
padding: 40px;
|
||||
background: white;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#login-container {
|
||||
/* No styling - let embedded modal blend seamlessly */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div id="login-container"></div>
|
||||
</div>
|
||||
|
||||
<script src="../lite/nostr.bundle.js"></script>
|
||||
<script src="../lite/nostr-lite.js"></script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
await window.NOSTR_LOGIN_LITE.init({
|
||||
theme:'default',
|
||||
methods: {
|
||||
extension: true,
|
||||
local: true,
|
||||
seedphrase: true,
|
||||
readonly: true,
|
||||
connect: true,
|
||||
remote: true,
|
||||
otp: true
|
||||
}
|
||||
});
|
||||
|
||||
window.NOSTR_LOGIN_LITE.embed('#login-container', {
|
||||
seamless: true
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+1062
-51
File diff suppressed because it is too large
Load Diff
+638
-171
@@ -4,214 +4,142 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>C-Relay Admin API</title>
|
||||
<title>C-Relay-PG Admin</title>
|
||||
<link rel="stylesheet" href="/api/index.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>C-RELAY ADMIN API</h1>
|
||||
<!-- Side Navigation Menu -->
|
||||
<nav class="side-nav" id="side-nav">
|
||||
<ul class="nav-menu">
|
||||
<li><button class="nav-item" data-page="statistics">Statistics</button></li>
|
||||
<li><button class="nav-item" data-page="subscriptions">Subscriptions</button></li>
|
||||
<li><button class="nav-item" data-page="configuration">Configuration</button></li>
|
||||
<li><button class="nav-item" data-page="authorization">Authorization</button></li>
|
||||
<li><button class="nav-item" data-page="ip-bans">IP BANS</button></li>
|
||||
<li><button class="nav-item" data-page="relay-events">Relay Events</button></li>
|
||||
<li><button class="nav-item" data-page="caching">Caching</button></li>
|
||||
<li><button class="nav-item" data-page="dm">DM</button></li>
|
||||
<li><button class="nav-item" data-page="database">Database Query</button></li>
|
||||
</ul>
|
||||
<div class="nav-footer">
|
||||
<button class="nav-footer-btn" id="nav-dark-mode-btn">DARK MODE</button>
|
||||
<button class="nav-footer-btn" id="nav-logout-btn">LOGOUT</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main Sections Wrapper -->
|
||||
<div class="main-sections-wrapper">
|
||||
<!-- Side Navigation Overlay -->
|
||||
<div class="side-nav-overlay" id="side-nav-overlay"></div>
|
||||
|
||||
<!-- Persistent Authentication Header - Always Visible -->
|
||||
<div id="persistent-auth-container" class="section flex-section">
|
||||
<div class="user-info-container">
|
||||
<button type="button" id="login-logout-btn" class="login-logout-btn">LOGIN</button>
|
||||
<div class="user-details" id="persistent-user-details" style="display: none;">
|
||||
<div><strong>Name:</strong> <span id="persistent-user-name">Loading...</span></div>
|
||||
<div><strong>Public Key:</strong>
|
||||
<div class="user-pubkey" id="persistent-user-pubkey">Loading...</div>
|
||||
</div>
|
||||
<div><strong>About:</strong> <span id="persistent-user-about">Loading...</span></div>
|
||||
<!-- Header with title and profile display -->
|
||||
<div class="section">
|
||||
|
||||
<div class="header-content">
|
||||
<div class="header-title clickable" id="header-title">
|
||||
<span class="relay-letter" data-letter="R">R</span>
|
||||
<span class="relay-letter" data-letter="E">E</span>
|
||||
<span class="relay-letter" data-letter="L">L</span>
|
||||
<span class="relay-letter" data-letter="A">A</span>
|
||||
<span class="relay-letter" data-letter="Y">Y</span>
|
||||
</div>
|
||||
<div class="relay-info">
|
||||
<div id="relay-name" class="relay-name">C-Relay-PG</div>
|
||||
<div id="relay-description" class="relay-description">Loading...</div>
|
||||
<div id="relay-pubkey-container" class="relay-pubkey-container">
|
||||
<div id="relay-pubkey" class="relay-pubkey">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Login Section -->
|
||||
<div id="login-section" class="flex-section">
|
||||
<div class="section">
|
||||
<h2>NOSTR AUTHENTICATION</h2>
|
||||
<p id="login-instructions">Please login with your Nostr identity to access the admin interface.</p>
|
||||
<!-- nostr-lite login UI will be injected here -->
|
||||
<div class="profile-area" id="profile-area" style="display: none;">
|
||||
<div class="admin-label">admin</div>
|
||||
<div class="profile-container">
|
||||
<img id="header-user-image" class="header-user-image" alt="Profile" style="display: none;">
|
||||
<span id="header-user-name" class="header-user-name">Loading...</span>
|
||||
</div>
|
||||
<!-- Logout dropdown -->
|
||||
<!-- Dropdown menu removed - buttons moved to sidebar -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Relay Connection Section -->
|
||||
<div id="relay-connection-section" class="flex-section">
|
||||
<div class="section">
|
||||
<h2>RELAY CONNECTION</h2>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="relay-connection-url">Relay URL:</label>
|
||||
<input type="text" id="relay-connection-url" value="ws://localhost:8888"
|
||||
placeholder="ws://localhost:8888 or wss://relay.example.com">
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="relay-pubkey-manual">Relay Pubkey (if not available via NIP-11):</label>
|
||||
<input type="text" id="relay-pubkey-manual" placeholder="64-character hex pubkey"
|
||||
pattern="[0-9a-fA-F]{64}" title="64-character hexadecimal public key">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="connect-relay-btn">CONNECT TO RELAY</button>
|
||||
<button type="button" id="disconnect-relay-btn" disabled>DISCONNECT</button>
|
||||
<button type="button" id="restart-relay-btn" disabled>RESTART RELAY</button>
|
||||
</div>
|
||||
|
||||
<div class="status disconnected" id="relay-connection-status">NOT CONNECTED</div>
|
||||
|
||||
<!-- Relay Information Display -->
|
||||
<div id="relay-info-display" class="hidden">
|
||||
<h3>Relay Information (NIP-11)</h3>
|
||||
<table class="config-table" id="relay-info-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Property</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="relay-info-table-body">
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- End Main Sections Wrapper -->
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Testing Section -->
|
||||
<div id="div_config" class="section flex-section" style="display: none;">
|
||||
<h2>RELAY CONFIGURATION</h2>
|
||||
<div id="config-display" class="hidden">
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="config-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Value</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="config-table-body">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="fetch-config-btn">REFRESH</button>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Auth Rules Management - Moved after configuration -->
|
||||
<div class="section flex-section" id="authRulesSection" style="display: none;">
|
||||
<div class="section-header">
|
||||
<h2>AUTH RULES MANAGEMENT</h2>
|
||||
</div>
|
||||
|
||||
<!-- Auth Rules Table -->
|
||||
<div id="authRulesTableContainer" style="display: none;">
|
||||
<table class="config-table" id="authRulesTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rule Type</th>
|
||||
<th>Pattern Type</th>
|
||||
<th>Pattern Value</th>
|
||||
<th>Action</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="authRulesTableBody">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Simplified Auth Rule Input Section -->
|
||||
<div id="authRuleInputSections" style="display: block;">
|
||||
|
||||
<!-- Combined Pubkey Auth Rule Section -->
|
||||
|
||||
|
||||
<div class="input-group">
|
||||
<label for="authRulePubkey">Pubkey (nsec or hex):</label>
|
||||
<input type="text" id="authRulePubkey" placeholder="nsec1... or 64-character hex pubkey">
|
||||
|
||||
</div>
|
||||
<div id="whitelistWarning" class="warning-box" style="display: none;">
|
||||
<strong>⚠️ WARNING:</strong> Adding whitelist rules changes relay behavior to whitelist-only
|
||||
mode.
|
||||
Only whitelisted users will be able to interact with the relay.
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="addWhitelistBtn" onclick="addWhitelistRule()">ADD TO
|
||||
WHITELIST</button>
|
||||
<button type="button" id="addBlacklistBtn" onclick="addBlacklistRule()">ADD TO
|
||||
BLACKLIST</button>
|
||||
<button type="button" id="refreshAuthRulesBtn">REFRESH</button>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Login Modal Overlay -->
|
||||
<div id="login-modal" class="login-modal-overlay" style="display: none;">
|
||||
<div class="login-modal-content">
|
||||
<div id="login-modal-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Access Denied Overlay (shown when non-admin user logs in) -->
|
||||
<div id="access-denied-overlay" class="access-denied-overlay" style="display: none;">
|
||||
<div class="access-denied-content">
|
||||
<div class="access-denied-icon">⛔</div>
|
||||
<h2>ACCESS DENIED</h2>
|
||||
<p class="access-denied-message">This interface is restricted to the relay administrator.</p>
|
||||
<p class="access-denied-submessage">The logged-in account does not have admin privileges.</p>
|
||||
<button type="button" class="access-denied-logout-btn" onclick="logout()">LOGOUT</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DATABASE STATISTICS Section -->
|
||||
<div class="section">
|
||||
<!-- Subscribe to kind 24567 events to receive real-time monitoring data -->
|
||||
<div class="section flex-section" id="databaseStatisticsSection" style="display: none;">
|
||||
<div class="section-header">
|
||||
<h2>DATABASE STATISTICS</h2>
|
||||
DATABASE STATISTICS
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Event Rate Graph Container -->
|
||||
<div id="event-rate-chart"></div>
|
||||
|
||||
<!-- Database Overview Table -->
|
||||
<div class="input-group">
|
||||
<label>Database Overview:</label>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="stats-overview-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Metric</th>
|
||||
<th>Value</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="stats-overview-table-body">
|
||||
<tr>
|
||||
<td>Database Size</td>
|
||||
<td id="db-size">-</td>
|
||||
<td>Current database file size</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Events</td>
|
||||
<td id="total-events">-</td>
|
||||
<td>Total number of events stored</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Process ID</td>
|
||||
<td id="process-id">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WebSocket Connections</td>
|
||||
<td id="websocket-connections">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Active Subscriptions</td>
|
||||
<td id="active-subscriptions">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Memory Usage</td>
|
||||
<td id="memory-usage">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CPU Usage</td>
|
||||
<td id="cpu-usage">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CPU Core</td>
|
||||
<td id="cpu-core">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Oldest Event</td>
|
||||
<td id="oldest-event">-</td>
|
||||
<td>Timestamp of oldest event</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Newest Event</td>
|
||||
<td id="newest-event">-</td>
|
||||
<td>Timestamp of newest event</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -248,24 +176,20 @@
|
||||
<tr>
|
||||
<th>Period</th>
|
||||
<th>Events</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="stats-time-table-body">
|
||||
<tr>
|
||||
<td>Last 24 Hours</td>
|
||||
<td id="events-24h">-</td>
|
||||
<td>Events in the last day</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last 7 Days</td>
|
||||
<td id="events-7d">-</td>
|
||||
<td>Events in the last week</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last 30 Days</td>
|
||||
<td id="events-30d">-</td>
|
||||
<td>Events in the last month</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -280,6 +204,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rank</th>
|
||||
<th>Name</th>
|
||||
<th>Pubkey</th>
|
||||
<th>Event Count</th>
|
||||
<th>Percentage</th>
|
||||
@@ -287,19 +212,157 @@
|
||||
</thead>
|
||||
<tbody id="stats-pubkeys-table-body">
|
||||
<tr>
|
||||
<td colspan="4" style="text-align: center; font-style: italic;">No data loaded</td>
|
||||
<td colspan="5" style="text-align: center; font-style: italic;">No data loaded</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Refresh Button -->
|
||||
</div>
|
||||
|
||||
<!-- SUBSCRIPTION DETAILS Section (Admin Only) -->
|
||||
<div class="section flex-section" id="subscriptionDetailsSection" style="display: none;">
|
||||
<div class="section-header">
|
||||
ACTIVE SUBSCRIPTION DETAILS
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<button type="button" id="refresh-stats-btn">REFRESH STATISTICS</button>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="subscription-details-table">
|
||||
<tbody id="subscription-details-table-body">
|
||||
<tr>
|
||||
<td colspan="4" style="text-align: center; font-style: italic;">No subscriptions active</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Testing Section -->
|
||||
<div id="div_config" class="section flex-section" style="display: none;">
|
||||
<div class="section-header">
|
||||
RELAY CONFIGURATION
|
||||
</div>
|
||||
<div id="config-display" class="hidden">
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="config-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Value</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="config-table-body">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="fetch-config-btn">REFRESH</button>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Auth Rules Management - Moved after configuration -->
|
||||
<!-- AUTH RULES MANAGEMENT SECTION -->
|
||||
<div class="section flex-section" id="authRulesSection" style="display: none;">
|
||||
<div class="section-header">
|
||||
AUTH RULES MANAGEMENT
|
||||
</div>
|
||||
|
||||
<!-- Auth Rules Table -->
|
||||
<div id="authRulesTableContainer" style="display: none;">
|
||||
<table class="config-table" id="authRulesTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rule Type</th>
|
||||
<th>Pattern Type</th>
|
||||
<th>Pattern Value</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="authRulesTableBody">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Auth Rule Input Section -->
|
||||
<div id="authRuleInputSections" style="display: block;">
|
||||
<div class="input-group">
|
||||
<label for="authRulePubkey">Public Key (npub or hex):</label>
|
||||
<input type="text" id="authRulePubkey" placeholder="npub1... or 64-character hex pubkey">
|
||||
</div>
|
||||
<div id="whitelistWarning" class="warning-box" style="display: none;">
|
||||
<strong>⚠️ WARNING:</strong> Adding whitelist rules changes relay behavior to whitelist-only
|
||||
mode.
|
||||
Only whitelisted users will be able to interact with the relay.
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="addWhitelistBtn" onclick="addWhitelistRule()">ADD TO
|
||||
WHITELIST</button>
|
||||
<button type="button" id="addBlacklistBtn" onclick="addBlacklistRule()">ADD TO
|
||||
BLACKLIST</button>
|
||||
<button type="button" id="refreshAuthRulesBtn">REFRESH</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- WEB OF TRUST SECTION -->
|
||||
<div class="section flex-section" id="wotSection" style="display: none;">
|
||||
<div class="section-header">
|
||||
WEB OF TRUST
|
||||
</div>
|
||||
|
||||
<!-- Kind 3 Status Indicator -->
|
||||
<div id="wotKind3Status" class="wot-status-row">
|
||||
<span>Admin Contact List (kind 3):</span>
|
||||
<span id="wotKind3Indicator" class="wot-indicator wot-unknown">Checking...</span>
|
||||
</div>
|
||||
|
||||
<!-- WoT Level Selector -->
|
||||
<div class="wot-level-selector">
|
||||
<label>WoT Level:</label>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="wotLevel0Btn" class="wot-level-btn" onclick="setWotLevel(0)">
|
||||
OFF
|
||||
</button>
|
||||
<button type="button" id="wotLevel1Btn" class="wot-level-btn" onclick="setWotLevel(1)">
|
||||
WRITE ONLY
|
||||
</button>
|
||||
<button type="button" id="wotLevel2Btn" class="wot-level-btn" onclick="setWotLevel(2)">
|
||||
FULL
|
||||
</button>
|
||||
</div>
|
||||
<div class="wot-level-description" id="wotLevelDescription">
|
||||
Level 0: Open relay — anyone can read and write
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- WoT Stats -->
|
||||
<div class="wot-stats-row">
|
||||
<span>Whitelisted Pubkeys:</span>
|
||||
<span id="wotWhitelistCount">—</span>
|
||||
</div>
|
||||
|
||||
<!-- Sync Button -->
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="wotSyncBtn" onclick="syncWot()">SYNC FROM KIND 3</button>
|
||||
<button type="button" id="wotRefreshBtn" onclick="loadWotStatus()">REFRESH STATUS</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- NIP-17 DIRECT MESSAGES Section -->
|
||||
<div class="section" id="nip17DMSection" style="display: none;">
|
||||
<div class="section-header">
|
||||
@@ -307,7 +370,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Outbox -->
|
||||
<div class="input-group">
|
||||
<div>
|
||||
<label for="dm-outbox">Send Message to Relay:</label>
|
||||
<textarea id="dm-outbox" rows="4" placeholder="Enter your message to send to the relay..."></textarea>
|
||||
</div>
|
||||
@@ -326,6 +389,408 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- IP BANS Section -->
|
||||
<div class="section" id="ipBansSection" style="display: none;">
|
||||
<div class="section-header">
|
||||
IP BAN MANAGEMENT
|
||||
</div>
|
||||
|
||||
<!-- Statistics Cards -->
|
||||
<div class="input-group">
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="ip-bans-stats-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Total IPs Tracked</th>
|
||||
<th>Currently Banned</th>
|
||||
<th>Total Bans Issued</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td id="ip-bans-total">-</td>
|
||||
<td id="ip-bans-active">-</td>
|
||||
<td id="ip-bans-issued">-</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Ban Form -->
|
||||
<div class="input-group">
|
||||
<h3>Manually Ban IP Address</h3>
|
||||
<div class="form-group">
|
||||
<label for="ban-ip-input">IP Address:</label>
|
||||
<input type="text" id="ban-ip-input" placeholder="192.168.1.100">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="ban-duration-select">Ban Duration:</label>
|
||||
<select id="ban-duration-select">
|
||||
<option value="3600">1 Hour</option>
|
||||
<option value="86400" selected>24 Hours</option>
|
||||
<option value="604800">7 Days</option>
|
||||
<option value="2592000">30 Days</option>
|
||||
<option value="31536000">1 Year</option>
|
||||
<option value="999999999">Permanent</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="add-ban-btn">BAN IP</button>
|
||||
</div>
|
||||
<div id="add-ban-status" class="status-message"></div>
|
||||
</div>
|
||||
|
||||
<!-- Whitelist Management -->
|
||||
<div class="input-group">
|
||||
<h3>IP Whitelist (Never Banned)</h3>
|
||||
<p style="font-size:13px;opacity:0.8;">IPs in this list are never idle-banned. Comma-separated.</p>
|
||||
<div class="form-group">
|
||||
<label for="whitelist-ip-input">Add IP to Whitelist:</label>
|
||||
<input type="text" id="whitelist-ip-input" placeholder="103.81.231.220">
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="add-whitelist-btn">ADD TO WHITELIST</button>
|
||||
</div>
|
||||
<div id="whitelist-status" class="status-message"></div>
|
||||
<div id="whitelist-current" style="margin-top:8px;font-size:13px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- Filter Controls -->
|
||||
<div class="input-group">
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="ip-ban-filter-all" class="active">All IPs</button>
|
||||
<button type="button" id="ip-ban-filter-banned">Currently Banned</button>
|
||||
<button type="button" id="ip-ban-filter-expired">Expired</button>
|
||||
<button type="button" id="refresh-ip-bans-btn">REFRESH</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- IP Bans List -->
|
||||
<div class="input-group">
|
||||
<label>Banned IP Addresses:</label>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="ip-bans-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>IP Address</th>
|
||||
<th>Status</th>
|
||||
<th>Banned Until</th>
|
||||
<th>Failures</th>
|
||||
<th>Authed Successfully</th>
|
||||
<th>Connection Attempts</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="ip-bans-tbody">
|
||||
<tr>
|
||||
<td colspan="7" style="text-align: center;">Click REFRESH to load IP bans</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RELAY EVENTS Section -->
|
||||
<div class="section" id="relayEventsSection" style="display: none;">
|
||||
<div class="section-header">
|
||||
RELAY EVENTS MANAGEMENT
|
||||
</div>
|
||||
|
||||
<!-- Live Relay Event Feed -->
|
||||
<div class="input-group">
|
||||
<h3>Live Relay Event Feed (Normal Nostr Subscription)</h3>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="live-relay-events-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Kind</th>
|
||||
<th>Pubkey</th>
|
||||
<th>ID</th>
|
||||
<th>Content Preview</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="live-relay-events-table-body">
|
||||
<tr>
|
||||
<td colspan="5" style="text-align: center;">Waiting for live events...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Kind 0: User Metadata -->
|
||||
<div class="input-group">
|
||||
<h3>Kind 0: User Metadata</h3>
|
||||
<div class="form-group">
|
||||
<label for="kind0-name">Name:</label>
|
||||
<input type="text" id="kind0-name" placeholder="Relay Name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="kind0-about">About:</label>
|
||||
<textarea id="kind0-about" rows="3" placeholder="Relay Description"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="kind0-picture">Picture URL:</label>
|
||||
<input type="url" id="kind0-picture" placeholder="https://example.com/logo.png">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="kind0-banner">Banner URL:</label>
|
||||
<input type="url" id="kind0-banner" placeholder="https://example.com/banner.png">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="kind0-nip05">NIP-05:</label>
|
||||
<input type="text" id="kind0-nip05" placeholder="relay@example.com">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="kind0-website">Website:</label>
|
||||
<input type="url" id="kind0-website" placeholder="https://example.com">
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="submit-kind0-btn">UPDATE METADATA</button>
|
||||
</div>
|
||||
<div id="kind0-status" class="status-message"></div>
|
||||
</div>
|
||||
|
||||
<!-- Kind 10050: DM Relay List -->
|
||||
<div class="input-group">
|
||||
<h3>Kind 10050: DM Relay List</h3>
|
||||
<div class="form-group">
|
||||
<label for="kind10050-relays">Relay URLs (one per line):</label>
|
||||
<textarea id="kind10050-relays" rows="4" placeholder="wss://relay1.com wss://relay2.com"></textarea>
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="submit-kind10050-btn">UPDATE DM RELAYS</button>
|
||||
</div>
|
||||
<div id="kind10050-status" class="status-message"></div>
|
||||
</div>
|
||||
|
||||
<!-- Kind 10002: Relay List -->
|
||||
<div class="input-group">
|
||||
<h3>Kind 10002: Relay List</h3>
|
||||
<div id="kind10002-relay-entries">
|
||||
<!-- Dynamic relay entries will be added here -->
|
||||
</div>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="add-relay-entry-btn">ADD RELAY</button>
|
||||
<button type="button" id="submit-kind10002-btn">UPDATE RELAYS</button>
|
||||
</div>
|
||||
<div id="kind10002-status" class="status-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CACHING Section -->
|
||||
<div class="section" id="cachingSection" style="display: none;">
|
||||
<div class="section-header">CACHING</div>
|
||||
|
||||
<!-- Caching Service Status (read-only) -->
|
||||
<div class="input-group">
|
||||
<h3>Caching Service Status</h3>
|
||||
<div id="caching-service-status" class="status-display">
|
||||
<p>Service status will appear here after connecting.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Relay Inbox Status (read-only) -->
|
||||
<div class="input-group">
|
||||
<h3>Relay Inbox Status</h3>
|
||||
<div id="caching-inbox-status" class="status-display">
|
||||
<p>Inbox status will appear here after connecting.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Caching Configuration (editable) -->
|
||||
<div class="input-group">
|
||||
<h3>Caching Configuration</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-enabled">Enable Caching:</label>
|
||||
<select id="caching-enabled">
|
||||
<option value="false">Disabled</option>
|
||||
<option value="true">Enabled</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-inbox-enabled">Enable Inbox Consumer:</label>
|
||||
<select id="caching-inbox-enabled">
|
||||
<option value="false">Disabled</option>
|
||||
<option value="true">Enabled</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-root-npubs">Root Npubs (one per line):</label>
|
||||
<textarea id="caching-root-npubs" rows="4" placeholder="npub1...">npub13lm5wf8dvsdnc2894pkhch9uf8phvw9varrv8zf4sc885hhdmc8q6lx7ks</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-bootstrap-relays">Bootstrap Relays (one per line):</label>
|
||||
<textarea id="caching-bootstrap-relays" rows="4" placeholder="wss://relay.damus.io">wss://relay.damus.io
|
||||
wss://nos.lol
|
||||
wss://relay.primal.net
|
||||
wss://laantungir.net/relay</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-kinds">Kinds (comma-separated):</label>
|
||||
<input type="text" id="caching-kinds" placeholder="1,3,6,10000,30023" value="0,1,3,6,10000,10002,30023">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-admin-kinds">Admin Kinds (comma-separated, * for all):</label>
|
||||
<input type="text" id="caching-admin-kinds" placeholder="*">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-live-enabled">Live Subscriptions:</label>
|
||||
<select id="caching-live-enabled">
|
||||
<option value="true">Enabled</option>
|
||||
<option value="false">Disabled</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-backfill-enabled">Backfill:</label>
|
||||
<select id="caching-backfill-enabled">
|
||||
<option value="true">Enabled</option>
|
||||
<option value="false">Disabled</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-backfill-windows">Backfill Windows (seconds, comma-separated):</label>
|
||||
<input type="text" id="caching-backfill-windows" placeholder="86400,604800,2592000,7776000,31536000">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-backfill-page-size">Backfill Page Size:</label>
|
||||
<input type="number" id="caching-backfill-page-size" placeholder="50">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-backfill-tick-interval">Backfill Tick Interval (ms):</label>
|
||||
<input type="number" id="caching-backfill-tick-interval" placeholder="5000">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-inbox-batch-size">Inbox Batch Size:</label>
|
||||
<input type="number" id="caching-inbox-batch-size" placeholder="150">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-inbox-active-poll">Inbox Active Poll (ms):</label>
|
||||
<input type="number" id="caching-inbox-active-poll" placeholder="200">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-inbox-idle-poll">Inbox Idle Poll (ms):</label>
|
||||
<input type="number" id="caching-inbox-idle-poll" placeholder="5000">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-service-binary-path">Caching Service Binary Path:</label>
|
||||
<input type="text" id="caching-service-binary-path" placeholder="./caching_relay" value="./caching_relay">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-service-pg-conn">Caching Service PG Connection:</label>
|
||||
<input type="text" id="caching-service-pg-conn" placeholder="host=localhost port=5432 dbname=crelay user=crelay password=crelay" value="host=localhost port=5432 dbname=crelay user=crelay password=crelay">
|
||||
</div>
|
||||
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="caching-apply-btn">APPLY CONFIGURATION</button>
|
||||
<button type="button" id="caching-reset-progress-btn">RESET BACKFILL PROGRESS</button>
|
||||
</div>
|
||||
<div id="caching-config-status" class="status-message"></div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<h3>Caching Service Control</h3>
|
||||
<p>Start or stop the external caching service process. Set <code>caching_service_binary_path</code> and <code>caching_service_pg_conn</code> above and click APPLY CONFIGURATION before starting.</p>
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="caching-start-service-btn">START CACHING SERVICE</button>
|
||||
<button type="button" id="caching-stop-service-btn">STOP CACHING SERVICE</button>
|
||||
</div>
|
||||
<div id="caching-service-control-status" class="status-message"></div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<h3>Followed Pubkeys</h3>
|
||||
<p>Pubkeys being cached with their profile names, event counts, outbox relays, and backfill status.</p>
|
||||
<div id="caching-follows-status" class="status-message"></div>
|
||||
<table id="caching-follows-table" style="width: 100%; border-collapse: collapse; font-size: 13px;">
|
||||
<thead>
|
||||
<tr style="border-bottom: 2px solid var(--border-color, #444); text-align: left;">
|
||||
<th style="padding: 6px 8px;">Name</th>
|
||||
<th style="padding: 6px 8px;">npub</th>
|
||||
<th style="padding: 6px 8px;">Root?</th>
|
||||
<th style="padding: 6px 8px;">Events in DB</th>
|
||||
<th style="padding: 6px 8px;">Backfill</th>
|
||||
<th style="padding: 6px 8px; width: 40%;">Relays (status, events fetched)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="caching-follows-table-body">
|
||||
<tr><td colspan="6" style="text-align: center; font-style: italic; padding: 12px;">Loading follows status...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SQL QUERY Section -->
|
||||
<div class="section" id="sqlQuerySection" style="display: none;">
|
||||
<div class="section-header">
|
||||
<h2>SQL QUERY CONSOLE</h2>
|
||||
</div>
|
||||
|
||||
<!-- Query Selector -->
|
||||
<div class="input-group">
|
||||
<label for="query-dropdown">Quick Queries & History:</label>
|
||||
<select id="query-dropdown" onchange="loadSelectedQuery()">
|
||||
<option value="">-- Select a query --</option>
|
||||
<optgroup label="Common Queries">
|
||||
<option value="recent_events">Recent Events</option>
|
||||
<option value="event_stats">Event Statistics</option>
|
||||
<option value="subscriptions">Active Subscriptions</option>
|
||||
<option value="top_pubkeys">Top Pubkeys</option>
|
||||
<option value="event_kinds">Event Kinds Distribution</option>
|
||||
<option value="time_stats">Time-based Statistics</option>
|
||||
</optgroup>
|
||||
<optgroup label="IP Ban Queries">
|
||||
<option value="banned_ips_summary">Banned IPs Summary</option>
|
||||
<option value="banned_ips_list">All Banned IP Addresses</option>
|
||||
</optgroup>
|
||||
<optgroup label="Query History" id="history-group">
|
||||
<!-- Dynamically populated from localStorage -->
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Query Editor -->
|
||||
<div class="input-group">
|
||||
<label for="sql-input">SQL Query:</label>
|
||||
<textarea id="sql-input" rows="5" placeholder="SELECT * FROM events LIMIT 10"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Query Actions -->
|
||||
<div class="input-group">
|
||||
<div class="inline-buttons">
|
||||
<button type="button" id="execute-sql-btn">EXECUTE QUERY</button>
|
||||
<button type="button" id="clear-sql-btn">CLEAR</button>
|
||||
<button type="button" id="clear-history-btn">CLEAR HISTORY</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Query Results -->
|
||||
<div class="input-group">
|
||||
<label>Query Results:</label>
|
||||
<div id="query-info" class="info-box"></div>
|
||||
<div id="query-table" class="config-table-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Load the official nostr-tools bundle first -->
|
||||
<!-- <script src="https://laantungir.net/nostr-login-lite/nostr.bundle.js"></script> -->
|
||||
<script src="/api/nostr.bundle.js"></script>
|
||||
@@ -333,6 +798,8 @@
|
||||
<!-- Load NOSTR_LOGIN_LITE main library -->
|
||||
<!-- <script src="https://laantungir.net/nostr-login-lite/nostr-lite.js"></script> -->
|
||||
<script src="/api/nostr-lite.js"></script>
|
||||
<!-- Load text_graph library -->
|
||||
<script src="/api/text_graph.js"></script>
|
||||
|
||||
|
||||
|
||||
|
||||
+7067
-3120
File diff suppressed because it is too large
Load Diff
+95
-1
@@ -3297,8 +3297,18 @@ var NostrTools = (() => {
|
||||
this.enablePing = opts.enablePing;
|
||||
}
|
||||
async ensureRelay(url, params) {
|
||||
const rawUrl = url;
|
||||
const debugEnabled = typeof window !== "undefined" && !!window.__SIMPLE_POOL_DEBUG__;
|
||||
url = normalizeURL(url);
|
||||
let relay = this.relays.get(url);
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL ensureRelay START", {
|
||||
rawUrl,
|
||||
normalizedUrl: url,
|
||||
hadRelay: !!relay,
|
||||
relayMapKeysBefore: Array.from(this.relays.keys())
|
||||
});
|
||||
}
|
||||
if (!relay) {
|
||||
relay = new AbstractRelay(url, {
|
||||
verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,
|
||||
@@ -3306,13 +3316,38 @@ var NostrTools = (() => {
|
||||
enablePing: this.enablePing
|
||||
});
|
||||
relay.onclose = () => {
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL ensureRelay onclose", {
|
||||
normalizedUrl: url,
|
||||
relayMapKeysBeforeDelete: Array.from(this.relays.keys())
|
||||
});
|
||||
}
|
||||
this.relays.delete(url);
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL ensureRelay onclose complete", {
|
||||
normalizedUrl: url,
|
||||
relayMapKeysAfterDelete: Array.from(this.relays.keys())
|
||||
});
|
||||
}
|
||||
};
|
||||
if (params?.connectionTimeout)
|
||||
relay.connectionTimeout = params.connectionTimeout;
|
||||
this.relays.set(url, relay);
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL ensureRelay created relay", {
|
||||
normalizedUrl: url,
|
||||
relayMapKeysAfterCreate: Array.from(this.relays.keys())
|
||||
});
|
||||
}
|
||||
}
|
||||
await relay.connect();
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL ensureRelay connected", {
|
||||
normalizedUrl: url,
|
||||
relayConnected: relay.connected,
|
||||
relayMapKeysAfterConnect: Array.from(this.relays.keys())
|
||||
});
|
||||
}
|
||||
return relay;
|
||||
}
|
||||
close(relays) {
|
||||
@@ -3334,16 +3369,26 @@ var NostrTools = (() => {
|
||||
}
|
||||
subscribeMany(relays, filters, params) {
|
||||
params.onauth = params.onauth || params.doauth;
|
||||
const debugEnabled = typeof window !== "undefined" && !!window.__SIMPLE_POOL_DEBUG__;
|
||||
const request = [];
|
||||
const uniqUrls = [];
|
||||
for (let i2 = 0; i2 < relays.length; i2++) {
|
||||
const url = normalizeURL(relays[i2]);
|
||||
if (uniqUrls.indexOf(url) === -1) {
|
||||
uniqUrls.push(url);
|
||||
for (let f2 = 0; f2 < filters.length; f2++) {
|
||||
request.push({ url, filter: filters[f2] });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL subscribeMany", {
|
||||
relaysInput: relays,
|
||||
uniqUrls,
|
||||
filtersCount: filters.length,
|
||||
requestsCount: request.length
|
||||
});
|
||||
}
|
||||
return this.subscribeMap(request, params);
|
||||
}
|
||||
subscribeMap(requests, params) {
|
||||
@@ -3391,14 +3436,31 @@ var NostrTools = (() => {
|
||||
_knownIds.add(id);
|
||||
return have;
|
||||
};
|
||||
const debugEnabled = typeof window !== "undefined" && !!window.__SIMPLE_POOL_DEBUG__;
|
||||
const allOpened = Promise.all(
|
||||
requests.map(async ({ url, filter }, i2) => {
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL subscribeMap request", {
|
||||
index: i2,
|
||||
url,
|
||||
filterKinds: filter?.kinds,
|
||||
hasAuthorFilter: !!filter?.authors,
|
||||
hasPTagFilter: !!filter?.["#p"]
|
||||
});
|
||||
}
|
||||
let relay;
|
||||
try {
|
||||
relay = await this.ensureRelay(url, {
|
||||
connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : void 0
|
||||
});
|
||||
} catch (err) {
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL subscribeMap ensureRelay FAILED", {
|
||||
index: i2,
|
||||
url,
|
||||
error: err?.message || String(err)
|
||||
});
|
||||
}
|
||||
handleClose(i2, err?.message || String(err));
|
||||
return;
|
||||
}
|
||||
@@ -3480,18 +3542,50 @@ var NostrTools = (() => {
|
||||
return events[0] || null;
|
||||
}
|
||||
publish(relays, event, options) {
|
||||
return relays.map(normalizeURL).map(async (url, i2, arr) => {
|
||||
const debugEnabled = typeof window !== "undefined" && !!window.__SIMPLE_POOL_DEBUG__;
|
||||
const normalizedRelays = relays.map(normalizeURL);
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL publish START", {
|
||||
relaysInput: relays,
|
||||
normalizedRelays,
|
||||
eventKind: event?.kind,
|
||||
eventId: event?.id
|
||||
});
|
||||
}
|
||||
return normalizedRelays.map(async (url, i2, arr) => {
|
||||
if (arr.indexOf(url) !== i2) {
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL publish duplicate URL", { url, index: i2 });
|
||||
}
|
||||
return Promise.reject("duplicate url");
|
||||
}
|
||||
let r = await this.ensureRelay(url);
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL publish ensured relay", {
|
||||
url,
|
||||
relayConnected: r?.connected,
|
||||
relayMapKeys: Array.from(this.relays.keys())
|
||||
});
|
||||
}
|
||||
return r.publish(event).catch(async (err) => {
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL publish ERROR", {
|
||||
url,
|
||||
error: err?.message || String(err)
|
||||
});
|
||||
}
|
||||
if (err instanceof Error && err.message.startsWith("auth-required: ") && options?.onauth) {
|
||||
await r.auth(options.onauth);
|
||||
return r.publish(event);
|
||||
}
|
||||
throw err;
|
||||
}).then((reason) => {
|
||||
if (debugEnabled) {
|
||||
console.log("🔎 SIMPLE_POOL publish SUCCESS", {
|
||||
url,
|
||||
reason
|
||||
});
|
||||
}
|
||||
if (this.trackRelays) {
|
||||
let set = this.seenOn.get(event.id);
|
||||
if (!set) {
|
||||
|
||||
@@ -0,0 +1,813 @@
|
||||
<!DOCTYPE html>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<html lang="en" dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>TEMPLATE</title>
|
||||
|
||||
<link rel="stylesheet" href="./css/client.css" />
|
||||
|
||||
<!-- Initialize theme BEFORE any components load -->
|
||||
<script>
|
||||
(function () {
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme === 'dark') {
|
||||
document.documentElement.classList.add('dark-mode');
|
||||
if (document.body) {
|
||||
document.body.classList.add('dark-mode');
|
||||
}
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
|
||||
|
||||
<!-- SVG.js library (required by HamburgerMorphing) -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- ================================================================
|
||||
HAMBURGER BUTTON (Fixed, separate from header)
|
||||
================================================================
|
||||
The hamburger button is a fixed element outside the header
|
||||
to ensure it stays visible above the sidenav (z-index: 10 > 3).
|
||||
================================================================ -->
|
||||
<div id="divSvgHam" class="divHeaderButtons">
|
||||
<!-- HamburgerMorphing will be injected here -->
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
HEADER
|
||||
================================================================
|
||||
Standard header with title (center).
|
||||
================================================================ -->
|
||||
<div id="divHeader">
|
||||
<div id="divHeaderFlexLeft">
|
||||
<!-- Hamburger is now separate fixed element -->
|
||||
</div>
|
||||
|
||||
<div id="divHeaderFlexCenter">
|
||||
<div class="divHeaderText"></div>
|
||||
</div>
|
||||
|
||||
<div id="divHeaderFlexRight">
|
||||
<!-- No button in header right - logout is in sidenav footer -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
BODY
|
||||
================================================================
|
||||
Main content area. Add your page-specific content here.
|
||||
================================================================ -->
|
||||
<div id="divBody">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
FOOTER
|
||||
================================================================
|
||||
Three-section footer layout:
|
||||
- Left: Relay status animations (HamburgerMorphing instances)
|
||||
- Center: General status information
|
||||
- Right: Additional information
|
||||
================================================================ -->
|
||||
<div id="divFooter">
|
||||
<div id="divFooterLeft" class="divFooterBox"></div>
|
||||
<div id="divFooterCenter" class="divFooterBox"></div>
|
||||
<div id="divFooterRight" class="divFooterBox"></div>
|
||||
<div id="divFooterBalance" class="divFooterBox">0 sats</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
SIDENAV
|
||||
================================================================
|
||||
Slide-out navigation panel. Opens from left when hamburger clicked.
|
||||
Uses flexbox layout to pin version bar to bottom.
|
||||
Includes a version bar footer with theme toggle and logout buttons.
|
||||
================================================================ -->
|
||||
<div id="divSideNav">
|
||||
<div id="divSideNavHeader">
|
||||
<!-- No close button - use main hamburger to close -->
|
||||
</div>
|
||||
|
||||
<div id="divSideNavBody">
|
||||
<div id="divFiles"></div>
|
||||
</div>
|
||||
|
||||
<div id="divAiSection" class="sidenavSection">
|
||||
<div id="divAiSectionTitle" class="sidenavSectionTitle">AI</div>
|
||||
<div id="divAiList" class="sidenavSectionList">
|
||||
<div id="divAiProvidersList">No saved providers yet.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="divRelaySection">
|
||||
<div id="divRelaySectionTitle">
|
||||
リレー
|
||||
</div>
|
||||
<div id="divRelayList">
|
||||
Loading relays...
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="divBlossomSection">
|
||||
|
||||
<div id="divBlossomSectionTitle">ブロッサム</div>
|
||||
|
||||
<div id="divBlossomList">Loading blossom servers...</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="divVersionBar">
|
||||
<span id="versionDisplay">v0.0.1</span>
|
||||
<div id="divVersionBarButtons">
|
||||
<button id="themeToggleButton" title="Toggle Dark/Light Mode">
|
||||
<div id="themeToggleHamburgerContainer"></div>
|
||||
</button>
|
||||
<button id="logoutButton" title="Logout">
|
||||
<div id="logoutHamburgerContainer"></div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
REQUIRED SCRIPTS
|
||||
================================================================
|
||||
These scripts must be loaded in this order:
|
||||
1. nostr.bundle.js - Nostr tools library
|
||||
2. nostr-lite.js - Authentication modal (nostr-login-lite)
|
||||
================================================================ -->
|
||||
<script src="./nostr.bundle.js"></script>
|
||||
<script src="./nostr-lite.js"></script>
|
||||
|
||||
<script type="module">
|
||||
/* ================================================================
|
||||
IMPORTS
|
||||
================================================================
|
||||
Import shared NDK functionality from init-ndk.mjs:
|
||||
- initNDKPage() - Initialize authentication and worker
|
||||
- getPubkey() - Get current user's pubkey
|
||||
- subscribe() - Create NDK subscriptions
|
||||
- publishEvent() - Publish events via NDK
|
||||
- disconnect() - Disconnect from worker
|
||||
- getRelayData() - Get relay connection data
|
||||
- getRelayStats() - Get relay activity statistics
|
||||
|
||||
Import HamburgerMorphing for animated icons
|
||||
================================================================ */
|
||||
import {
|
||||
initNDKPage,
|
||||
getPubkey, injectHeaderAvatar,
|
||||
subscribe,
|
||||
publishEvent,
|
||||
disconnect,
|
||||
getVersion,
|
||||
updateVersionDisplay,
|
||||
getUserSettings,
|
||||
patchUserSettings,
|
||||
onUserSettings
|
||||
} from './js/init-ndk.mjs';
|
||||
import { HamburgerMorphing } from "./hamburger_morphing/hamburger.mjs";
|
||||
import { initFooterRelayStatus, updateFooterRelayStatus, initSidenavRelaySection, updateSidenavRelaySection, setRelayActivityState } from './js/relay-ui.mjs';
|
||||
|
||||
import { initBlossomSection, updateBlossomSection } from './js/blossom-ui.mjs';
|
||||
|
||||
import { initAiSectionWithLocalConfig } from './js/ai-ui.mjs';
|
||||
// Version will be loaded asynchronously
|
||||
const versionInfo = await getVersion();
|
||||
const VERSION = versionInfo.VERSION;
|
||||
console.log(`[template.html ${VERSION}] Loading...`);
|
||||
|
||||
/* ================================================================
|
||||
GLOBAL VARIABLES
|
||||
================================================================
|
||||
Track state for hamburger menu, relay status, and theme.
|
||||
================================================================ */
|
||||
let updateIntervalId = null;
|
||||
let currentPubkey = null;
|
||||
|
||||
/*
|
||||
AUTH STATE MODEL (Template reference)
|
||||
------------------------------------------------------------------
|
||||
This template now demonstrates three auth modes for standalone pages:
|
||||
|
||||
- required (default):
|
||||
Behaves like existing pages: login is required immediately.
|
||||
|
||||
- optional:
|
||||
Page can render public/read-only data without login, but can still
|
||||
prompt login later for user actions (publish, settings, etc).
|
||||
|
||||
- none:
|
||||
Never auto-login on load (pure public page).
|
||||
|
||||
URL behavior in this template:
|
||||
- If ?auth=required|optional|none is present, it wins.
|
||||
- Otherwise, if URL includes ?npub=... or ?pubkey=..., mode defaults
|
||||
to optional because pages with explicit profile targets are commonly
|
||||
public-readable.
|
||||
- Otherwise, mode defaults to required.
|
||||
*/
|
||||
let isAuthenticated = false;
|
||||
let authMode = 'required';
|
||||
let authedPageInitialized = false;
|
||||
let relayActivityListenersBound = false;
|
||||
|
||||
// Hamburger menu
|
||||
let hamburgerInstance = null;
|
||||
let isNavOpen = false;
|
||||
|
||||
// Version bar buttons
|
||||
let logoutHamburger = null;
|
||||
let themeToggleHamburger = null;
|
||||
let isDarkMode = false;
|
||||
|
||||
// App-wide user settings (NIP-78 kind 30078, d:user-settings)
|
||||
let pageSettings = {};
|
||||
let unsubscribeUserSettings = null;
|
||||
|
||||
/* ================================================================
|
||||
DOM VARIABLES
|
||||
================================================================
|
||||
Cache DOM element references for better performance.
|
||||
================================================================ */
|
||||
const divBody = document.getElementById("divBody");
|
||||
const divSideNav = document.getElementById("divSideNav");
|
||||
const divSideNavBody = document.getElementById("divSideNavBody");
|
||||
const divFooterCenter = document.getElementById("divFooterCenter");
|
||||
const divFooterRight = document.getElementById("divFooterRight");
|
||||
|
||||
/* ================================================================
|
||||
HAMBURGER MENU
|
||||
================================================================
|
||||
Initialize and control the animated hamburger menu.
|
||||
================================================================ */
|
||||
function initHamburgerMenu() {
|
||||
hamburgerInstance = new HamburgerMorphing('#divSvgHam', {
|
||||
foreground: 'var(--primary-color)',
|
||||
background: 'var(--secondary-color)',
|
||||
hover: 'var(--accent-color)'
|
||||
});
|
||||
hamburgerInstance.animateTo('burger');
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
SIDENAV FUNCTIONS
|
||||
================================================================
|
||||
Open/close sidenav with hamburger morphing animation.
|
||||
================================================================ */
|
||||
function openNav() {
|
||||
divSideNav.style.zIndex = 3;
|
||||
divSideNav.style.width = "clamp(400px, 50vw, 600px)";
|
||||
isNavOpen = true;
|
||||
if (hamburgerInstance) {
|
||||
hamburgerInstance.animateTo('arrow_left');
|
||||
}
|
||||
|
||||
|
||||
// Initialize version bar buttons when sidenav opens (lazy load)
|
||||
if (!logoutHamburger) {
|
||||
logoutHamburger = new HamburgerMorphing('#logoutHamburgerContainer', {
|
||||
size: 24,
|
||||
foreground: 'var(--primary-color)',
|
||||
background: 'var(--secondary-color)',
|
||||
hover: 'var(--accent-color)'
|
||||
});
|
||||
logoutHamburger.animateTo('x');
|
||||
}
|
||||
|
||||
if (!themeToggleHamburger) {
|
||||
themeToggleHamburger = new HamburgerMorphing('#themeToggleHamburgerContainer', {
|
||||
size: 24,
|
||||
foreground: 'var(--primary-color)',
|
||||
background: 'var(--secondary-color)',
|
||||
hover: 'var(--accent-color)'
|
||||
});
|
||||
|
||||
// Determine current theme
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
isDarkMode = savedTheme === 'dark' || document.body.classList.contains('dark-mode');
|
||||
const initialShape = isDarkMode ? 'moon' : 'circle';
|
||||
themeToggleHamburger.animateTo(initialShape);
|
||||
}
|
||||
}
|
||||
|
||||
function closeNav() {
|
||||
divSideNav.style.width = "0vw";
|
||||
divSideNav.style.zIndex = -1;
|
||||
isNavOpen = false;
|
||||
if (hamburgerInstance) {
|
||||
hamburgerInstance.animateTo('burger');
|
||||
}
|
||||
}
|
||||
|
||||
function toggleNav() {
|
||||
if (isNavOpen) {
|
||||
closeNav();
|
||||
} else {
|
||||
openNav();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ================================================================
|
||||
AUTH MODE HELPERS
|
||||
================================================================
|
||||
These functions are meant as reusable guidance for future pages.
|
||||
================================================================ */
|
||||
function hasTargetPubkeyInUrl() {
|
||||
const params = new URLSearchParams(window.location.search || '');
|
||||
const npub = String(params.get('npub') || '').trim();
|
||||
const pubkey = String(params.get('pubkey') || '').trim();
|
||||
return Boolean(npub || pubkey);
|
||||
}
|
||||
|
||||
function resolveAuthModeFromUrl() {
|
||||
const params = new URLSearchParams(window.location.search || '');
|
||||
const explicitAuth = String(params.get('auth') || '').trim().toLowerCase();
|
||||
if (explicitAuth === 'required' || explicitAuth === 'optional' || explicitAuth === 'none') {
|
||||
return explicitAuth;
|
||||
}
|
||||
|
||||
// Convention: explicit target profiles are public-readable by default.
|
||||
if (hasTargetPubkeyInUrl()) {
|
||||
return 'optional';
|
||||
}
|
||||
|
||||
return 'required';
|
||||
}
|
||||
|
||||
function isAuthRequiredError(error) {
|
||||
const message = String(error?.message || error || '').toLowerCase();
|
||||
return message.includes('authentication required');
|
||||
}
|
||||
|
||||
async function initializeAuthentication(mode) {
|
||||
// required: existing behavior, throw if auth fails.
|
||||
if (mode === 'required') {
|
||||
await initNDKPage();
|
||||
currentPubkey = await getPubkey();
|
||||
isAuthenticated = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// none: public page, no login attempt on load.
|
||||
if (mode === 'none') {
|
||||
isAuthenticated = false;
|
||||
currentPubkey = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// optional: try silent/normal init; if auth required, continue public.
|
||||
try {
|
||||
await initNDKPage();
|
||||
currentPubkey = await getPubkey();
|
||||
isAuthenticated = true;
|
||||
} catch (error) {
|
||||
if (isAuthRequiredError(error)) {
|
||||
console.log('[template.html] Optional auth mode: continuing unauthenticated');
|
||||
isAuthenticated = false;
|
||||
currentPubkey = null;
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function initializeAuthenticatedPageFeatures() {
|
||||
if (!isAuthenticated || authedPageInitialized) return;
|
||||
|
||||
await injectHeaderAvatar(currentPubkey);
|
||||
console.log('[template.html] Authenticated as:', currentPubkey);
|
||||
|
||||
// Hydrate app-wide user settings for this page
|
||||
try {
|
||||
pageSettings = await getUserSettings();
|
||||
} catch (error) {
|
||||
console.warn('[template.html] getUserSettings failed:', error);
|
||||
pageSettings = {};
|
||||
}
|
||||
|
||||
// Subscribe to live user settings updates (cross-tab + publish echoes)
|
||||
if (!unsubscribeUserSettings) {
|
||||
unsubscribeUserSettings = onUserSettings((settings) => {
|
||||
pageSettings = settings || {};
|
||||
// TODO: Re-render page-specific UI from pageSettings here.
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize relay-dependent UI only once authenticated.
|
||||
initFooterRelayStatus();
|
||||
initSidenavRelaySection();
|
||||
await initBlossomSection();
|
||||
initAiSectionWithLocalConfig();
|
||||
await UpdateFooter();
|
||||
|
||||
if (!updateIntervalId) {
|
||||
updateIntervalId = setInterval(UpdateFooter, 1000);
|
||||
}
|
||||
|
||||
// Relay activity listeners only matter after worker init/auth.
|
||||
if (!relayActivityListenersBound) {
|
||||
window.addEventListener('ndkRelayActivity', (event) => {
|
||||
const { relayUrl, activity, stats } = event.detail;
|
||||
console.log(`[template.html] Relay activity: ${relayUrl} - ${activity}`, stats);
|
||||
setRelayActivityState(relayUrl, activity);
|
||||
});
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data && event.data.type === 'relayActivity') {
|
||||
const { relayUrl, activity } = event.data;
|
||||
console.log(`[template.html] Relay activity: ${relayUrl} - ${activity}`);
|
||||
setRelayActivityState(relayUrl, activity);
|
||||
}
|
||||
});
|
||||
|
||||
relayActivityListenersBound = true;
|
||||
}
|
||||
|
||||
authedPageInitialized = true;
|
||||
}
|
||||
|
||||
async function promptLoginIfNeeded() {
|
||||
if (isAuthenticated) return true;
|
||||
|
||||
await initNDKPage();
|
||||
currentPubkey = await getPubkey();
|
||||
isAuthenticated = true;
|
||||
await initializeAuthenticatedPageFeatures();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
UPDATE FOOTER
|
||||
================================================================
|
||||
Update footer sections with relay status, pubkey, and other info.
|
||||
Called periodically by update loop.
|
||||
================================================================ */
|
||||
const UpdateFooter = async () => {
|
||||
|
||||
try {
|
||||
// Update relay status visuals in footer and sidenav
|
||||
await updateFooterRelayStatus();
|
||||
await updateSidenavRelaySection();
|
||||
|
||||
await updateBlossomSection();
|
||||
// Clear center and right sections
|
||||
divFooterCenter.innerHTML = '';
|
||||
divFooterRight.innerHTML = '';
|
||||
} catch (error) {
|
||||
console.error('[template.html] Error updating footer:', error);
|
||||
}
|
||||
};
|
||||
|
||||
/* ================================================================
|
||||
LOGOUT
|
||||
================================================================
|
||||
Complete logout process:
|
||||
1. Stop update loop
|
||||
2. Disconnect from NDK worker
|
||||
3. Logout from nostr-login-lite
|
||||
4. Clear all storage (localStorage, sessionStorage, IndexedDB)
|
||||
5. Reload page
|
||||
================================================================ */
|
||||
const Logout = async () => {
|
||||
console.log("[template.html] Starting logout process...");
|
||||
|
||||
// Stop the update loop
|
||||
if (updateIntervalId) {
|
||||
clearInterval(updateIntervalId);
|
||||
updateIntervalId = null;
|
||||
}
|
||||
|
||||
// Disconnect from worker
|
||||
disconnect();
|
||||
|
||||
// Logout from nostr-login-lite
|
||||
if (window.NOSTR_LOGIN_LITE && window.NOSTR_LOGIN_LITE.logout) {
|
||||
await window.NOSTR_LOGIN_LITE.logout();
|
||||
}
|
||||
|
||||
// Clear all storage
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
|
||||
// Clear IndexedDB
|
||||
if (window.indexedDB) {
|
||||
const databases = await window.indexedDB.databases();
|
||||
for (const db of databases) {
|
||||
if (db.name) {
|
||||
window.indexedDB.deleteDatabase(db.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("[template.html] Logged out, reloading page");
|
||||
location.reload(true);
|
||||
};
|
||||
|
||||
/* ================================================================
|
||||
EVENT LISTENERS
|
||||
================================================================
|
||||
Wire up UI interactions.
|
||||
Main hamburger button click handler is set up in main() after initialization.
|
||||
================================================================ */
|
||||
|
||||
/* ================================================================
|
||||
SUBSCRIPTION EXAMPLE
|
||||
================================================================
|
||||
Example of how to subscribe to Nostr events:
|
||||
|
||||
const sub = subscribe(
|
||||
{ kinds: [1], authors: [pubkey], limit: 10 },
|
||||
{ closeOnEose: false, cacheUsage: 'CACHE_FIRST' }
|
||||
);
|
||||
|
||||
Cache usage options:
|
||||
- 'CACHE_FIRST' - Check cache first, then relays
|
||||
- 'ONLY_RELAY' - Only query relays
|
||||
- 'ONLY_CACHE' - Only query cache
|
||||
- 'PARALLEL' - Query cache and relays simultaneously
|
||||
|
||||
Listen for events via window events:
|
||||
window.addEventListener('ndkEvent', (event) => {
|
||||
const evt = event.detail;
|
||||
console.log('Received event:', evt);
|
||||
});
|
||||
================================================================ */
|
||||
|
||||
/* ================================================================
|
||||
PUBLISH EXAMPLE
|
||||
================================================================
|
||||
Example of how to publish a Nostr event:
|
||||
|
||||
const event = {
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
kind: 1,
|
||||
tags: [],
|
||||
content: "Hello, Nostr!"
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await publishEvent(event);
|
||||
console.log("✅ Published to:", result.relayResults.successful);
|
||||
console.log("❌ Failed:", result.relayResults.failed);
|
||||
console.log("Total relays:", result.totalRelays);
|
||||
} catch (error) {
|
||||
console.error("Publish error:", error);
|
||||
}
|
||||
|
||||
Note: Events are automatically signed by the NDK worker using
|
||||
the message-based signer (which calls window.nostr.signEvent).
|
||||
================================================================ */
|
||||
|
||||
/* ================================================================
|
||||
USER SETTINGS EXAMPLE (NIP-78)
|
||||
================================================================
|
||||
Read/subscribe/write helper pattern for all pages:
|
||||
|
||||
// Read latest merged settings (cache + relay hydrated by worker)
|
||||
const settings = await getUserSettings();
|
||||
|
||||
// Subscribe to cross-tab updates
|
||||
const unsubscribe = onUserSettings((nextSettings) => {
|
||||
// Re-render page from nextSettings
|
||||
});
|
||||
|
||||
// Patch only your feature namespace
|
||||
await patchUserSettings({
|
||||
myFeature: {
|
||||
someFlag: true
|
||||
}
|
||||
});
|
||||
|
||||
// On page teardown (if applicable)
|
||||
// unsubscribe();
|
||||
================================================================ */
|
||||
|
||||
/* ================================================================
|
||||
INITIALIZATION
|
||||
================================================================
|
||||
Main initialization sequence:
|
||||
1. Initialize hamburger menu
|
||||
2. Set up hamburger click handler
|
||||
3. Resolve auth mode from URL/query policy
|
||||
4. Initialize authentication based on mode
|
||||
5. Initialize authenticated-only features (if signed in)
|
||||
6. Set up version bar button listeners
|
||||
7. Restore sidenav state
|
||||
8. Update version display
|
||||
|
||||
Notes:
|
||||
- required mode = existing behavior (prompt login on load)
|
||||
- optional mode = allow public load, login later on demand
|
||||
- none mode = no auto-login on load
|
||||
================================================================ */
|
||||
(async function main() {
|
||||
console.log("[template.html] Starting initialization...");
|
||||
|
||||
try {
|
||||
// Initialize hamburger menu first
|
||||
initHamburgerMenu();
|
||||
|
||||
// Add click handler to hamburger
|
||||
const divSvgHam = document.getElementById('divSvgHam');
|
||||
if (divSvgHam) {
|
||||
divSvgHam.addEventListener('click', toggleNav);
|
||||
}
|
||||
|
||||
// Initialize version bar buttons
|
||||
const themeToggleButton = document.getElementById('themeToggleButton');
|
||||
const logoutButton = document.getElementById('logoutButton');
|
||||
|
||||
if (themeToggleButton) {
|
||||
themeToggleButton.addEventListener('click', () => {
|
||||
isDarkMode = !isDarkMode;
|
||||
if (isDarkMode) {
|
||||
localStorage.setItem('theme', 'dark');
|
||||
} else {
|
||||
localStorage.setItem('theme', 'light');
|
||||
}
|
||||
// Save sidenav state before reload
|
||||
localStorage.setItem('sidenavWasOpen', isNavOpen ? 'true' : 'false');
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
if (logoutButton) {
|
||||
logoutButton.addEventListener('click', async () => {
|
||||
try {
|
||||
// In optional/none modes this doubles as a "Sign in" entry point.
|
||||
if (!isAuthenticated) {
|
||||
await promptLoginIfNeeded();
|
||||
return;
|
||||
}
|
||||
await Logout();
|
||||
} catch (error) {
|
||||
console.error('Logout/login action failed:', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Resolve and initialize page auth policy.
|
||||
authMode = resolveAuthModeFromUrl();
|
||||
console.log('[template.html] Resolved auth mode:', authMode);
|
||||
await initializeAuthentication(authMode);
|
||||
|
||||
// Initialize authenticated features only when signed in.
|
||||
await initializeAuthenticatedPageFeatures();
|
||||
|
||||
/* ============================================================
|
||||
EXAMPLE: Subscribe to events
|
||||
============================================================
|
||||
Uncomment to subscribe to user's notes:
|
||||
|
||||
const notesSub = subscribe(
|
||||
{ kinds: [1], authors: [currentPubkey], limit: 10 },
|
||||
{ closeOnEose: false, cacheUsage: 'CACHE_FIRST' }
|
||||
);
|
||||
console.log("[template.html] Subscribed to kind 1");
|
||||
============================================================ */
|
||||
|
||||
/* ============================================================
|
||||
EXAMPLE: Listen for events from worker
|
||||
============================================================
|
||||
Uncomment to handle incoming events:
|
||||
|
||||
window.addEventListener('ndkEvent', (event) => {
|
||||
const evt = event.detail;
|
||||
console.log("[template.html] Received event:", evt.kind, evt.pubkey);
|
||||
|
||||
if (evt.pubkey === currentPubkey) {
|
||||
if (evt.kind === 1) {
|
||||
// Handle note event
|
||||
console.log("Note:", evt.content);
|
||||
}
|
||||
}
|
||||
});
|
||||
============================================================ */
|
||||
|
||||
/* ============================================================
|
||||
EXAMPLE: Listen for cached profile
|
||||
============================================================
|
||||
Uncomment to handle cached profile data:
|
||||
|
||||
window.addEventListener('ndkProfile', (event) => {
|
||||
console.log("[template.html] Cached profile:", event.detail);
|
||||
// event.detail contains profile object (name, about, etc.)
|
||||
});
|
||||
============================================================ */
|
||||
|
||||
// Restore sidenav state if it was open before theme toggle
|
||||
const sidenavWasOpen = localStorage.getItem('sidenavWasOpen');
|
||||
if (sidenavWasOpen === 'true') {
|
||||
localStorage.removeItem('sidenavWasOpen');
|
||||
openNav();
|
||||
}
|
||||
|
||||
// Optional UX note for public mode pages.
|
||||
if (!isAuthenticated && (authMode === 'optional' || authMode === 'none')) {
|
||||
divFooterCenter.textContent = 'Public mode';
|
||||
divFooterRight.textContent = 'Sign in from side menu for private features';
|
||||
}
|
||||
|
||||
// Update version display
|
||||
await updateVersionDisplay();
|
||||
|
||||
console.log('[template.html] Initialization complete');
|
||||
} catch (error) {
|
||||
console.error('[template.html] Initialization failed:', error);
|
||||
divBody.innerHTML = `<div style="text-align: center; padding: 50px;">
|
||||
<div style="font-size: 24px; margin-bottom: 20px; color: red;">❌ Authentication Error</div>
|
||||
<div style="font-size: 16px; color: #666;">${error.message}</div>
|
||||
<div style="margin-top: 20px;">
|
||||
<button onclick="location.reload()" style="padding: 10px 20px; font-size: 16px;">Retry</button>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
})();
|
||||
|
||||
/* ================================================================
|
||||
WORKER MESSAGE TYPES
|
||||
================================================================
|
||||
The NDK worker can send these message types:
|
||||
|
||||
1. 'response' - Response to init/subscribe/publish requests
|
||||
- data.profile - User profile (from init)
|
||||
- data.relays - User relays (from init)
|
||||
- data.success - Publish success status
|
||||
- data.relayResults - Relay publish results
|
||||
|
||||
2. 'event' - Nostr event from subscription
|
||||
- Dispatched as 'ndkEvent' window event
|
||||
- event.detail contains the Nostr event
|
||||
|
||||
3. 'eose' - End of stored events for subscription
|
||||
- Dispatched as 'ndkEose' window event
|
||||
- event.detail.subId contains subscription ID
|
||||
|
||||
4. 'signRequest' - Request to sign event/encrypt/decrypt
|
||||
- Handled automatically by init-ndk.mjs
|
||||
- Calls window.nostr methods and sends response
|
||||
|
||||
5. 'error' - Error from worker
|
||||
- Logged to console automatically
|
||||
|
||||
6. 'relayActivity' - Relay read/write activity notification
|
||||
- Dispatched as 'ndkRelayActivity' window event
|
||||
- Used to animate relay status icons in footer
|
||||
================================================================ */
|
||||
|
||||
/* ================================================================
|
||||
DISTRIBUTED ARCHITECTURE NOTES
|
||||
================================================================
|
||||
Each page is independently accessible and self-contained:
|
||||
|
||||
1. Authentication persists via nostr-login-lite localStorage
|
||||
- Login once on any page
|
||||
- All other pages automatically authenticated
|
||||
|
||||
2. NDK SharedWorker is shared across all tabs/pages
|
||||
- Single NDK instance manages all connections
|
||||
- Subscriptions from all pages handled by one worker
|
||||
- Events broadcast to all connected pages
|
||||
|
||||
3. Dexie cache is shared across all pages
|
||||
- IndexedDB persists across sessions
|
||||
- Cache-first queries are fast
|
||||
- Reduces relay load
|
||||
|
||||
4. User settings are centralized and shared
|
||||
- Worker hydrates kind 30078 (`d:user-settings`) on init
|
||||
- Pages read via getUserSettings()
|
||||
- Pages patch via patchUserSettings({ featureNamespace: ... })
|
||||
- Pages subscribe via onUserSettings() for live updates
|
||||
|
||||
5. Each page can be distributed independently
|
||||
- Copy template.html and customize
|
||||
- No dependencies on other pages
|
||||
- Works standalone or as part of suite
|
||||
|
||||
6. Message-based signer bridges worker and page
|
||||
- Worker's NDK uses MessageBasedSigner
|
||||
- Signer sends sign requests to page
|
||||
- Page calls window.nostr.signEvent()
|
||||
- Response sent back to worker
|
||||
- NDK completes signing and publishing
|
||||
|
||||
7. Relay status visualization
|
||||
- Footer left section shows connected relays
|
||||
- Each relay has animated icon (HamburgerMorphing)
|
||||
- Icons morph based on activity (read/write)
|
||||
- Temporary animations show real-time activity
|
||||
================================================================ */
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,463 @@
|
||||
/**
|
||||
* ASCIIBarChart - A dynamic ASCII-based vertical bar chart renderer
|
||||
*
|
||||
* Creates real-time animated bar charts using monospaced characters (X)
|
||||
* with automatic scaling, labels, and responsive font sizing.
|
||||
*/
|
||||
class ASCIIBarChart {
|
||||
/**
|
||||
* Create a new ASCII bar chart
|
||||
* @param {string} containerId - The ID of the HTML element to render the chart in
|
||||
* @param {Object} options - Configuration options
|
||||
* @param {number} [options.maxHeight=20] - Maximum height of the chart in rows
|
||||
* @param {number} [options.maxDataPoints=30] - Maximum number of data columns before scrolling
|
||||
* @param {string} [options.title=''] - Chart title (displayed centered at top)
|
||||
* @param {string} [options.xAxisLabel=''] - X-axis label (displayed centered at bottom)
|
||||
* @param {string} [options.yAxisLabel=''] - Y-axis label (displayed vertically on left)
|
||||
* @param {boolean} [options.autoFitWidth=true] - Automatically adjust font size to fit container width
|
||||
* @param {boolean} [options.useBinMode=false] - Enable time bin mode for data aggregation
|
||||
* @param {number} [options.binDuration=10000] - Duration of each time bin in milliseconds (10 seconds default)
|
||||
* @param {string} [options.xAxisLabelFormat='elapsed'] - X-axis label format: 'elapsed', 'bins', 'timestamps', 'ranges'
|
||||
* @param {boolean} [options.debug=false] - Enable debug logging
|
||||
*/
|
||||
constructor(containerId, options = {}) {
|
||||
this.container = document.getElementById(containerId);
|
||||
this.data = [];
|
||||
this.maxHeight = options.maxHeight || 20;
|
||||
this.maxDataPoints = options.maxDataPoints || 30;
|
||||
this.totalDataPoints = 0; // Track total number of data points added
|
||||
this.title = options.title || '';
|
||||
this.xAxisLabel = options.xAxisLabel || '';
|
||||
this.yAxisLabel = options.yAxisLabel || '';
|
||||
this.autoFitWidth = options.autoFitWidth !== false; // Default to true
|
||||
this.debug = options.debug || false; // Debug logging option
|
||||
|
||||
// Time bin configuration
|
||||
this.useBinMode = options.useBinMode !== false; // Default to true
|
||||
this.binDuration = options.binDuration || 4000; // 4 seconds default
|
||||
this.xAxisLabelFormat = options.xAxisLabelFormat || 'elapsed';
|
||||
|
||||
// Time bin data structures
|
||||
this.bins = [];
|
||||
this.currentBinIndex = -1;
|
||||
this.binStartTime = null;
|
||||
this.binCheckInterval = null;
|
||||
this.chartStartTime = Date.now();
|
||||
|
||||
// Set up resize observer if auto-fit is enabled
|
||||
if (this.autoFitWidth) {
|
||||
this.resizeObserver = new ResizeObserver(() => {
|
||||
this.adjustFontSize();
|
||||
});
|
||||
this.resizeObserver.observe(this.container);
|
||||
}
|
||||
|
||||
// Initialize first bin if bin mode is enabled
|
||||
if (this.useBinMode) {
|
||||
this.initializeBins();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new data point to the chart
|
||||
* @param {number} value - The numeric value to add
|
||||
*/
|
||||
addValue(value) {
|
||||
// Time bin mode: add value to current active bin count
|
||||
this.checkBinRotation(); // Ensure we have an active bin
|
||||
this.bins[this.currentBinIndex].count += value; // Changed from ++ to += value
|
||||
this.totalDataPoints++;
|
||||
|
||||
this.render();
|
||||
this.updateInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all data from the chart
|
||||
*/
|
||||
clear() {
|
||||
this.data = [];
|
||||
this.totalDataPoints = 0;
|
||||
|
||||
if (this.useBinMode) {
|
||||
this.bins = [];
|
||||
this.currentBinIndex = -1;
|
||||
this.binStartTime = null;
|
||||
this.initializeBins();
|
||||
}
|
||||
|
||||
this.render();
|
||||
this.updateInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the width of the chart in characters
|
||||
* @returns {number} The chart width in characters
|
||||
* @private
|
||||
*/
|
||||
getChartWidth() {
|
||||
let dataLength = this.maxDataPoints; // Always use maxDataPoints for consistent width
|
||||
|
||||
if (dataLength === 0) return 50; // Default width for empty chart
|
||||
|
||||
const yAxisPadding = this.yAxisLabel ? 2 : 0;
|
||||
const yAxisNumbers = 3; // Width of Y-axis numbers
|
||||
const separator = 1; // The '|' character
|
||||
// const dataWidth = dataLength * 2; // Each column is 2 characters wide // TEMP: commented for no-space test
|
||||
const dataWidth = dataLength; // Each column is 1 character wide // TEMP: adjusted for no-space columns
|
||||
const padding = 1; // Extra padding
|
||||
|
||||
const totalWidth = yAxisPadding + yAxisNumbers + separator + dataWidth + padding;
|
||||
|
||||
// Only log when width changes
|
||||
if (this.debug && this.lastChartWidth !== totalWidth) {
|
||||
console.log('getChartWidth changed:', { dataLength, totalWidth, previous: this.lastChartWidth });
|
||||
this.lastChartWidth = totalWidth;
|
||||
}
|
||||
|
||||
return totalWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust font size to fit container width
|
||||
* @private
|
||||
*/
|
||||
adjustFontSize() {
|
||||
if (!this.autoFitWidth) return;
|
||||
|
||||
const containerWidth = this.container.clientWidth;
|
||||
const chartWidth = this.getChartWidth();
|
||||
|
||||
if (chartWidth === 0) return;
|
||||
|
||||
// Calculate optimal font size
|
||||
// For monospace fonts, character width is approximately 0.6 * font size
|
||||
// Use a slightly smaller ratio to fit more content
|
||||
const charWidthRatio = 0.7;
|
||||
const padding = 30; // Reduce padding to fit more content
|
||||
const availableWidth = containerWidth - padding;
|
||||
const optimalFontSize = Math.floor((availableWidth / chartWidth) / charWidthRatio);
|
||||
|
||||
// Set reasonable bounds (min 4px, max 20px)
|
||||
const fontSize = Math.max(4, Math.min(20, optimalFontSize));
|
||||
|
||||
// Only log when font size changes
|
||||
if (this.debug && this.lastFontSize !== fontSize) {
|
||||
console.log('fontSize changed:', { containerWidth, chartWidth, fontSize, previous: this.lastFontSize });
|
||||
this.lastFontSize = fontSize;
|
||||
}
|
||||
|
||||
this.container.style.fontSize = fontSize + 'px';
|
||||
this.container.style.lineHeight = '1.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the chart to the container
|
||||
* @private
|
||||
*/
|
||||
render() {
|
||||
let dataToRender = [];
|
||||
let maxValue = 0;
|
||||
let minValue = 0;
|
||||
let valueRange = 0;
|
||||
|
||||
if (this.useBinMode) {
|
||||
// Bin mode: render bin counts
|
||||
if (this.bins.length === 0) {
|
||||
this.container.textContent = 'No data yet. Click Start to begin.';
|
||||
return;
|
||||
}
|
||||
// Always create a fixed-length array filled with 0s, then overlay actual bin data
|
||||
dataToRender = new Array(this.maxDataPoints).fill(0);
|
||||
|
||||
// Overlay actual bin data (most recent bins, reversed for left-to-right display)
|
||||
const startIndex = Math.max(0, this.bins.length - this.maxDataPoints);
|
||||
const recentBins = this.bins.slice(startIndex);
|
||||
|
||||
// Reverse the bins so most recent is on the left, and overlay onto the fixed array
|
||||
recentBins.reverse().forEach((bin, index) => {
|
||||
if (index < this.maxDataPoints) {
|
||||
dataToRender[index] = bin.count;
|
||||
}
|
||||
});
|
||||
|
||||
if (this.debug) {
|
||||
console.log('render() dataToRender:', dataToRender, 'bins length:', this.bins.length);
|
||||
}
|
||||
maxValue = Math.max(...dataToRender);
|
||||
minValue = Math.min(...dataToRender);
|
||||
valueRange = maxValue - minValue;
|
||||
} else {
|
||||
// Legacy mode: render individual values
|
||||
if (this.data.length === 0) {
|
||||
this.container.textContent = 'No data yet. Click Start to begin.';
|
||||
return;
|
||||
}
|
||||
dataToRender = this.data;
|
||||
maxValue = Math.max(...this.data);
|
||||
minValue = Math.min(...this.data);
|
||||
valueRange = maxValue - minValue;
|
||||
}
|
||||
|
||||
let output = '';
|
||||
const scale = this.maxHeight;
|
||||
|
||||
// Calculate scaling factor: each X represents at least 1 count
|
||||
const maxCount = Math.max(...dataToRender);
|
||||
const scaleFactor = Math.max(1, Math.ceil(maxCount / scale)); // 1 X = scaleFactor counts
|
||||
const scaledMax = Math.ceil(maxCount / scaleFactor) * scaleFactor;
|
||||
|
||||
// Calculate Y-axis label width (for vertical text)
|
||||
const yLabelWidth = this.yAxisLabel ? 2 : 0;
|
||||
const yAxisPadding = this.yAxisLabel ? ' ' : '';
|
||||
|
||||
// Add title if provided (centered)
|
||||
if (this.title) {
|
||||
// const chartWidth = 4 + this.maxDataPoints * 2; // Y-axis numbers + data columns // TEMP: commented for no-space test
|
||||
const chartWidth = 4 + this.maxDataPoints; // Y-axis numbers + data columns // TEMP: adjusted for no-space columns
|
||||
const titlePadding = Math.floor((chartWidth - this.title.length) / 2);
|
||||
output += yAxisPadding + ' '.repeat(Math.max(0, titlePadding)) + this.title + '\n\n';
|
||||
}
|
||||
|
||||
// Draw from top to bottom
|
||||
for (let row = scale; row > 0; row--) {
|
||||
let line = '';
|
||||
|
||||
// Add vertical Y-axis label character
|
||||
if (this.yAxisLabel) {
|
||||
const L = this.yAxisLabel.length;
|
||||
const startRow = Math.floor((scale - L) / 2) + 1;
|
||||
const relativeRow = scale - row + 1; // 1 at top, scale at bottom
|
||||
if (relativeRow >= startRow && relativeRow < startRow + L) {
|
||||
const labelIndex = relativeRow - startRow;
|
||||
line += this.yAxisLabel[labelIndex] + ' ';
|
||||
} else {
|
||||
line += ' ';
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the actual count value this row represents (1 at bottom, increasing upward)
|
||||
const rowCount = (row - 1) * scaleFactor + 1;
|
||||
|
||||
// Add Y-axis label (show actual count values)
|
||||
line += String(rowCount).padStart(3, ' ') + ' |';
|
||||
|
||||
// Draw each column
|
||||
for (let i = 0; i < dataToRender.length; i++) {
|
||||
const count = dataToRender[i];
|
||||
const scaledHeight = Math.ceil(count / scaleFactor);
|
||||
|
||||
if (scaledHeight >= row) {
|
||||
// line += ' X'; // TEMP: commented out space between columns
|
||||
line += 'X'; // TEMP: no space between columns
|
||||
} else {
|
||||
// line += ' '; // TEMP: commented out space between columns
|
||||
line += ' '; // TEMP: single space for empty columns
|
||||
}
|
||||
}
|
||||
|
||||
output += line + '\n';
|
||||
}
|
||||
|
||||
// Draw X-axis
|
||||
// output += yAxisPadding + ' +' + '-'.repeat(this.maxDataPoints * 2) + '\n'; // TEMP: commented out for no-space test
|
||||
output += yAxisPadding + ' +' + '-'.repeat(this.maxDataPoints) + '\n'; // TEMP: back to original length
|
||||
|
||||
// Draw X-axis labels based on mode and format
|
||||
let xAxisLabels = yAxisPadding + ' '; // Initial padding to align with X-axis
|
||||
|
||||
// Determine label interval (every 5 columns)
|
||||
const labelInterval = 5;
|
||||
|
||||
// Generate all labels first and store in array
|
||||
let labels = [];
|
||||
for (let i = 0; i < this.maxDataPoints; i++) {
|
||||
if (i % labelInterval === 0) {
|
||||
let label = '';
|
||||
if (this.useBinMode) {
|
||||
// For bin mode, show labels for all possible positions
|
||||
// i=0 is leftmost (most recent), i=maxDataPoints-1 is rightmost (oldest)
|
||||
const elapsedSec = (i * this.binDuration) / 1000;
|
||||
// Format with appropriate precision for sub-second bins
|
||||
if (this.binDuration < 1000) {
|
||||
// Show decimal seconds for sub-second bins
|
||||
label = elapsedSec.toFixed(1) + 's';
|
||||
} else {
|
||||
// Show whole seconds for 1+ second bins
|
||||
label = String(Math.round(elapsedSec)) + 's';
|
||||
}
|
||||
} else {
|
||||
// For legacy mode, show data point numbers
|
||||
const startIndex = Math.max(1, this.totalDataPoints - this.maxDataPoints + 1);
|
||||
label = String(startIndex + i);
|
||||
}
|
||||
labels.push(label);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the label string with calculated spacing
|
||||
for (let i = 0; i < labels.length; i++) {
|
||||
const label = labels[i];
|
||||
xAxisLabels += label;
|
||||
|
||||
// Add spacing: labelInterval - label.length (except for last label)
|
||||
if (i < labels.length - 1) {
|
||||
const spacing = labelInterval - label.length;
|
||||
xAxisLabels += ' '.repeat(spacing);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the label line extends to match the X-axis dash line length
|
||||
// The dash line is this.maxDataPoints characters long, starting after " +"
|
||||
const dashLineLength = this.maxDataPoints;
|
||||
const minLabelLineLength = yAxisPadding.length + 4 + dashLineLength; // 4 for " "
|
||||
if (xAxisLabels.length < minLabelLineLength) {
|
||||
xAxisLabels += ' '.repeat(minLabelLineLength - xAxisLabels.length);
|
||||
}
|
||||
output += xAxisLabels + '\n';
|
||||
|
||||
// Add X-axis label if provided
|
||||
if (this.xAxisLabel) {
|
||||
// const labelPadding = Math.floor((this.maxDataPoints * 2 - this.xAxisLabel.length) / 2); // TEMP: commented for no-space test
|
||||
const labelPadding = Math.floor((this.maxDataPoints - this.xAxisLabel.length) / 2); // TEMP: adjusted for no-space columns
|
||||
output += '\n' + yAxisPadding + ' ' + ' '.repeat(Math.max(0, labelPadding)) + this.xAxisLabel + '\n';
|
||||
}
|
||||
|
||||
this.container.textContent = output;
|
||||
|
||||
// Adjust font size to fit width (only once at initialization)
|
||||
if (this.autoFitWidth) {
|
||||
this.adjustFontSize();
|
||||
}
|
||||
|
||||
// Update the external info display
|
||||
if (this.useBinMode) {
|
||||
const binCounts = this.bins.map(bin => bin.count);
|
||||
const scaleFactor = Math.max(1, Math.ceil(maxValue / scale));
|
||||
document.getElementById('values').textContent = `[${dataToRender.join(', ')}]`;
|
||||
document.getElementById('max-value').textContent = maxValue;
|
||||
document.getElementById('scale').textContent = `Min: ${minValue}, Max: ${maxValue}, 1X=${scaleFactor} counts`;
|
||||
} else {
|
||||
document.getElementById('values').textContent = `[${this.data.join(', ')}]`;
|
||||
document.getElementById('max-value').textContent = maxValue;
|
||||
document.getElementById('scale').textContent = `Min: ${minValue}, Max: ${maxValue}, Height: ${scale}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the info display
|
||||
* @private
|
||||
*/
|
||||
updateInfo() {
|
||||
if (this.useBinMode) {
|
||||
const totalCount = this.bins.reduce((sum, bin) => sum + bin.count, 0);
|
||||
document.getElementById('count').textContent = totalCount;
|
||||
} else {
|
||||
document.getElementById('count').textContent = this.data.length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the bin system
|
||||
* @private
|
||||
*/
|
||||
initializeBins() {
|
||||
this.bins = [];
|
||||
this.currentBinIndex = -1;
|
||||
this.binStartTime = null;
|
||||
this.chartStartTime = Date.now();
|
||||
|
||||
// Create first bin
|
||||
this.rotateBin();
|
||||
|
||||
// Set up automatic bin rotation check
|
||||
this.binCheckInterval = setInterval(() => {
|
||||
this.checkBinRotation();
|
||||
}, 100); // Check every 100ms for responsiveness
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current bin should rotate and create new bin if needed
|
||||
* @private
|
||||
*/
|
||||
checkBinRotation() {
|
||||
if (!this.useBinMode || !this.binStartTime) return;
|
||||
|
||||
const now = Date.now();
|
||||
if ((now - this.binStartTime) >= this.binDuration) {
|
||||
this.rotateBin();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate to a new bin, finalizing the current one
|
||||
*/
|
||||
rotateBin() {
|
||||
// Finalize current bin if it exists
|
||||
if (this.currentBinIndex >= 0) {
|
||||
this.bins[this.currentBinIndex].isActive = false;
|
||||
}
|
||||
|
||||
// Create new bin
|
||||
const newBin = {
|
||||
startTime: Date.now(),
|
||||
count: 0,
|
||||
isActive: true
|
||||
};
|
||||
|
||||
this.bins.push(newBin);
|
||||
this.currentBinIndex = this.bins.length - 1;
|
||||
this.binStartTime = newBin.startTime;
|
||||
|
||||
// Keep only the most recent bins
|
||||
if (this.bins.length > this.maxDataPoints) {
|
||||
this.bins.shift();
|
||||
this.currentBinIndex--;
|
||||
}
|
||||
|
||||
// Ensure currentBinIndex points to the last bin (the active one)
|
||||
this.currentBinIndex = this.bins.length - 1;
|
||||
|
||||
// Force a render to update the display immediately
|
||||
this.render();
|
||||
this.updateInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format X-axis label for a bin based on the configured format
|
||||
* @param {number} binIndex - Index of the bin
|
||||
* @returns {string} Formatted label
|
||||
* @private
|
||||
*/
|
||||
formatBinLabel(binIndex) {
|
||||
const bin = this.bins[binIndex];
|
||||
if (!bin) return ' ';
|
||||
|
||||
switch (this.xAxisLabelFormat) {
|
||||
case 'bins':
|
||||
return String(binIndex + 1).padStart(2, ' ');
|
||||
|
||||
case 'timestamps':
|
||||
const time = new Date(bin.startTime);
|
||||
return time.toLocaleTimeString('en-US', {
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
}).replace(/:/g, '');
|
||||
|
||||
case 'ranges':
|
||||
const startSec = Math.floor((bin.startTime - this.chartStartTime) / 1000);
|
||||
const endSec = startSec + Math.floor(this.binDuration / 1000);
|
||||
return `${startSec}-${endSec}`;
|
||||
|
||||
case 'elapsed':
|
||||
default:
|
||||
// For elapsed time, always show time relative to the first bin (index 0)
|
||||
// This keeps the leftmost label as 0s and increases to the right
|
||||
const firstBinTime = this.bins[0] ? this.bins[0].startTime : this.chartStartTime;
|
||||
const elapsedSec = Math.floor((bin.startTime - firstBinTime) / 1000);
|
||||
return String(elapsedSec).padStart(2, ' ') + 's';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,616 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
||||
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
||||
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# Global variables
|
||||
COMMIT_MESSAGE=""
|
||||
RELEASE_MODE=false
|
||||
|
||||
show_usage() {
|
||||
echo "C-Relay Build and Push Script"
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " $0 \"commit message\" - Default: compile, increment patch, commit & push"
|
||||
echo " $0 -r \"commit message\" - Release: compile x86+arm64, increment minor, create release"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 \"Fixed event validation bug\""
|
||||
echo " $0 --release \"Major release with new features\""
|
||||
echo ""
|
||||
echo "Default Mode (patch increment):"
|
||||
echo " - Compile C-Relay"
|
||||
echo " - Increment patch version (v1.2.3 → v1.2.4)"
|
||||
echo " - Git add, commit with message, and push"
|
||||
echo ""
|
||||
echo "Release Mode (-r flag):"
|
||||
echo " - Compile C-Relay for x86_64 and arm64 (dynamic and static versions)"
|
||||
echo " - Increment minor version, zero patch (v1.2.3 → v1.3.0)"
|
||||
echo " - Git add, commit, push, and create Gitea release"
|
||||
echo ""
|
||||
echo "Requirements for Release Mode:"
|
||||
echo " - For ARM64 builds: make install-arm64-deps (optional - will build x86_64 only if missing)"
|
||||
echo " - For static builds: sudo apt-get install musl-dev libcap-dev libuv1-dev libev-dev"
|
||||
echo " - Gitea token in ~/.gitea_token for release uploads"
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-r|--release)
|
||||
RELEASE_MODE=true
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
show_usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
# First non-flag argument is the commit message
|
||||
if [[ -z "$COMMIT_MESSAGE" ]]; then
|
||||
COMMIT_MESSAGE="$1"
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate inputs
|
||||
if [[ -z "$COMMIT_MESSAGE" ]]; then
|
||||
print_error "Commit message is required"
|
||||
echo ""
|
||||
show_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if we're in a git repository
|
||||
check_git_repo() {
|
||||
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
print_error "Not in a git repository"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to get current version and increment appropriately
|
||||
increment_version() {
|
||||
local increment_type="$1" # "patch" or "minor"
|
||||
|
||||
print_status "Getting current version..."
|
||||
|
||||
# Get the highest version tag (not chronologically latest)
|
||||
LATEST_TAG=$(git tag -l 'v*.*.*' | sort -V | tail -n 1 || echo "")
|
||||
if [[ -z "$LATEST_TAG" ]]; then
|
||||
LATEST_TAG="v0.0.0"
|
||||
print_warning "No version tags found, starting from $LATEST_TAG"
|
||||
fi
|
||||
|
||||
# Extract version components (remove 'v' prefix)
|
||||
VERSION=${LATEST_TAG#v}
|
||||
|
||||
# Parse major.minor.patch using regex
|
||||
if [[ $VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
||||
MAJOR=${BASH_REMATCH[1]}
|
||||
MINOR=${BASH_REMATCH[2]}
|
||||
PATCH=${BASH_REMATCH[3]}
|
||||
else
|
||||
print_error "Invalid version format in tag: $LATEST_TAG"
|
||||
print_error "Expected format: v0.1.0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Increment version based on type
|
||||
if [[ "$increment_type" == "minor" ]]; then
|
||||
# Minor release: increment minor, zero patch
|
||||
NEW_MINOR=$((MINOR + 1))
|
||||
NEW_PATCH=0
|
||||
NEW_VERSION="v${MAJOR}.${NEW_MINOR}.${NEW_PATCH}"
|
||||
print_status "Release mode: incrementing minor version"
|
||||
else
|
||||
# Default: increment patch
|
||||
NEW_PATCH=$((PATCH + 1))
|
||||
NEW_VERSION="v${MAJOR}.${MINOR}.${NEW_PATCH}"
|
||||
print_status "Default mode: incrementing patch version"
|
||||
fi
|
||||
|
||||
print_status "Current version: $LATEST_TAG"
|
||||
print_status "New version: $NEW_VERSION"
|
||||
|
||||
# Export for use in other functions
|
||||
export NEW_VERSION
|
||||
}
|
||||
|
||||
# Function to compile the C-Relay project
|
||||
compile_project() {
|
||||
print_status "Compiling C-Relay..."
|
||||
|
||||
# Clean previous build
|
||||
if make clean > /dev/null 2>&1; then
|
||||
print_success "Cleaned previous build"
|
||||
else
|
||||
print_warning "Clean failed or no Makefile found"
|
||||
fi
|
||||
|
||||
# Force regenerate main.h to pick up new tags
|
||||
if make force-version > /dev/null 2>&1; then
|
||||
print_success "Regenerated main.h"
|
||||
else
|
||||
print_warning "Failed to regenerate main.h"
|
||||
fi
|
||||
|
||||
# Compile the project
|
||||
if make > /dev/null 2>&1; then
|
||||
print_success "C-Relay compiled successfully"
|
||||
else
|
||||
print_error "Compilation failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to build release binaries
|
||||
build_release_binaries() {
|
||||
print_status "Building release binaries..."
|
||||
|
||||
# Build x86_64 version
|
||||
print_status "Building x86_64 version..."
|
||||
make clean > /dev/null 2>&1
|
||||
if make x86 > /dev/null 2>&1; then
|
||||
if [[ -f "build/c_relay_x86" ]]; then
|
||||
cp build/c_relay_x86 c-relay-x86_64
|
||||
print_success "x86_64 binary created: c-relay-x86_64"
|
||||
else
|
||||
print_error "x86_64 binary not found after compilation"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
print_error "x86_64 build failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Try to build ARM64 version
|
||||
print_status "Attempting ARM64 build..."
|
||||
make clean > /dev/null 2>&1
|
||||
if make arm64 > /dev/null 2>&1; then
|
||||
if [[ -f "build/c_relay_arm64" ]]; then
|
||||
cp build/c_relay_arm64 c-relay-arm64
|
||||
print_success "ARM64 binary created: c-relay-arm64"
|
||||
else
|
||||
print_warning "ARM64 binary not found after compilation"
|
||||
fi
|
||||
else
|
||||
print_warning "ARM64 build failed - ARM64 cross-compilation not properly set up"
|
||||
print_status "Only x86_64 binary will be included in release"
|
||||
fi
|
||||
|
||||
# Build static x86_64 version
|
||||
print_status "Building static x86_64 version..."
|
||||
make clean > /dev/null 2>&1
|
||||
if make static-musl-x86_64 > /dev/null 2>&1; then
|
||||
if [[ -f "build/c_relay_static_musl_x86_64" ]]; then
|
||||
cp build/c_relay_static_musl_x86_64 c-relay-static-x86_64
|
||||
print_success "Static x86_64 binary created: c-relay-static-x86_64"
|
||||
else
|
||||
print_warning "Static x86_64 binary not found after compilation"
|
||||
fi
|
||||
else
|
||||
print_warning "Static x86_64 build failed - MUSL development packages may not be installed"
|
||||
print_status "Run 'sudo apt-get install musl-dev libcap-dev libuv1-dev libev-dev' to enable static builds"
|
||||
fi
|
||||
|
||||
# Try to build static ARM64 version
|
||||
print_status "Attempting static ARM64 build..."
|
||||
make clean > /dev/null 2>&1
|
||||
if make static-musl-arm64 > /dev/null 2>&1; then
|
||||
if [[ -f "build/c_relay_static_musl_arm64" ]]; then
|
||||
cp build/c_relay_static_musl_arm64 c-relay-static-arm64
|
||||
print_success "Static ARM64 binary created: c-relay-static-arm64"
|
||||
else
|
||||
print_warning "Static ARM64 binary not found after compilation"
|
||||
fi
|
||||
else
|
||||
print_warning "Static ARM64 build failed - ARM64 cross-compilation or MUSL ARM64 packages not set up"
|
||||
fi
|
||||
|
||||
# Restore normal build
|
||||
make clean > /dev/null 2>&1
|
||||
make > /dev/null 2>&1
|
||||
}
|
||||
|
||||
# Function to commit and push changes
|
||||
git_commit_and_push() {
|
||||
print_status "Preparing git commit..."
|
||||
|
||||
# Stage all changes
|
||||
if git add . > /dev/null 2>&1; then
|
||||
print_success "Staged all changes"
|
||||
else
|
||||
print_error "Failed to stage changes"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if there are changes to commit
|
||||
if git diff --staged --quiet; then
|
||||
print_warning "No changes to commit"
|
||||
else
|
||||
# Commit changes
|
||||
if git commit -m "$NEW_VERSION - $COMMIT_MESSAGE" > /dev/null 2>&1; then
|
||||
print_success "Committed changes"
|
||||
else
|
||||
print_error "Failed to commit changes"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create new git tag
|
||||
if git tag "$NEW_VERSION" > /dev/null 2>&1; then
|
||||
print_success "Created tag: $NEW_VERSION"
|
||||
else
|
||||
print_warning "Tag $NEW_VERSION already exists"
|
||||
fi
|
||||
|
||||
# Push changes and tags
|
||||
print_status "Pushing to remote repository..."
|
||||
if git push > /dev/null 2>&1; then
|
||||
print_success "Pushed changes"
|
||||
else
|
||||
print_error "Failed to push changes"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Push only the new tag to avoid conflicts with existing tags
|
||||
if git push origin "$NEW_VERSION" > /dev/null 2>&1; then
|
||||
print_success "Pushed tag: $NEW_VERSION"
|
||||
else
|
||||
print_warning "Tag push failed, trying force push..."
|
||||
if git push --force origin "$NEW_VERSION" > /dev/null 2>&1; then
|
||||
print_success "Force-pushed updated tag: $NEW_VERSION"
|
||||
else
|
||||
print_error "Failed to push tag: $NEW_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to commit and push changes without creating a tag (tag already created)
|
||||
git_commit_and_push_no_tag() {
|
||||
print_status "Preparing git commit..."
|
||||
|
||||
# Stage all changes
|
||||
if git add . > /dev/null 2>&1; then
|
||||
print_success "Staged all changes"
|
||||
else
|
||||
print_error "Failed to stage changes"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if there are changes to commit
|
||||
if git diff --staged --quiet; then
|
||||
print_warning "No changes to commit"
|
||||
else
|
||||
# Commit changes
|
||||
if git commit -m "$NEW_VERSION - $COMMIT_MESSAGE" > /dev/null 2>&1; then
|
||||
print_success "Committed changes"
|
||||
else
|
||||
print_error "Failed to commit changes"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Push changes and tags
|
||||
print_status "Pushing to remote repository..."
|
||||
if git push > /dev/null 2>&1; then
|
||||
print_success "Pushed changes"
|
||||
else
|
||||
print_error "Failed to push changes"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Push only the new tag to avoid conflicts with existing tags
|
||||
if git push origin "$NEW_VERSION" > /dev/null 2>&1; then
|
||||
print_success "Pushed tag: $NEW_VERSION"
|
||||
else
|
||||
print_warning "Tag push failed, trying force push..."
|
||||
if git push --force origin "$NEW_VERSION" > /dev/null 2>&1; then
|
||||
print_success "Force-pushed updated tag: $NEW_VERSION"
|
||||
else
|
||||
print_error "Failed to push tag: $NEW_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to create Gitea release
|
||||
create_gitea_release() {
|
||||
print_status "Creating Gitea release..."
|
||||
|
||||
# Check for Gitea token
|
||||
if [[ ! -f "$HOME/.gitea_token" ]]; then
|
||||
print_warning "No ~/.gitea_token found. Skipping release creation."
|
||||
print_warning "Create ~/.gitea_token with your Gitea access token to enable releases."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local token=$(cat "$HOME/.gitea_token" | tr -d '\n\r')
|
||||
local api_url="https://git.laantungir.net/api/v1/repos/laantungir/c-relay"
|
||||
|
||||
# Create release
|
||||
print_status "Creating release $NEW_VERSION..."
|
||||
local response=$(curl -s -X POST "$api_url/releases" \
|
||||
-H "Authorization: token $token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\": \"$NEW_VERSION\", \"name\": \"$NEW_VERSION\", \"body\": \"$COMMIT_MESSAGE\"}")
|
||||
|
||||
local upload_result=false
|
||||
|
||||
if echo "$response" | grep -q '"id"'; then
|
||||
print_success "Created release $NEW_VERSION"
|
||||
if upload_release_binaries "$api_url" "$token"; then
|
||||
upload_result=true
|
||||
fi
|
||||
elif echo "$response" | grep -q "already exists"; then
|
||||
print_warning "Release $NEW_VERSION already exists"
|
||||
if upload_release_binaries "$api_url" "$token"; then
|
||||
upload_result=true
|
||||
fi
|
||||
else
|
||||
print_error "Failed to create release $NEW_VERSION"
|
||||
print_error "Response: $response"
|
||||
|
||||
# Try to check if the release exists anyway
|
||||
print_status "Checking if release exists..."
|
||||
local check_response=$(curl -s -H "Authorization: token $token" "$api_url/releases/tags/$NEW_VERSION")
|
||||
if echo "$check_response" | grep -q '"id"'; then
|
||||
print_warning "Release exists but creation response was unexpected"
|
||||
if upload_release_binaries "$api_url" "$token"; then
|
||||
upload_result=true
|
||||
fi
|
||||
else
|
||||
print_error "Release does not exist and creation failed"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Return based on upload success
|
||||
if [[ "$upload_result" == true ]]; then
|
||||
return 0
|
||||
else
|
||||
print_error "Binary upload failed"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to upload release binaries
|
||||
upload_release_binaries() {
|
||||
local api_url="$1"
|
||||
local token="$2"
|
||||
local upload_success=true
|
||||
|
||||
# Get release ID with more robust parsing
|
||||
print_status "Getting release ID for $NEW_VERSION..."
|
||||
local response=$(curl -s -H "Authorization: token $token" "$api_url/releases/tags/$NEW_VERSION")
|
||||
local release_id=$(echo "$response" | grep -o '"id":[0-9]*' | head -n1 | cut -d: -f2)
|
||||
|
||||
if [[ -z "$release_id" ]]; then
|
||||
print_error "Could not get release ID for $NEW_VERSION"
|
||||
print_error "API Response: $response"
|
||||
|
||||
# Try to list all releases to debug
|
||||
print_status "Available releases:"
|
||||
curl -s -H "Authorization: token $token" "$api_url/releases" | grep -o '"tag_name":"[^"]*"' | head -5
|
||||
return 1
|
||||
fi
|
||||
|
||||
print_success "Found release ID: $release_id"
|
||||
|
||||
# Upload x86_64 binary
|
||||
if [[ -f "c-relay-x86_64" ]]; then
|
||||
print_status "Uploading x86_64 binary..."
|
||||
local upload_response=$(curl -s -w "\n%{http_code}" -X POST "$api_url/releases/$release_id/assets" \
|
||||
-H "Authorization: token $token" \
|
||||
-F "attachment=@c-relay-x86_64;filename=c-relay-${NEW_VERSION}-linux-x86_64")
|
||||
|
||||
local http_code=$(echo "$upload_response" | tail -n1)
|
||||
local response_body=$(echo "$upload_response" | head -n -1)
|
||||
|
||||
if [[ "$http_code" == "201" ]]; then
|
||||
print_success "Uploaded x86_64 binary successfully"
|
||||
else
|
||||
print_error "Failed to upload x86_64 binary (HTTP $http_code)"
|
||||
print_error "Response: $response_body"
|
||||
upload_success=false
|
||||
fi
|
||||
else
|
||||
print_warning "x86_64 binary not found: c-relay-x86_64"
|
||||
fi
|
||||
|
||||
# Upload ARM64 binary
|
||||
if [[ -f "c-relay-arm64" ]]; then
|
||||
print_status "Uploading ARM64 binary..."
|
||||
local upload_response=$(curl -s -w "\n%{http_code}" -X POST "$api_url/releases/$release_id/assets" \
|
||||
-H "Authorization: token $token" \
|
||||
-F "attachment=@c-relay-arm64;filename=c-relay-${NEW_VERSION}-linux-arm64")
|
||||
|
||||
local http_code=$(echo "$upload_response" | tail -n1)
|
||||
local response_body=$(echo "$upload_response" | head -n -1)
|
||||
|
||||
if [[ "$http_code" == "201" ]]; then
|
||||
print_success "Uploaded ARM64 binary successfully"
|
||||
else
|
||||
print_error "Failed to upload ARM64 binary (HTTP $http_code)"
|
||||
print_error "Response: $response_body"
|
||||
upload_success=false
|
||||
fi
|
||||
else
|
||||
print_warning "ARM64 binary not found: c-relay-arm64"
|
||||
fi
|
||||
|
||||
# Upload static x86_64 binary
|
||||
if [[ -f "c-relay-static-x86_64" ]]; then
|
||||
print_status "Uploading static x86_64 binary..."
|
||||
local upload_response=$(curl -s -w "\n%{http_code}" -X POST "$api_url/releases/$release_id/assets" \
|
||||
-H "Authorization: token $token" \
|
||||
-F "attachment=@c-relay-static-x86_64;filename=c-relay-${NEW_VERSION}-linux-x86_64-static")
|
||||
|
||||
local http_code=$(echo "$upload_response" | tail -n1)
|
||||
local response_body=$(echo "$upload_response" | head -n -1)
|
||||
|
||||
if [[ "$http_code" == "201" ]]; then
|
||||
print_success "Uploaded static x86_64 binary successfully"
|
||||
else
|
||||
print_error "Failed to upload static x86_64 binary (HTTP $http_code)"
|
||||
print_error "Response: $response_body"
|
||||
upload_success=false
|
||||
fi
|
||||
else
|
||||
print_warning "Static x86_64 binary not found: c-relay-static-x86_64"
|
||||
fi
|
||||
|
||||
# Upload static ARM64 binary
|
||||
if [[ -f "c-relay-static-arm64" ]]; then
|
||||
print_status "Uploading static ARM64 binary..."
|
||||
local upload_response=$(curl -s -w "\n%{http_code}" -X POST "$api_url/releases/$release_id/assets" \
|
||||
-H "Authorization: token $token" \
|
||||
-F "attachment=@c-relay-static-arm64;filename=c-relay-${NEW_VERSION}-linux-arm64-static")
|
||||
|
||||
local http_code=$(echo "$upload_response" | tail -n1)
|
||||
local response_body=$(echo "$upload_response" | head -n -1)
|
||||
|
||||
if [[ "$http_code" == "201" ]]; then
|
||||
print_success "Uploaded static ARM64 binary successfully"
|
||||
else
|
||||
print_error "Failed to upload static ARM64 binary (HTTP $http_code)"
|
||||
print_error "Response: $response_body"
|
||||
upload_success=false
|
||||
fi
|
||||
else
|
||||
print_warning "Static ARM64 binary not found: c-relay-static-arm64"
|
||||
fi
|
||||
|
||||
# Return success/failure status
|
||||
if [[ "$upload_success" == true ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to clean up release binaries
|
||||
cleanup_release_binaries() {
|
||||
local force_cleanup="$1" # Optional parameter to force cleanup even on failure
|
||||
|
||||
if [[ "$force_cleanup" == "force" ]] || [[ "$upload_success" == true ]]; then
|
||||
if [[ -f "c-relay-x86_64" ]]; then
|
||||
rm -f c-relay-x86_64
|
||||
print_status "Cleaned up x86_64 binary"
|
||||
fi
|
||||
if [[ -f "c-relay-arm64" ]]; then
|
||||
rm -f c-relay-arm64
|
||||
print_status "Cleaned up ARM64 binary"
|
||||
fi
|
||||
if [[ -f "c-relay-static-x86_64" ]]; then
|
||||
rm -f c-relay-static-x86_64
|
||||
print_status "Cleaned up static x86_64 binary"
|
||||
fi
|
||||
if [[ -f "c-relay-static-arm64" ]]; then
|
||||
rm -f c-relay-static-arm64
|
||||
print_status "Cleaned up static ARM64 binary"
|
||||
fi
|
||||
else
|
||||
print_warning "Keeping binary files due to upload failures"
|
||||
print_status "Files available for manual upload:"
|
||||
if [[ -f "c-relay-x86_64" ]]; then
|
||||
print_status " - c-relay-x86_64"
|
||||
fi
|
||||
if [[ -f "c-relay-arm64" ]]; then
|
||||
print_status " - c-relay-arm64"
|
||||
fi
|
||||
if [[ -f "c-relay-static-x86_64" ]]; then
|
||||
print_status " - c-relay-static-x86_64"
|
||||
fi
|
||||
if [[ -f "c-relay-static-arm64" ]]; then
|
||||
print_status " - c-relay-static-arm64"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
print_status "C-Relay Build and Push Script"
|
||||
|
||||
# Check prerequisites
|
||||
check_git_repo
|
||||
|
||||
if [[ "$RELEASE_MODE" == true ]]; then
|
||||
print_status "=== RELEASE MODE ==="
|
||||
|
||||
# Increment minor version for releases
|
||||
increment_version "minor"
|
||||
|
||||
# Create new git tag BEFORE compilation so version.h picks it up
|
||||
if git tag "$NEW_VERSION" > /dev/null 2>&1; then
|
||||
print_success "Created tag: $NEW_VERSION"
|
||||
else
|
||||
print_warning "Tag $NEW_VERSION already exists, removing and recreating..."
|
||||
git tag -d "$NEW_VERSION" > /dev/null 2>&1
|
||||
git tag "$NEW_VERSION" > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
# Compile project first (will now pick up the new tag)
|
||||
compile_project
|
||||
|
||||
# Build release binaries
|
||||
build_release_binaries
|
||||
|
||||
# Commit and push (but skip tag creation since we already did it)
|
||||
git_commit_and_push_no_tag
|
||||
|
||||
# Create Gitea release with binaries
|
||||
if create_gitea_release; then
|
||||
print_success "Release $NEW_VERSION completed successfully!"
|
||||
print_status "Binaries uploaded to Gitea release"
|
||||
upload_success=true
|
||||
else
|
||||
print_error "Release creation or binary upload failed"
|
||||
upload_success=false
|
||||
fi
|
||||
|
||||
# Cleanup (only if upload was successful)
|
||||
cleanup_release_binaries
|
||||
|
||||
else
|
||||
print_status "=== DEFAULT MODE ==="
|
||||
|
||||
# Increment patch version for regular commits
|
||||
increment_version "patch"
|
||||
|
||||
# Create new git tag BEFORE compilation so version.h picks it up
|
||||
if git tag "$NEW_VERSION" > /dev/null 2>&1; then
|
||||
print_success "Created tag: $NEW_VERSION"
|
||||
else
|
||||
print_warning "Tag $NEW_VERSION already exists, removing and recreating..."
|
||||
git tag -d "$NEW_VERSION" > /dev/null 2>&1
|
||||
git tag "$NEW_VERSION" > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
# Compile project (will now pick up the new tag)
|
||||
compile_project
|
||||
|
||||
# Commit and push (but skip tag creation since we already did it)
|
||||
git_commit_and_push_no_tag
|
||||
|
||||
print_success "Build and push completed successfully!"
|
||||
print_status "Version $NEW_VERSION pushed to repository"
|
||||
fi
|
||||
}
|
||||
|
||||
# Execute main function
|
||||
main
|
||||
+81
-62
@@ -1,7 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Build fully static MUSL binaries for C-Relay using Alpine Docker
|
||||
# Build fully static MUSL binaries for C-Relay-PG using Alpine Docker
|
||||
# Produces truly portable binaries with zero runtime dependencies
|
||||
# PostgreSQL backend only.
|
||||
|
||||
set -e
|
||||
|
||||
@@ -9,11 +10,36 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BUILD_DIR="$SCRIPT_DIR/build"
|
||||
DOCKERFILE="$SCRIPT_DIR/Dockerfile.alpine-musl"
|
||||
|
||||
echo "=========================================="
|
||||
echo "C-Relay MUSL Static Binary Builder"
|
||||
echo "=========================================="
|
||||
# Parse command line arguments
|
||||
DEBUG_BUILD=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--debug)
|
||||
DEBUG_BUILD=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: Unknown argument: $1"
|
||||
echo "Usage: $0 [--debug]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$DEBUG_BUILD" == "true" ]]; then
|
||||
echo "=========================================="
|
||||
echo "C-Relay-PG MUSL Static Binary Builder (DEBUG MODE)"
|
||||
echo "=========================================="
|
||||
else
|
||||
echo "=========================================="
|
||||
echo "C-Relay-PG MUSL Static Binary Builder (PRODUCTION MODE)"
|
||||
echo "=========================================="
|
||||
fi
|
||||
echo "Project directory: $SCRIPT_DIR"
|
||||
echo "Build directory: $BUILD_DIR"
|
||||
echo "Debug build: $DEBUG_BUILD"
|
||||
echo "DB backend: postgres"
|
||||
echo ""
|
||||
|
||||
# Create build directory
|
||||
@@ -53,24 +79,52 @@ ARCH=$(uname -m)
|
||||
case "$ARCH" in
|
||||
x86_64)
|
||||
PLATFORM="linux/amd64"
|
||||
OUTPUT_NAME="c_relay_static_x86_64"
|
||||
OUTPUT_NAME="c_relay_pg_static_x86_64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
PLATFORM="linux/arm64"
|
||||
OUTPUT_NAME="c_relay_static_arm64"
|
||||
OUTPUT_NAME="c_relay_pg_static_arm64"
|
||||
;;
|
||||
*)
|
||||
echo "WARNING: Unknown architecture: $ARCH"
|
||||
echo "Defaulting to linux/amd64"
|
||||
PLATFORM="linux/amd64"
|
||||
OUTPUT_NAME="c_relay_static_${ARCH}"
|
||||
OUTPUT_NAME="c_relay_pg_static_${ARCH}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Append _debug suffix to output name for debug builds so production binary is never overwritten
|
||||
if [ "$DEBUG_BUILD" = true ]; then
|
||||
OUTPUT_NAME="${OUTPUT_NAME}_debug"
|
||||
fi
|
||||
|
||||
echo "Building for platform: $PLATFORM"
|
||||
echo "Output binary: $OUTPUT_NAME"
|
||||
echo ""
|
||||
|
||||
# Check if Alpine base image is cached
|
||||
echo "Checking for cached Alpine Docker image..."
|
||||
if ! docker images alpine:3.19 --format "{{.Repository}}:{{.Tag}}" | grep -q "alpine:3.19"; then
|
||||
echo "⚠ Alpine 3.19 image not found in cache"
|
||||
echo "Attempting to pull Alpine 3.19 image..."
|
||||
if ! docker pull alpine:3.19; then
|
||||
echo ""
|
||||
echo "ERROR: Failed to pull Alpine 3.19 image"
|
||||
echo "This is required for the static build."
|
||||
echo ""
|
||||
echo "Possible solutions:"
|
||||
echo " 1. Check your internet connection"
|
||||
echo " 2. Try again later (Docker Hub may be temporarily unavailable)"
|
||||
echo " 3. If you have IPv6 issues, disable IPv6 for Docker"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ Alpine 3.19 image pulled successfully"
|
||||
else
|
||||
echo "✓ Alpine 3.19 image found in cache"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Build the Docker image
|
||||
echo "=========================================="
|
||||
echo "Step 1: Building Alpine Docker image"
|
||||
@@ -78,13 +132,14 @@ echo "=========================================="
|
||||
echo "This will:"
|
||||
echo " - Use Alpine Linux (native MUSL)"
|
||||
echo " - Build all dependencies statically"
|
||||
echo " - Compile c-relay with full static linking"
|
||||
echo " - Compile c-relay-pg with full static linking"
|
||||
echo ""
|
||||
|
||||
$DOCKER_CMD build \
|
||||
--platform "$PLATFORM" \
|
||||
--build-arg DEBUG_BUILD=$DEBUG_BUILD \
|
||||
-f "$DOCKERFILE" \
|
||||
-t c-relay-musl-builder:latest \
|
||||
-t c-relay-pg-musl-builder:latest \
|
||||
--progress=plain \
|
||||
. || {
|
||||
echo ""
|
||||
@@ -105,16 +160,17 @@ echo "=========================================="
|
||||
# Build the builder stage to extract the binary
|
||||
$DOCKER_CMD build \
|
||||
--platform "$PLATFORM" \
|
||||
--build-arg DEBUG_BUILD=$DEBUG_BUILD \
|
||||
--target builder \
|
||||
-f "$DOCKERFILE" \
|
||||
-t c-relay-static-builder-stage:latest \
|
||||
-t c-relay-pg-static-builder-stage:latest \
|
||||
. > /dev/null 2>&1
|
||||
|
||||
# Create a temporary container to copy the binary
|
||||
CONTAINER_ID=$($DOCKER_CMD create c-relay-static-builder-stage:latest)
|
||||
CONTAINER_ID=$($DOCKER_CMD create c-relay-pg-static-builder-stage:latest)
|
||||
|
||||
# Copy binary from container
|
||||
$DOCKER_CMD cp "$CONTAINER_ID:/build/c_relay_static" "$BUILD_DIR/$OUTPUT_NAME" || {
|
||||
$DOCKER_CMD cp "$CONTAINER_ID:/build/c_relay_pg_static" "$BUILD_DIR/$OUTPUT_NAME" || {
|
||||
echo "ERROR: Failed to extract binary from container"
|
||||
$DOCKER_CMD rm "$CONTAINER_ID" 2>/dev/null
|
||||
exit 1
|
||||
@@ -123,68 +179,31 @@ $DOCKER_CMD cp "$CONTAINER_ID:/build/c_relay_static" "$BUILD_DIR/$OUTPUT_NAME" |
|
||||
# Clean up container
|
||||
$DOCKER_CMD rm "$CONTAINER_ID" > /dev/null
|
||||
|
||||
echo "✓ Binary extracted to: $BUILD_DIR/$OUTPUT_NAME"
|
||||
echo "✓ Binary extracted: $BUILD_DIR/$OUTPUT_NAME"
|
||||
echo ""
|
||||
|
||||
# Make binary executable
|
||||
chmod +x "$BUILD_DIR/$OUTPUT_NAME"
|
||||
|
||||
# Verify the binary
|
||||
echo "=========================================="
|
||||
echo "Step 3: Verifying static binary"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
file "$BUILD_DIR/$OUTPUT_NAME"
|
||||
ls -lh "$BUILD_DIR/$OUTPUT_NAME"
|
||||
|
||||
echo "Checking for dynamic dependencies:"
|
||||
if LDD_OUTPUT=$(timeout 5 ldd "$BUILD_DIR/$OUTPUT_NAME" 2>&1); then
|
||||
if echo "$LDD_OUTPUT" | grep -q "not a dynamic executable"; then
|
||||
echo "✓ Binary is fully static (no dynamic dependencies)"
|
||||
TRULY_STATIC=true
|
||||
elif echo "$LDD_OUTPUT" | grep -q "statically linked"; then
|
||||
echo "✓ Binary is statically linked"
|
||||
TRULY_STATIC=true
|
||||
else
|
||||
echo "⚠ WARNING: Binary may have dynamic dependencies:"
|
||||
echo "$LDD_OUTPUT"
|
||||
TRULY_STATIC=false
|
||||
fi
|
||||
# Check for dynamic dependencies
|
||||
if ldd "$BUILD_DIR/$OUTPUT_NAME" 2>&1 | grep -q "not a dynamic executable"; then
|
||||
echo "✓ Binary is truly static (no dynamic dependencies)"
|
||||
else
|
||||
# ldd failed or timed out - check with file command instead
|
||||
if file "$BUILD_DIR/$OUTPUT_NAME" | grep -q "statically linked"; then
|
||||
echo "✓ Binary is statically linked (verified with file command)"
|
||||
TRULY_STATIC=true
|
||||
else
|
||||
echo "⚠ Could not verify static linking (ldd check failed)"
|
||||
TRULY_STATIC=false
|
||||
fi
|
||||
echo "⚠ Binary has dynamic dependencies:"
|
||||
ldd "$BUILD_DIR/$OUTPUT_NAME" 2>&1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "File size: $(ls -lh "$BUILD_DIR/$OUTPUT_NAME" | awk '{print $5}')"
|
||||
echo ""
|
||||
|
||||
# Test if binary runs
|
||||
echo "Testing binary execution:"
|
||||
if "$BUILD_DIR/$OUTPUT_NAME" --version 2>&1 | head -5; then
|
||||
echo "✓ Binary executes successfully"
|
||||
else
|
||||
echo "⚠ Binary execution test failed (this may be normal if --version is not supported)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Summary
|
||||
echo "=========================================="
|
||||
echo "Build Summary"
|
||||
echo "Build complete!"
|
||||
echo "=========================================="
|
||||
echo "Binary: $BUILD_DIR/$OUTPUT_NAME"
|
||||
echo "Size: $(du -h "$BUILD_DIR/$OUTPUT_NAME" | cut -f1)"
|
||||
echo "Platform: $PLATFORM"
|
||||
if [ "$TRULY_STATIC" = true ]; then
|
||||
echo "Type: Fully static binary (Alpine MUSL-based)"
|
||||
echo "Portability: Works on ANY Linux distribution"
|
||||
else
|
||||
echo "Type: Static binary (may have minimal dependencies)"
|
||||
fi
|
||||
echo ""
|
||||
echo "✓ Build complete!"
|
||||
echo "Size: $(ls -lh "$BUILD_DIR/$OUTPUT_NAME" | awk '{print $5}')"
|
||||
echo ""
|
||||
|
||||
# Clean up Docker builder stage image
|
||||
$DOCKER_CMD rmi c-relay-pg-static-builder-stage:latest > /dev/null 2>&1 || true
|
||||
|
||||
Submodule
+1
Submodule c_utils_lib added at f46747b243
@@ -0,0 +1,31 @@
|
||||
# Database files (from c-relay running in this directory)
|
||||
*.db
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
|
||||
# Build artifacts
|
||||
*.o
|
||||
*.a
|
||||
|
||||
# Binary (built into root, not version-controlled)
|
||||
caching_relay
|
||||
caching_relay_static_*
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
crelay.log
|
||||
|
||||
# Test configs (not for version control)
|
||||
test_config*.jsonc
|
||||
|
||||
# Note: caching_relay_config.jsonc IS version-controlled (it's the default
|
||||
# config + state store). Don't ignore it.
|
||||
|
||||
# Docker build context temp (copied nostr_core_lib during static build)
|
||||
nostr_core_lib/
|
||||
|
||||
# Editor
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.vscode/
|
||||
@@ -0,0 +1,128 @@
|
||||
# Alpine-based MUSL static binary builder for caching_relay
|
||||
# Produces a truly portable binary with zero runtime dependencies.
|
||||
# Adapted from c-relay's Dockerfile.alpine-musl.
|
||||
|
||||
ARG DEBUG_BUILD=false
|
||||
|
||||
FROM alpine:3.19 AS builder
|
||||
|
||||
ARG DEBUG_BUILD=false
|
||||
|
||||
# Install build dependencies
|
||||
RUN apk add --no-cache \
|
||||
build-base \
|
||||
musl-dev \
|
||||
git \
|
||||
cmake \
|
||||
pkgconfig \
|
||||
autoconf \
|
||||
automake \
|
||||
libtool \
|
||||
openssl-dev \
|
||||
openssl-libs-static \
|
||||
zlib-dev \
|
||||
zlib-static \
|
||||
curl-dev \
|
||||
curl-static \
|
||||
sqlite-dev \
|
||||
postgresql-dev \
|
||||
linux-headers \
|
||||
wget \
|
||||
bash
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Build libsecp256k1 static
|
||||
RUN cd /tmp && \
|
||||
git clone https://github.com/bitcoin-core/secp256k1.git && \
|
||||
cd secp256k1 && \
|
||||
./autogen.sh && \
|
||||
./configure --enable-static --disable-shared --prefix=/usr \
|
||||
CFLAGS="-fPIC" && \
|
||||
make -j$(nproc) && \
|
||||
make install && \
|
||||
rm -rf /tmp/secp256k1
|
||||
|
||||
# Build libwebsockets static with minimal features
|
||||
RUN cd /tmp && \
|
||||
git clone --depth 1 --branch v4.3.3 https://github.com/warmcat/libwebsockets.git && \
|
||||
cd libwebsockets && \
|
||||
mkdir build && cd build && \
|
||||
cmake .. \
|
||||
-DLWS_WITH_STATIC=ON \
|
||||
-DLWS_WITH_SHARED=OFF \
|
||||
-DLWS_WITH_SSL=ON \
|
||||
-DLWS_WITHOUT_TESTAPPS=ON \
|
||||
-DLWS_WITHOUT_TEST_SERVER=ON \
|
||||
-DLWS_WITHOUT_TEST_CLIENT=ON \
|
||||
-DLWS_WITHOUT_TEST_PING=ON \
|
||||
-DLWS_WITH_HTTP2=OFF \
|
||||
-DLWS_WITH_LIBUV=OFF \
|
||||
-DLWS_WITH_LIBEVENT=OFF \
|
||||
-DLWS_IPV6=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DCMAKE_C_FLAGS="-fPIC" && \
|
||||
make -j$(nproc) && \
|
||||
make install && \
|
||||
rm -rf /tmp/libwebsockets
|
||||
|
||||
# Copy nostr_core_lib source (sibling project)
|
||||
COPY nostr_core_lib /build/nostr_core_lib/
|
||||
|
||||
# Build nostr_core_lib with the NIPs needed by the relay pool + signer:
|
||||
# 1 (basic), 6 (keys), 19 (npub bech32), 4 (legacy encryption, signer dep),
|
||||
# 42 (auth, relay pool dep), 44 (modern encryption, signer dep)
|
||||
RUN cd nostr_core_lib && \
|
||||
chmod +x build.sh && \
|
||||
sed -i 's/CFLAGS="-Wall -Wextra -std=c99 -fPIC -O2"/CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -Wall -Wextra -std=c99 -fPIC -O2"/' build.sh && \
|
||||
rm -f *.o *.a 2>/dev/null || true && \
|
||||
./build.sh --nips=1,4,6,19,42,44 && \
|
||||
if [ -f libnostr_core_arm64.a ]; then \
|
||||
cp libnostr_core_arm64.a libnostr_core.a; \
|
||||
elif [ -f libnostr_core_x64.a ]; then \
|
||||
cp libnostr_core_x64.a libnostr_core.a; \
|
||||
else \
|
||||
echo "ERROR: No supported nostr_core static library produced"; \
|
||||
ls -la *.a 2>/dev/null || true; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
# Copy caching_relay source LAST (only this layer rebuilds on source changes)
|
||||
COPY src/ /build/src/
|
||||
|
||||
# Build caching_relay with full static linking.
|
||||
# No sqlite (the daemon doesn't use it), no c_utils (not needed).
|
||||
RUN if [ "$DEBUG_BUILD" = "true" ]; then \
|
||||
CFLAGS="-g -O2 -DDEBUG -fno-omit-frame-pointer"; \
|
||||
STRIP_CMD="echo 'Keeping debug symbols'"; \
|
||||
else \
|
||||
CFLAGS="-O2"; \
|
||||
STRIP_CMD="strip /build/caching_relay_static"; \
|
||||
fi && \
|
||||
gcc -static $CFLAGS -Wall -Wextra -std=c99 \
|
||||
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \
|
||||
-I. -Isrc -Inostr_core_lib -Inostr_core_lib/nostr_core \
|
||||
-Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket \
|
||||
-I/usr/include/postgresql \
|
||||
src/main.c src/debug.c src/jsonc_strip.c src/config.c src/state.c \
|
||||
src/follow_graph.c src/relay_sink.c src/live_subscriber.c \
|
||||
src/backfill.c src/relay_discovery.c \
|
||||
src/pg_inbox.c src/pg_config.c src/forward_catchup.c \
|
||||
-o /build/caching_relay_static \
|
||||
nostr_core_lib/libnostr_core.a \
|
||||
-lwebsockets -lssl -lcrypto -lsecp256k1 \
|
||||
-lcurl -lz -lpthread -lm -ldl -lpq -lpgcommon -lpgport && \
|
||||
eval "$STRIP_CMD"
|
||||
|
||||
# Verify it's truly static
|
||||
RUN echo "=== Binary Information ===" && \
|
||||
file /build/caching_relay_static && \
|
||||
ls -lh /build/caching_relay_static && \
|
||||
echo "=== Checking for dynamic dependencies ===" && \
|
||||
(ldd /build/caching_relay_static 2>&1 || echo "Binary is static") && \
|
||||
echo "=== Build complete ==="
|
||||
|
||||
# Output stage - just the binary
|
||||
FROM scratch AS output
|
||||
COPY --from=builder /build/caching_relay_static /caching_relay_static
|
||||
@@ -0,0 +1,85 @@
|
||||
# caching_relay Makefile - statically linked C99 binary, c-relay style
|
||||
|
||||
# Use bash for reliable glob expansion in recipes (dash handles globs differently).
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -std=c99 -g -O2
|
||||
|
||||
# nostr_core_lib is inside the c-relay-pg project root (one dir up from caching/).
|
||||
NOSTR_CORE_DIR = ../nostr_core_lib
|
||||
|
||||
INCLUDES = -I. -Isrc -I$(NOSTR_CORE_DIR) -I$(NOSTR_CORE_DIR)/nostr_core \
|
||||
-I$(NOSTR_CORE_DIR)/cjson -I$(NOSTR_CORE_DIR)/nostr_websocket \
|
||||
-I/usr/include/postgresql
|
||||
|
||||
# -lsqlite3: nostr_core_lib's request_validator.x64.o references SQLite symbols;
|
||||
# we use --whole-archive so the linker pulls in all objects (needed for NIP-42
|
||||
# cross-references within the archive), which means SQLite must be satisfied.
|
||||
# No c_utils_lib: nostr_core_lib does not depend on it for the NIPs we use.
|
||||
# -lpq: PostgreSQL client library for the caching_event_inbox integration.
|
||||
LIBS = -lwebsockets -lssl -lcrypto -lsecp256k1 -lcurl -lz -ldl -lpthread -lm -lpq -lsqlite3
|
||||
|
||||
MAIN_SRC = src/main.c src/debug.c src/jsonc_strip.c src/config.c src/state.c \
|
||||
src/follow_graph.c src/relay_sink.c src/live_subscriber.c \
|
||||
src/backfill.c src/forward_catchup.c src/relay_discovery.c \
|
||||
src/pg_inbox.c src/pg_config.c
|
||||
|
||||
# Architecture detection
|
||||
ARCH = $(shell uname -m)
|
||||
ifeq ($(ARCH),x86_64)
|
||||
NOSTR_CORE_LIB = $(NOSTR_CORE_DIR)/libnostr_core_x64.a
|
||||
else ifeq ($(ARCH),aarch64)
|
||||
NOSTR_CORE_LIB = $(NOSTR_CORE_DIR)/libnostr_core_arm64.a
|
||||
else ifeq ($(ARCH),arm64)
|
||||
NOSTR_CORE_LIB = $(NOSTR_CORE_DIR)/libnostr_core_arm64.a
|
||||
else
|
||||
NOSTR_CORE_LIB = $(NOSTR_CORE_DIR)/libnostr_core_x64.a
|
||||
endif
|
||||
|
||||
# Binary goes in the c-relay-pg build/ directory so the launcher can find it.
|
||||
TARGET = ../build/caching_relay
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
# Build nostr_core_lib with the NIPs needed by the relay pool + signer:
|
||||
# 1 (basic), 6 (keys), 19 (npub bech32), 4 (legacy encryption, signer dep),
|
||||
# 42 (auth, relay pool dep), 44 (modern encryption, signer dep)
|
||||
$(NOSTR_CORE_LIB):
|
||||
@echo "Building nostr_core_lib with required NIPs..."
|
||||
cd $(NOSTR_CORE_DIR) && ./build.sh --nips=1,4,6,19,42,44
|
||||
|
||||
$(TARGET): $(MAIN_SRC) $(NOSTR_CORE_LIB)
|
||||
@echo "Compiling caching_relay for architecture: $(ARCH)"
|
||||
@# Extract all objects from the static library and link them directly.
|
||||
@# This avoids archive symbol resolution ordering issues (NIP-42 cross-refs).
|
||||
@# Use a fixed temp dir and chain all commands with && so failures stop the build.
|
||||
@rm -rf /tmp/cr_lib && mkdir -p /tmp/cr_lib && \
|
||||
ar x $(NOSTR_CORE_LIB) --output=/tmp/cr_lib && \
|
||||
echo "Extracted $$(ls /tmp/cr_lib/*.o | wc -l) objects" && \
|
||||
$(CC) $(CFLAGS) $(INCLUDES) $(MAIN_SRC) /tmp/cr_lib/*.o -o $(TARGET) $(LIBS) && \
|
||||
rm -rf /tmp/cr_lib && \
|
||||
echo "Build complete: $(TARGET)"
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# cache_all_test - feasibility test for "cache everything" approach #
|
||||
# ------------------------------------------------------------------ #
|
||||
TEST_TARGET = ../build/cache_all_test
|
||||
TEST_SRC = src/cache_all_test.c src/debug.c src/jsonc_strip.c src/config.c \
|
||||
src/state.c
|
||||
|
||||
$(TEST_TARGET): $(TEST_SRC) $(NOSTR_CORE_LIB)
|
||||
@echo "Compiling cache_all_test for architecture: $(ARCH)"
|
||||
@rm -rf /tmp/cr_lib && mkdir -p /tmp/cr_lib && \
|
||||
ar x $(NOSTR_CORE_LIB) --output=/tmp/cr_lib && \
|
||||
echo "Extracted $$(ls /tmp/cr_lib/*.o | wc -l) objects" && \
|
||||
$(CC) $(CFLAGS) $(INCLUDES) $(TEST_SRC) /tmp/cr_lib/*.o -o $(TEST_TARGET) $(LIBS) && \
|
||||
rm -rf /tmp/cr_lib && \
|
||||
echo "Build complete: $(TEST_TARGET)"
|
||||
|
||||
cache_all_test: $(TEST_TARGET)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET) $(TEST_TARGET)
|
||||
|
||||
.PHONY: all clean cache_all_test
|
||||
@@ -0,0 +1,297 @@
|
||||
# caching_relay
|
||||
|
||||
A C99 daemon that caches Nostr events from people you follow into a local relay,
|
||||
so your Nostr client can point at a single fast local relay instead of fanning
|
||||
out to dozens of upstream relays.
|
||||
|
||||
## What it does
|
||||
|
||||
1. Reads a `.jsonc` config file listing your **root npub(s)**, upstream relays,
|
||||
a local relay URL, and the event kinds to cache.
|
||||
2. For each root npub, fetches its kind-3 contact list to discover **followed
|
||||
pubkeys** (your follows + their follows).
|
||||
3. **Live-subscribes** to new events of the configured kinds from the union of
|
||||
followed pubkeys.
|
||||
4. **Backfills** historical events using a progressive window-expansion strategy
|
||||
(24h → 7d → 30d → 90d → 365d), round-robin per pubkey, throttled to be polite
|
||||
to upstream relays.
|
||||
5. **Re-publishes** every fetched event to the local relay via a plain WebSocket
|
||||
`EVENT` client connection (relay-agnostic - works with c-relay, c-relay-pg,
|
||||
or any Nostr relay).
|
||||
6. Persists its backfill progress **in the config file itself** so a restart
|
||||
resumes where it left off.
|
||||
|
||||
## Build
|
||||
|
||||
### Static binary (recommended, c-relay style)
|
||||
|
||||
Produces a truly portable statically-linked MUSL binary with zero runtime
|
||||
dependencies:
|
||||
|
||||
```bash
|
||||
./build_static.sh
|
||||
# or with debug symbols:
|
||||
./build_static.sh --debug
|
||||
# or cross-compile for arm64:
|
||||
./build_static.sh --arch arm64
|
||||
```
|
||||
|
||||
Output: `caching_relay` (in the project root).
|
||||
|
||||
Requires Docker. The build runs in an Alpine container that compiles
|
||||
libsecp256k1, libwebsockets, and nostr_core_lib from source, then statically
|
||||
links everything.
|
||||
|
||||
### Local build (if you have the shared libs installed)
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
Output: `caching_relay` (in the project root).
|
||||
|
||||
Requires: `libwebsockets`, `openssl`, `libsecp256k1`, `libcurl`, `zlib` shared
|
||||
libraries, and a pre-built `../nostr_core_lib/libnostr_core_x64.a`.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
./caching_relay -d 3
|
||||
```
|
||||
|
||||
The daemon looks for `caching_relay_config.jsonc` in the current directory by default.
|
||||
You can override with `-c`:
|
||||
|
||||
```bash
|
||||
./caching_relay -c /path/to/my_config.jsonc -d 3
|
||||
```
|
||||
|
||||
Options:
|
||||
- `-c, --config <file>` - Path to `.jsonc` config file (default: `./caching_relay_config.jsonc`)
|
||||
- `-d, --debug <level>` - Log level 1-4 (1=error, 2=warn, 3=info, 4=debug). Default 3.
|
||||
- `-h, --help` - Show help
|
||||
|
||||
Signals:
|
||||
- `SIGINT` / `SIGTERM` - Graceful shutdown (saves state, closes connections)
|
||||
- `SIGHUP` - Reload config (preserves backfill state)
|
||||
|
||||
## Config file
|
||||
|
||||
The config file [`caching_relay_config.jsonc`](caching_relay_config.jsonc) lives in the
|
||||
project root. It is JSONC (JSON with `//` and `/* */` comments). The daemon
|
||||
rewrites it as plain JSON when saving state (comments are not preserved on
|
||||
rewrite).
|
||||
|
||||
Key fields:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `root_npubs` | npubs whose kind-3 follows list we crawl |
|
||||
| `upstream_relays` | bootstrap relays for initial discovery (kind-3, kind-10002). Outbox relays are discovered dynamically via NIP-65. |
|
||||
| `local_relay` | relay to publish cached events into (never queried) |
|
||||
| `kinds` | event kinds to cache for followed people (e.g. `[1, 3, 6, 10000, 30023]`) |
|
||||
| `admin_kinds` | kinds to follow specifically for root (admin) npubs. Use `["*"]` for all kinds. If omitted, admin uses same `kinds` as everyone else. |
|
||||
| `backfill.window_schedule_seconds` | progressive window sizes in seconds |
|
||||
| `backfill.events_per_tick` | max events per pubkey per backfill tick |
|
||||
| `backfill.tick_interval_seconds` | delay between pubkey backfills (throttle) |
|
||||
| `live.enabled` | enable live subscription |
|
||||
| `follow_graph_refresh_seconds` | how often to re-resolve the follow graph |
|
||||
| `state.*` | managed by the daemon - do not hand-edit |
|
||||
|
||||
## Architecture
|
||||
|
||||
See [`plans/plan.md`](plans/plan.md) for the full architecture document with
|
||||
Mermaid diagrams.
|
||||
|
||||
The daemon uses a **NIP-65 outbox model**: instead of querying a fixed set of
|
||||
bootstrap relays for everything, it discovers which relays each followed pubkey
|
||||
actually posts to (via kind 10002 relay lists) and connects to those relays
|
||||
dynamically. The `upstream_relays` in the config serve only as **bootstrap
|
||||
relays** -- the initial set used to discover kind-3 and kind-10002 events before
|
||||
the outbox relay map is built.
|
||||
|
||||
### Relay pool selection: minimum covering set
|
||||
|
||||
After discovering each followed pubkey's outbox relays (from their kind 10002),
|
||||
the daemon computes the **minimum set of relays that covers all followed
|
||||
pubkeys**. This is the classic set cover problem, solved with a greedy
|
||||
approximation:
|
||||
|
||||
1. Build a map: `{relay_url -> set of pubkeys that list it in their 10002}`
|
||||
2. Greedily pick the relay that covers the most uncovered pubkeys
|
||||
3. Repeat until all pubkeys are covered (or no more relays to pick)
|
||||
4. Always include the bootstrap relays in the final set (they may have events
|
||||
from pubkeys that don't publish a kind 10002)
|
||||
|
||||
This minimizes the number of WebSocket connections while ensuring every
|
||||
followed pubkey is reachable. The daemon logs the selected relay set and which
|
||||
pubkeys each relay covers.
|
||||
|
||||
Pubkeys that have no kind 10002 (or whose 10002 lists no relays) are covered by
|
||||
the bootstrap relays as a fallback.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ caching_relay │
|
||||
│ │
|
||||
upstream relays │ upstream_pool sink_pool │ local relay
|
||||
(damus, nos.lol) │ (query + subscribe) (publish only) │ (c-relay)
|
||||
│ │ │ │ │ │
|
||||
│ │ follow_graph relay_sink │ │
|
||||
└──────────►│ live_subscriber ──────►│ ├─────►│
|
||||
│ backfill ──────────────►│ │ │
|
||||
│ │ │ │ │
|
||||
│ state + seen ring │ │ │
|
||||
└──────────────────────────────────────────┘ │
|
||||
```
|
||||
|
||||
Two `nostr_relay_pool_t` instances:
|
||||
- **upstream_pool** - holds bootstrap relays initially, then dynamically adds
|
||||
outbox relays discovered from kind 10002. Used for `query_sync` (kind-3 fetch,
|
||||
kind-10002 fetch, backfill) and the long-lived live subscription.
|
||||
- **sink_pool** - holds only the local relay; used exclusively for
|
||||
`publish_async`. Never queried.
|
||||
|
||||
## Startup Flow
|
||||
|
||||
### First-time startup (empty local relay)
|
||||
|
||||
The daemon has never run before. The local relay has no cached events. The
|
||||
daemon must bootstrap from the config's `upstream_relays` to discover the
|
||||
outbox relays for each followed pubkey.
|
||||
|
||||
```
|
||||
START
|
||||
|
|
||||
v
|
||||
Load config (caching_relay_config.jsonc)
|
||||
| - root_npubs, upstream_relays (bootstrap), kinds, admin_kinds
|
||||
| - state.backfilled_until == 0 => first-time startup
|
||||
|
|
||||
v
|
||||
Create upstream_pool with bootstrap relays only
|
||||
Create sink_pool with local_relay
|
||||
|
|
||||
v
|
||||
Phase 1: Resolve follow graph (from bootstrap relays)
|
||||
| - For each root npub: query_sync kind=3 from bootstrap relays
|
||||
| - Parse "p" tags => followed pubkey set
|
||||
| - Log: "follow: resolved N followed pubkeys"
|
||||
|
|
||||
v
|
||||
Phase 2: Discover outbox relays (NIP-65, kind 10002) from bootstrap relays
|
||||
| - For each followed pubkey: query_sync kind=10002 from bootstrap relays
|
||||
| - Parse "r" tags => per-pubkey relay list
|
||||
| - Publish all kind-10002 events to local relay (cache them)
|
||||
| - Dynamically add discovered relays to upstream_pool
|
||||
| - Log: "relay_discovery: found N relays from M pubkeys"
|
||||
| - Log: "upstream_pool: now connected to N relays" + list them
|
||||
|
|
||||
v
|
||||
Phase 3: Open live subscriptions on upstream_pool
|
||||
| - follows_sub: non-admin pubkeys + regular kinds
|
||||
| - admin_sub: admin npubs + admin_kinds (or all kinds)
|
||||
|
|
||||
v
|
||||
Phase 4: Begin progressive backfill
|
||||
| - Window 0: 24h -> query each pubkey from their outbox relays
|
||||
| - Window 1: 7d -> ...
|
||||
| - Window 2: 30d -> ...
|
||||
| - Publish all fetched events to local relay
|
||||
| - Save state to config file as each window completes
|
||||
|
|
||||
v
|
||||
Steady-state: live sub + periodic follow-graph refresh + periodic
|
||||
kind-10002 refresh + backfill re-cycle
|
||||
|
|
||||
v
|
||||
SHUTDOWN (SIGINT/SIGTERM) -> save state -> clean exit
|
||||
```
|
||||
|
||||
### Subsequent startup (local relay already has cached events)
|
||||
|
||||
The daemon has run before. The local relay already has kind-3 and kind-10002
|
||||
events cached from the previous run. The daemon can read these from the local
|
||||
relay directly (fast, no network round-trip to bootstrap relays) and only falls
|
||||
back to bootstrap relays for pubkeys it cannot find locally.
|
||||
|
||||
```
|
||||
START
|
||||
|
|
||||
v
|
||||
Load config (caching_relay_config.jsonc)
|
||||
| - state.backfilled_until > 0 => subsequent startup
|
||||
| - state.current_window_index, backfill_cursor preserved
|
||||
|
|
||||
v
|
||||
Create upstream_pool with bootstrap relays
|
||||
Create sink_pool with local_relay
|
||||
|
|
||||
v
|
||||
Phase 1: Resolve follow graph (from LOCAL relay first, bootstrap fallback)
|
||||
| - Query local relay for kind=3 per root npub
|
||||
| - If found locally: use it (fast, no upstream query)
|
||||
| - If not found: fall back to bootstrap relays
|
||||
| - Parse "p" tags => followed pubkey set
|
||||
| - Log: "follow: resolved N followed pubkeys (L local, B bootstrap)"
|
||||
|
|
||||
v
|
||||
Phase 2: Discover outbox relays (from LOCAL relay first, bootstrap fallback)
|
||||
| - Query local relay for kind=10002 per followed pubkey
|
||||
| - If found locally: use it (fast)
|
||||
| - If not found: fall back to bootstrap relays, cache result to local
|
||||
| - Parse "r" tags => per-pubkey relay list
|
||||
| - Dynamically add discovered relays to upstream_pool
|
||||
| - Log: "relay_discovery: found N relays (L local, B bootstrap)"
|
||||
| - Log: "upstream_pool: now connected to N relays" + list them
|
||||
|
|
||||
v
|
||||
Phase 3: Open live subscriptions on upstream_pool
|
||||
| - (same as first-time)
|
||||
|
|
||||
v
|
||||
Phase 4: Resume backfill from saved state
|
||||
| - Resume at state.current_window_index, state.backfill_cursor
|
||||
| - No re-pull of already-backfilled windows
|
||||
| - Continue progressive window expansion from where it left off
|
||||
|
|
||||
v
|
||||
Steady-state (same as first-time)
|
||||
|
|
||||
v
|
||||
SHUTDOWN -> save state -> clean exit
|
||||
```
|
||||
|
||||
### Relay logging
|
||||
|
||||
The daemon logs all relay activity so you can see exactly which relays are
|
||||
being used:
|
||||
|
||||
- `upstream: added wss://relay.damus.io` -- each relay added to the pool
|
||||
- `relay_discovery: found 47 relays from 195 pubkeys` -- outbox discovery summary
|
||||
- `upstream_pool: 50 relays connected:` -- full relay list at startup
|
||||
- `relay_discovery: pubkey X -> wss://relay.example.com (local)` -- per-pubkey
|
||||
relay source (local cache vs bootstrap)
|
||||
- `backfill: pubkey[3/195] abc123 -> wss://relay.example.com (12 events)` --
|
||||
which relay served each backfill query
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [nostr_core_lib](../nostr_core_lib) - built with NIPs 1, 4, 6, 19, 42, 44
|
||||
- libwebsockets, openssl, libsecp256k1, libcurl, zlib (all statically linked
|
||||
in the Docker build)
|
||||
|
||||
## Testing
|
||||
|
||||
Start a local c-relay, then run the daemon:
|
||||
|
||||
```bash
|
||||
# Start local relay (from c-relay project)
|
||||
cd ../c-relay/build && ./c_relay_static_x86_64 -p 8888 &
|
||||
|
||||
# Run the caching daemon (uses ./caching_relay_config.jsonc by default)
|
||||
./caching_relay -d 3
|
||||
|
||||
# Verify events are cached (from another terminal)
|
||||
nak req -k 1 -l 10 ws://127.0.0.1:8888
|
||||
```
|
||||
@@ -0,0 +1 @@
|
||||
0.0.2
|
||||
Executable
+147
@@ -0,0 +1,147 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Build fully static MUSL binary for caching_relay using Alpine Docker.
|
||||
# Produces a truly portable binary with zero runtime dependencies.
|
||||
# Adapted from c-relay's build_static.sh.
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DOCKERFILE="$SCRIPT_DIR/Dockerfile.alpine-musl"
|
||||
|
||||
# Parse command line arguments
|
||||
DEBUG_BUILD=false
|
||||
TARGET_ARCH=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--debug)
|
||||
DEBUG_BUILD=true
|
||||
shift
|
||||
;;
|
||||
--arch)
|
||||
if [[ -z "$2" ]]; then
|
||||
echo "ERROR: --arch requires a value"
|
||||
echo "Usage: $0 [--debug] [--arch <arm64|x86_64>]"
|
||||
exit 1
|
||||
fi
|
||||
case "$2" in
|
||||
arm64|x86_64)
|
||||
TARGET_ARCH="$2"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: Unsupported architecture '$2'"
|
||||
echo "Supported values: arm64, x86_64"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: Unknown argument '$1'"
|
||||
echo "Usage: $0 [--debug] [--arch <arm64|x86_64>]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$DEBUG_BUILD" = true ]; then
|
||||
echo "=========================================="
|
||||
echo "caching_relay MUSL Static Binary Builder (DEBUG MODE)"
|
||||
echo "=========================================="
|
||||
else
|
||||
echo "=========================================="
|
||||
echo "caching_relay MUSL Static Binary Builder (PRODUCTION MODE)"
|
||||
echo "=========================================="
|
||||
fi
|
||||
echo "Project directory: $SCRIPT_DIR"
|
||||
echo ""
|
||||
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "ERROR: Docker is not installed or not in PATH"
|
||||
exit 1
|
||||
fi
|
||||
if ! docker info &> /dev/null; then
|
||||
echo "ERROR: Docker daemon is not running or user not in docker group"
|
||||
exit 1
|
||||
fi
|
||||
echo "Docker is available and running"
|
||||
echo ""
|
||||
|
||||
# Detect host architecture
|
||||
ARCH=$(uname -m)
|
||||
case "$ARCH" in
|
||||
x86_64) ARCH="x86_64";;
|
||||
aarch64) ARCH="arm64";;
|
||||
arm64) ARCH="arm64";;
|
||||
esac
|
||||
if [[ -n "$TARGET_ARCH" ]]; then
|
||||
ARCH="$TARGET_ARCH"
|
||||
echo "Using target architecture: $ARCH"
|
||||
else
|
||||
echo "Detected host architecture: $ARCH"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# nostr_core_lib is inside the c-relay-pg project root (one dir up from caching/).
|
||||
# Copy it into the Docker build context (excluding .git and build artifacts).
|
||||
NOSTR_CORE_DIR="$SCRIPT_DIR/../nostr_core_lib"
|
||||
if [ ! -d "$NOSTR_CORE_DIR" ]; then
|
||||
echo "ERROR: nostr_core_lib not found at $NOSTR_CORE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NEEDS_COPY=1
|
||||
if [ -d "$SCRIPT_DIR/nostr_core_lib" ] && [ ! -L "$SCRIPT_DIR/nostr_core_lib" ]; then
|
||||
# Already a real directory (e.g. from a previous run); assume it's good.
|
||||
NEEDS_COPY=0
|
||||
fi
|
||||
if [ "$NEEDS_COPY" = "1" ]; then
|
||||
echo "Copying nostr_core_lib into build context..."
|
||||
rm -rf "$SCRIPT_DIR/nostr_core_lib"
|
||||
mkdir -p "$SCRIPT_DIR/nostr_core_lib"
|
||||
rsync -a --exclude='.git' --exclude='*.a' --exclude='*.o' \
|
||||
--exclude='.venv*' --exclude='backups' --exclude='verify_*' \
|
||||
--exclude='rewrite_mirror' --exclude='websocket_debug' \
|
||||
"$NOSTR_CORE_DIR/" "$SCRIPT_DIR/nostr_core_lib/"
|
||||
COPIED_NOSTR_CORE=1
|
||||
fi
|
||||
|
||||
# Build args
|
||||
BUILD_ARGS="--build-arg DEBUG_BUILD=$DEBUG_BUILD"
|
||||
if [ "$ARCH" = "arm64" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "arm64" ]; then
|
||||
BUILD_ARGS="$BUILD_ARGS --platform linux/arm64"
|
||||
fi
|
||||
|
||||
IMAGE_TAG="caching_relay_builder:latest"
|
||||
|
||||
echo "Building Docker image..."
|
||||
docker build $BUILD_ARGS \
|
||||
-f "$DOCKERFILE" \
|
||||
-t "$IMAGE_TAG" \
|
||||
"$SCRIPT_DIR" 2>&1
|
||||
|
||||
BUILD_RC=$?
|
||||
|
||||
# Clean up the copied nostr_core_lib to keep the project dir tidy.
|
||||
if [ "${COPIED_NOSTR_CORE:-0}" = "1" ]; then
|
||||
echo "Cleaning up copied nostr_core_lib from build context..."
|
||||
rm -rf "$SCRIPT_DIR/nostr_core_lib"
|
||||
fi
|
||||
|
||||
if [ $BUILD_RC -ne 0 ]; then
|
||||
exit $BUILD_RC
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Extracting binary from image..."
|
||||
# The output stage is FROM scratch with no CMD, so pass an empty command.
|
||||
CONTAINER_ID=$(docker create "$IMAGE_TAG" "")
|
||||
docker cp "$CONTAINER_ID:/caching_relay_static" "$SCRIPT_DIR/caching_relay"
|
||||
docker rm "$CONTAINER_ID" >/dev/null
|
||||
chmod +x "$SCRIPT_DIR/caching_relay"
|
||||
|
||||
echo ""
|
||||
echo "=== Build complete ==="
|
||||
ls -lh "$SCRIPT_DIR/caching_relay"
|
||||
file "$SCRIPT_DIR/caching_relay"
|
||||
@@ -0,0 +1,56 @@
|
||||
{
|
||||
// Cache-All Feasibility Test Config
|
||||
// Root npubs to resolve follow graph from
|
||||
"root_npubs": [
|
||||
"npub1rmz9gu6de0m0u4ysrn39crrud099ahvfgs6pvasl4hpjr5ud7yus54xv06"
|
||||
],
|
||||
|
||||
// Relays to test (from server relay list, connected ones only)
|
||||
"upstream_relays": [
|
||||
"wss://laantungir.net",
|
||||
"wss://nos.lol",
|
||||
"wss://nostr-pub.wellorder.net",
|
||||
"wss://nostr.mom",
|
||||
"wss://nostr.oxtr.dev",
|
||||
"wss://offchain.pub",
|
||||
"wss://premium.primal.net",
|
||||
"wss://relay.damus.io",
|
||||
"wss://relay.ditto.pub",
|
||||
"wss://relay.divine.video",
|
||||
"wss://relay.momostr.pink",
|
||||
"wss://relay.mostr.pub",
|
||||
"wss://relay.nostrplebs.com",
|
||||
"wss://relay.primal.net",
|
||||
"wss://theforest.nostr1.com"
|
||||
],
|
||||
|
||||
// Local relay (not used by test, but required by config parser)
|
||||
"local_relay": "ws://localhost:8888",
|
||||
|
||||
// Kinds to follow (not used by test, but required by config parser)
|
||||
"kinds": [0, 1, 3, 5, 6, 7, 9735, 10002, 30023],
|
||||
|
||||
// Admin kinds
|
||||
"admin_kinds": ["*"],
|
||||
|
||||
// Backfill config (not used by test)
|
||||
"backfill": {
|
||||
"enabled": false,
|
||||
"events_per_tick": 500,
|
||||
"tick_interval_seconds": 5
|
||||
},
|
||||
|
||||
// Live config (not used by test)
|
||||
"live": {
|
||||
"enabled": false,
|
||||
"resubscribe_interval_seconds": 300
|
||||
},
|
||||
|
||||
// Follow graph refresh (not used by test)
|
||||
"follow_graph_refresh_seconds": 600,
|
||||
|
||||
// State (not used by test)
|
||||
"state": {
|
||||
"backfilled_until": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"root_npubs": [
|
||||
"npub1rmz9gu6de0m0u4ysrn39crrud099ahvfgs6pvasl4hpjr5ud7yus54xv06"
|
||||
],
|
||||
"upstream_relays": [
|
||||
"wss://relay.primal.net"
|
||||
],
|
||||
"local_relay": "ws://localhost:8888",
|
||||
"kinds": [0, 1, 3, 5, 6, 7, 9735, 10002, 30023],
|
||||
"admin_kinds": ["*"],
|
||||
"backfill": { "enabled": false, "events_per_tick": 500, "tick_interval_seconds": 5 },
|
||||
"live": { "enabled": false, "resubscribe_interval_seconds": 300 },
|
||||
"follow_graph_refresh_seconds": 600,
|
||||
"state": { "backfilled_until": 0 }
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 5m 0s
|
||||
Config: cache_all_test_config.jsonc
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 11200
|
||||
Total bytes: 17099684 (16.31 MB)
|
||||
Avg event size: 1527 bytes
|
||||
Max event: 45848 bytes (kind 3)
|
||||
Unique pubkeys: 4292
|
||||
Relays contacted: 3
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://relay.primal.net 3492 1 0 0 0 0 DOWN
|
||||
wss://nos.lol 5613 0 0 0 0 0 DOWN
|
||||
wss://relay.damus.io 2095 0 0 0 0 0 DOWN
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
21059 Gift wrap (NIP-59) 3060 27.3% 8988132 2937 19622
|
||||
5 Deletion 1124 10.0% 498378 443 664
|
||||
24747 Ephemeral 1020 9.1% 602037 590 671
|
||||
22668 Ephemeral 547 4.9% 234663 429 429
|
||||
30078 App data 439 3.9% 1714659 3906 37853
|
||||
20001 Ephemeral (key xchg) 395 3.5% 266277 674 1719
|
||||
22734 Ephemeral 265 2.4% 113155 427 427
|
||||
4515 Unknown 246 2.2% 390676 1588 8760
|
||||
1 Text note 205 1.8% 164127 801 2024
|
||||
1059 Gift wrap seal 188 1.7% 301940 1606 5285
|
||||
23334 Ephemeral 179 1.6% 77621 434 438
|
||||
38501 App data (btc) 157 1.4% 116283 741 744
|
||||
30382 Addressable 138 1.2% 66879 485 498
|
||||
21050 Ephemeral 132 1.2% 128700 975 2558
|
||||
10002 Relay list 127 1.1% 178988 1409 42385
|
||||
22850 Ephemeral 124 1.1% 53320 430 430
|
||||
31991 Addressable 122 1.1% 56242 461 461
|
||||
0 Profile metadata 120 1.1% 92899 774 7180
|
||||
37195 Addressable 102 0.9% 77276 758 832
|
||||
24242 Ephemeral 93 0.8% 56549 608 3281
|
||||
25050 Ephemeral 90 0.8% 39930 444 465
|
||||
7 Reaction 79 0.7% 42454 537 738
|
||||
23337 Ephemeral 73 0.7% 37477 513 519
|
||||
24133 Ephemeral 71 0.6% 146874 2069 7334
|
||||
445 Encrypted group msg 68 0.6% 386304 5681 38736
|
||||
22601 Ephemeral 62 0.6% 26536 428 428
|
||||
22613 Ephemeral 58 0.5% 40166 693 695
|
||||
22749 Ephemeral 56 0.5% 24024 429 429
|
||||
22699 Ephemeral 56 0.5% 23968 428 428
|
||||
22676 Ephemeral 56 0.5% 23912 427 427
|
||||
23003 Ephemeral 50 0.4% 21400 428 428
|
||||
13194 NWC info 50 0.4% 25490 510 514
|
||||
29333 Ephemeral 50 0.4% 24600 492 492
|
||||
22795 Ephemeral 50 0.4% 22860 457 1839
|
||||
22774 Ephemeral 50 0.4% 21401 428 429
|
||||
20000 Ephemeral 50 0.4% 23047 461 536
|
||||
22655 Ephemeral 49 0.4% 20972 428 428
|
||||
31990 App handler info 46 0.4% 43151 938 1465
|
||||
5300 Unknown 44 0.4% 27099 616 701
|
||||
30383 Addressable 44 0.4% 23495 534 542
|
||||
22456 Ephemeral 43 0.4% 21378 497 790
|
||||
25555 Ephemeral 42 0.4% 175994 4190 16987
|
||||
20004 Ephemeral 39 0.3% 20619 529 549
|
||||
3927 Unknown 39 0.3% 20809 534 544
|
||||
22484 Ephemeral 36 0.3% 32790 911 1165
|
||||
11998 Unknown 33 0.3% 15297 464 465
|
||||
7368 Unknown 32 0.3% 33232 1038 1041
|
||||
20387 Ephemeral 31 0.3% 15934 514 514
|
||||
22507 Ephemeral 28 0.2% 25861 924 1163
|
||||
20787 Ephemeral 26 0.2% 34212 1316 2282
|
||||
10100 Unknown 25 0.2% 48552 1942 3825
|
||||
30091 Addressable 23 0.2% 14133 614 629
|
||||
30088 Addressable 23 0.2% 42847 1863 1871
|
||||
38502 Addressable 22 0.2% 8470 385 385
|
||||
4 Encrypted DM 22 0.2% 25752 1171 6250
|
||||
1985 Label 22 0.2% 10436 474 483
|
||||
10050 DM relays 21 0.2% 9383 447 465
|
||||
30315 User status 20 0.2% 12697 635 926
|
||||
22816 Ephemeral 20 0.2% 8580 429 429
|
||||
4004 Unknown 19 0.2% 22211 1169 1169
|
||||
22522 Ephemeral 18 0.2% 7632 424 424
|
||||
22914 Ephemeral 17 0.2% 15202 894 1819
|
||||
3 Follow list 15 0.1% 210884 14059 45848
|
||||
22591 Ephemeral 15 0.1% 6390 426 426
|
||||
30089 Chunked data 15 0.1% 221528 14769 44372
|
||||
6300 Unknown 15 0.1% 83624 5575 17374
|
||||
30023 Long-form article 15 0.1% 83310 5554 8177
|
||||
20333 Ephemeral 15 0.1% 11950 797 798
|
||||
22832 Ephemeral 14 0.1% 6006 429 429
|
||||
1077 Unknown 14 0.1% 8498 607 607
|
||||
22651 Ephemeral 14 0.1% 5992 428 428
|
||||
30515 Addressable 14 0.1% 55160 3940 3940
|
||||
23333 Ephemeral 11 0.1% 6455 587 601
|
||||
2333 Unknown 11 0.1% 7423 675 689
|
||||
30311 Addressable 10 0.1% 10569 1057 1214
|
||||
21617 Ephemeral 10 0.1% 4950 495 495
|
||||
30443 Addressable 10 0.1% 11954 1195 1292
|
||||
9735 Zap receipt 10 0.1% 20601 2060 2282
|
||||
1337 Unknown 10 0.1% 5696 570 811
|
||||
25055 Ephemeral 10 0.1% 14724 1472 1764
|
||||
21060 Ephemeral 9 0.1% 5130 570 570
|
||||
38225 Addressable 9 0.1% 9197 1022 1047
|
||||
22949 Ephemeral 9 0.1% 3879 431 431
|
||||
4244 Unknown 9 0.1% 5076 564 564
|
||||
7375 Unknown 9 0.1% 72189 8021 14089
|
||||
7376 Unknown 9 0.1% 4689 521 521
|
||||
38385 Addressable 9 0.1% 12280 1364 1496
|
||||
31234 Addressable 9 0.1% 12744 1416 1416
|
||||
22712 Ephemeral 8 0.1% 3424 428 428
|
||||
38503 Addressable 8 0.1% 4424 553 553
|
||||
30113 Addressable 8 0.1% 4688 586 701
|
||||
6 Repost 8 0.1% 11116 1390 2553
|
||||
31510 Addressable 7 0.1% 6853 979 982
|
||||
22785 Ephemeral 7 0.1% 2996 428 428
|
||||
22680 Ephemeral 7 0.1% 6191 884 1160
|
||||
22793 Ephemeral 7 0.1% 2996 428 428
|
||||
22684 Ephemeral 6 0.1% 2574 429 429
|
||||
22225 Ephemeral 6 0.1% 2661 444 444
|
||||
1002 Unknown 6 0.1% 5458 910 971
|
||||
22739 Ephemeral 6 0.1% 2568 428 428
|
||||
22658 Ephemeral 6 0.1% 5377 896 1164
|
||||
30080 Addressable 5 0.0% 4658 932 985
|
||||
33334 Addressable 5 0.0% 4155 831 831
|
||||
10011 Unknown 5 0.0% 2155 431 431
|
||||
25195 Ephemeral 5 0.0% 3390 678 678
|
||||
22508 Ephemeral 5 0.0% 2130 426 426
|
||||
22789 Ephemeral 5 0.0% 2140 428 428
|
||||
30380 Addressable 5 0.0% 2270 454 454
|
||||
38384 Addressable 5 0.0% 3715 743 743
|
||||
20384 Ephemeral 5 0.0% 3195 639 639
|
||||
22688 Ephemeral 5 0.0% 2150 430 430
|
||||
22649 Ephemeral 5 0.0% 2135 427 427
|
||||
39101 Addressable 5 0.0% 2665 533 533
|
||||
22611 Ephemeral 5 0.0% 2130 426 426
|
||||
22526 Ephemeral 5 0.0% 2150 430 430
|
||||
22514 Ephemeral 4 0.0% 1700 425 425
|
||||
22775 Ephemeral 4 0.0% 1716 429 429
|
||||
443 Unknown 4 0.0% 4336 1084 1084
|
||||
25196 Ephemeral 4 0.0% 7152 1788 2214
|
||||
30618 Addressable 4 0.0% 6570 1642 4371
|
||||
23194 NWC request 4 0.0% 2106 526 576
|
||||
1040 Unknown 4 0.0% 4192 1048 1048
|
||||
38500 Addressable 4 0.0% 2848 712 713
|
||||
22236 Ephemeral 4 0.0% 3109 777 801
|
||||
1111 Comment 4 0.0% 5593 1398 1988
|
||||
3434 Unknown 3 0.0% 2035 678 705
|
||||
1050 Unknown 3 0.0% 1311 437 437
|
||||
33051 Addressable 3 0.0% 1559 520 522
|
||||
7000 Unknown 3 0.0% 2329 776 779
|
||||
22309 Ephemeral 3 0.0% 1331 444 444
|
||||
30617 Addressable 3 0.0% 3267 1089 1089
|
||||
10030 Emoji list 3 0.0% 1215 405 405
|
||||
22253 Ephemeral 3 0.0% 1331 444 444
|
||||
22345 Ephemeral 3 0.0% 1331 444 444
|
||||
4245 Unknown 3 0.0% 1332 444 444
|
||||
22423 Ephemeral 3 0.0% 1331 444 444
|
||||
4243 Unknown 3 0.0% 1692 564 564
|
||||
10000 Mute list 3 0.0% 4678 1559 3850
|
||||
22352 Ephemeral 3 0.0% 1330 443 444
|
||||
38383 Addressable 3 0.0% 2159 720 743
|
||||
22327 Ephemeral 3 0.0% 1330 443 444
|
||||
30213 Addressable 3 0.0% 1880 627 637
|
||||
20 Picture 2 0.0% 1272 636 827
|
||||
10312 Unknown 2 0.0% 973 486 491
|
||||
10007 Search relays 2 0.0% 1272 636 754
|
||||
10086 Unknown 2 0.0% 1451 726 757
|
||||
22891 Ephemeral 2 0.0% 2272 1136 1843
|
||||
22495 Ephemeral 2 0.0% 854 427 427
|
||||
4242 Unknown 2 0.0% 12868 6434 6443
|
||||
30000 Follow sets 2 0.0% 1773 886 950
|
||||
22777 Ephemeral 2 0.0% 856 428 428
|
||||
22391 Ephemeral 2 0.0% 887 444 444
|
||||
6472 Unknown 2 0.0% 1106 553 553
|
||||
22239 Ephemeral 2 0.0% 887 444 444
|
||||
22146 Ephemeral 2 0.0% 886 443 443
|
||||
22420 Ephemeral 2 0.0% 887 444 444
|
||||
10063 Unknown 2 0.0% 1012 506 627
|
||||
22193 Ephemeral 2 0.0% 886 443 443
|
||||
22275 Ephemeral 2 0.0% 886 443 443
|
||||
31000 Addressable 2 0.0% 1204 602 616
|
||||
22738 Ephemeral 2 0.0% 858 429 429
|
||||
31340 Addressable 2 0.0% 854 427 430
|
||||
22218 Ephemeral 2 0.0% 887 444 444
|
||||
22285 Ephemeral 2 0.0% 887 444 444
|
||||
7403 Unknown 2 0.0% 982 491 491
|
||||
22302 Ephemeral 2 0.0% 886 443 443
|
||||
22241 Ephemeral 2 0.0% 887 444 444
|
||||
22288 Ephemeral 2 0.0% 887 444 444
|
||||
22120 Ephemeral 2 0.0% 2170 1085 1118
|
||||
22119 Ephemeral 2 0.0% 1691 846 846
|
||||
15750 Unknown 2 0.0% 1184 592 620
|
||||
10443 Unknown 2 0.0% 2578 1289 1289
|
||||
22736 Ephemeral 1 0.0% 429 429 429
|
||||
22653 Ephemeral 1 0.0% 1840 1840 1840
|
||||
22842 Ephemeral 1 0.0% 1847 1847 1847
|
||||
22190 Ephemeral 1 0.0% 443 443 443
|
||||
37779 Addressable 1 0.0% 523 523 523
|
||||
22312 Ephemeral 1 0.0% 443 443 443
|
||||
1717 Unknown 1 0.0% 1776 1776 1776
|
||||
22407 Ephemeral 1 0.0% 425 425 425
|
||||
1340 Unknown 1 0.0% 435 435 435
|
||||
10051 Unknown 1 0.0% 443 443 443
|
||||
10012 Unknown 1 0.0% 522 522 522
|
||||
22368 Ephemeral 1 0.0% 443 443 443
|
||||
10003 Bookmarks 1 0.0% 1974 1974 1974
|
||||
39015 Addressable 1 0.0% 696 696 696
|
||||
1311 Unknown 1 0.0% 534 534 534
|
||||
22820 Ephemeral 1 0.0% 430 430 430
|
||||
22928 Ephemeral 1 0.0% 429 429 429
|
||||
22713 Ephemeral 1 0.0% 429 429 429
|
||||
22543 Ephemeral 1 0.0% 1843 1843 1843
|
||||
22369 Ephemeral 1 0.0% 443 443 443
|
||||
22314 Ephemeral 1 0.0% 443 443 443
|
||||
10001 Pinned notes 1 0.0% 710 710 710
|
||||
30815 Addressable 1 0.0% 37534 37534 37534
|
||||
31339 Addressable 1 0.0% 1470 1470 1470
|
||||
38422 Addressable 1 0.0% 20019 20019 20019
|
||||
30087 Addressable 1 0.0% 7325 7325 7325
|
||||
30090 Addressable 1 0.0% 1515 1515 1515
|
||||
10089 Unknown 1 0.0% 1097 1097 1097
|
||||
13196 Unknown 1 0.0% 656 656 656
|
||||
39050 Addressable 1 0.0% 1843 1843 1843
|
||||
10005 Unknown 1 0.0% 694 694 694
|
||||
30554 Addressable 1 0.0% 609 609 609
|
||||
22765 Ephemeral 1 0.0% 431 431 431
|
||||
1078 Unknown 1 0.0% 13949 13949 13949
|
||||
22740 Ephemeral 1 0.0% 3194 3194 3194
|
||||
38111 Addressable 1 0.0% 747 747 747
|
||||
4747 Unknown 1 0.0% 721 721 721
|
||||
10019 Unknown 1 0.0% 536 536 536
|
||||
22333 Ephemeral 1 0.0% 443 443 443
|
||||
22318 Ephemeral 1 0.0% 443 443 443
|
||||
23010 Ephemeral 1 0.0% 429 429 429
|
||||
30079 Addressable 1 0.0% 875 875 875
|
||||
22455 Ephemeral 1 0.0% 1840 1840 1840
|
||||
22219 Ephemeral 1 0.0% 443 443 443
|
||||
30787 Addressable 1 0.0% 1370 1370 1370
|
||||
22624 Ephemeral 1 0.0% 3198 3198 3198
|
||||
22750 Ephemeral 1 0.0% 553 553 553
|
||||
22313 Ephemeral 1 0.0% 443 443 443
|
||||
1080 Unknown 1 0.0% 1033 1033 1033
|
||||
11316 Unknown 1 0.0% 725 725 725
|
||||
11317 Unknown 1 0.0% 12051 12051 12051
|
||||
12222 Unknown 1 0.0% 579 579 579
|
||||
22823 Ephemeral 1 0.0% 429 429 429
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 09:32:17 2026
|
||||
# Config: cache_all_test_config.jsonc
|
||||
# Duration: 300 seconds
|
||||
[2026-08-02 09:32:24] [RELAY] wss://relay.primal.net EOSE
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 2m 0s
|
||||
Config: cache_all_test_config.jsonc
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 4267
|
||||
Total bytes: 6726611 (6.41 MB)
|
||||
Avg event size: 1576 bytes
|
||||
Max event: 42385 bytes (kind 10002)
|
||||
Unique pubkeys: 1860
|
||||
Relays contacted: 3
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://relay.primal.net 1670 1 0 0 0 0 OK
|
||||
wss://nos.lol 1792 0 0 0 0 0 OK
|
||||
wss://relay.damus.io 805 0 0 0 0 0 OK
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
21059 Gift wrap (NIP-59) 1199 28.1% 3547818 2959 5314
|
||||
5 Deletion 466 10.9% 204587 439 1064
|
||||
30078 App data 222 5.2% 948782 4274 40337
|
||||
22668 Ephemeral 221 5.2% 94809 429 429
|
||||
20001 Ephemeral (key xchg) 152 3.6% 106536 701 1755
|
||||
4515 Unknown 152 3.6% 260732 1715 8759
|
||||
22734 Ephemeral 108 2.5% 46116 427 427
|
||||
1 Text note 105 2.5% 83026 791 3482
|
||||
21050 Ephemeral 91 2.1% 89206 980 2558
|
||||
24747 Ephemeral 85 2.0% 42775 503 671
|
||||
22850 Ephemeral 77 1.8% 33110 430 430
|
||||
22591 Ephemeral 66 1.5% 53607 812 1222
|
||||
38501 App data (btc) 61 1.4% 45175 741 744
|
||||
10002 Relay list 51 1.2% 63749 1250 42385
|
||||
0 Profile metadata 47 1.1% 33672 716 1611
|
||||
37195 Addressable 44 1.0% 32855 747 771
|
||||
24242 Ephemeral 37 0.9% 21423 579 579
|
||||
25050 Ephemeral 36 0.8% 15972 444 465
|
||||
7 Reaction 36 0.8% 18965 527 646
|
||||
22613 Ephemeral 35 0.8% 26154 747 1134
|
||||
22484 Ephemeral 32 0.7% 29125 910 1163
|
||||
22749 Ephemeral 29 0.7% 12441 429 429
|
||||
24133 Ephemeral 25 0.6% 37446 1498 7334
|
||||
22601 Ephemeral 25 0.6% 10700 428 428
|
||||
22507 Ephemeral 24 0.6% 22582 941 1165
|
||||
1059 Gift wrap seal 23 0.5% 41391 1800 2897
|
||||
22699 Ephemeral 23 0.5% 9844 428 428
|
||||
22676 Ephemeral 23 0.5% 9821 427 427
|
||||
22774 Ephemeral 20 0.5% 8560 428 428
|
||||
22795 Ephemeral 20 0.5% 8580 429 429
|
||||
22655 Ephemeral 20 0.5% 8560 428 428
|
||||
23003 Ephemeral 20 0.5% 8560 428 428
|
||||
30382 Addressable 20 0.5% 9960 498 498
|
||||
29333 Ephemeral 20 0.5% 9840 492 492
|
||||
25555 Ephemeral 18 0.4% 62434 3469 17003
|
||||
11998 Unknown 18 0.4% 8322 462 465
|
||||
31990 App handler info 18 0.4% 16845 936 1465
|
||||
4 Encrypted DM 18 0.4% 28064 1559 17018
|
||||
13194 NWC info 18 0.4% 9252 514 514
|
||||
22689 Ephemeral 17 0.4% 7259 427 427
|
||||
5300 Unknown 17 0.4% 10495 617 701
|
||||
445 Encrypted group msg 17 0.4% 81892 4817 19620
|
||||
20000 Ephemeral 15 0.4% 7045 470 546
|
||||
20387 Ephemeral 14 0.3% 7196 514 514
|
||||
20004 Ephemeral 14 0.3% 7488 535 549
|
||||
7368 Unknown 13 0.3% 13476 1037 1040
|
||||
22456 Ephemeral 13 0.3% 6110 470 470
|
||||
9735 Zap receipt 13 0.3% 26072 2006 2331
|
||||
22551 Ephemeral 13 0.3% 11042 849 1161
|
||||
22760 Ephemeral 13 0.3% 11014 847 1161
|
||||
22658 Ephemeral 13 0.3% 11050 850 1164
|
||||
10100 Unknown 11 0.3% 20684 1880 3825
|
||||
30315 User status 11 0.3% 8899 809 1038
|
||||
20787 Ephemeral 11 0.3% 15458 1405 2474
|
||||
22236 Ephemeral 10 0.2% 7818 782 814
|
||||
22832 Ephemeral 10 0.2% 4286 429 429
|
||||
38502 Addressable 8 0.2% 3080 385 385
|
||||
4004 Unknown 8 0.2% 9352 1169 1169
|
||||
22785 Ephemeral 8 0.2% 3432 429 429
|
||||
3 Follow list 8 0.2% 35850 4481 9845
|
||||
1985 Label 8 0.2% 3792 474 474
|
||||
22584 Ephemeral 8 0.2% 3416 427 427
|
||||
22816 Ephemeral 8 0.2% 3432 429 429
|
||||
22752 Ephemeral 8 0.2% 6212 776 3199
|
||||
6 Repost 7 0.2% 10112 1445 1872
|
||||
443 Unknown 7 0.2% 7780 1111 1116
|
||||
22651 Ephemeral 6 0.1% 2568 428 428
|
||||
1077 Unknown 6 0.1% 3642 607 607
|
||||
26428 Ephemeral 6 0.1% 5254 876 876
|
||||
22616 Ephemeral 6 0.1% 2574 429 429
|
||||
22626 Ephemeral 6 0.1% 2568 428 428
|
||||
22914 Ephemeral 6 0.1% 2580 430 430
|
||||
22614 Ephemeral 6 0.1% 2568 428 428
|
||||
22419 Ephemeral 5 0.1% 2218 444 444
|
||||
22847 Ephemeral 5 0.1% 2155 431 431
|
||||
30088 Addressable 5 0.1% 9317 1863 1871
|
||||
10050 DM relays 5 0.1% 2250 450 450
|
||||
30091 Addressable 5 0.1% 3085 617 629
|
||||
30311 Addressable 5 0.1% 5153 1031 1197
|
||||
23080 Ephemeral 5 0.1% 2155 431 431
|
||||
38225 Addressable 4 0.1% 4077 1019 1036
|
||||
4244 Unknown 4 0.1% 2256 564 564
|
||||
26429 Ephemeral 4 0.1% 1964 491 491
|
||||
3927 Unknown 4 0.1% 2132 533 533
|
||||
22806 Ephemeral 4 0.1% 1712 428 428
|
||||
30000 Follow sets 4 0.1% 9358 2340 2845
|
||||
21617 Ephemeral 4 0.1% 1980 495 495
|
||||
20333 Ephemeral 4 0.1% 3188 797 798
|
||||
22548 Ephemeral 4 0.1% 1720 430 430
|
||||
38503 Addressable 4 0.1% 2212 553 553
|
||||
30515 Addressable 4 0.1% 18496 4624 4624
|
||||
22740 Ephemeral 4 0.1% 1708 427 427
|
||||
22226 Ephemeral 3 0.1% 1331 444 444
|
||||
10011 Unknown 3 0.1% 1375 458 513
|
||||
30089 Chunked data 3 0.1% 6944 2315 3412
|
||||
30023 Long-form article 3 0.1% 19822 6607 7860
|
||||
21060 Ephemeral 3 0.1% 1710 570 570
|
||||
22526 Ephemeral 3 0.1% 1290 430 430
|
||||
22511 Ephemeral 3 0.1% 2383 794 1163
|
||||
22167 Ephemeral 3 0.1% 1331 444 444
|
||||
30213 Addressable 3 0.1% 1866 622 632
|
||||
22748 Ephemeral 3 0.1% 1284 428 428
|
||||
31234 Addressable 3 0.1% 4248 1416 1416
|
||||
22838 Ephemeral 2 0.0% 860 430 430
|
||||
38500 Addressable 2 0.0% 1424 712 713
|
||||
38384 Addressable 2 0.0% 1486 743 743
|
||||
30443 Addressable 2 0.0% 2379 1190 1220
|
||||
20384 Ephemeral 2 0.0% 1278 639 639
|
||||
34237 Addressable 2 0.0% 836 418 418
|
||||
22280 Ephemeral 2 0.0% 887 444 444
|
||||
23194 NWC request 2 0.0% 1020 510 510
|
||||
22320 Ephemeral 2 0.0% 887 444 444
|
||||
30080 Addressable 2 0.0% 1971 986 986
|
||||
22205 Ephemeral 2 0.0% 887 444 444
|
||||
22770 Ephemeral 2 0.0% 862 431 431
|
||||
22305 Ephemeral 2 0.0% 887 444 444
|
||||
22356 Ephemeral 2 0.0% 886 443 443
|
||||
22611 Ephemeral 2 0.0% 852 426 426
|
||||
22217 Ephemeral 2 0.0% 887 444 444
|
||||
22884 Ephemeral 2 0.0% 860 430 430
|
||||
33334 Addressable 2 0.0% 1662 831 831
|
||||
6300 Unknown 2 0.0% 8371 4186 5058
|
||||
22169 Ephemeral 2 0.0% 887 444 444
|
||||
22190 Ephemeral 2 0.0% 887 444 444
|
||||
30079 Addressable 2 0.0% 1750 875 875
|
||||
39101 Addressable 2 0.0% 1066 533 533
|
||||
22345 Ephemeral 2 0.0% 887 444 444
|
||||
22310 Ephemeral 2 0.0% 887 444 444
|
||||
1111 Comment 2 0.0% 2557 1278 1564
|
||||
22235 Ephemeral 2 0.0% 887 444 444
|
||||
38385 Addressable 2 0.0% 2552 1276 1319
|
||||
4747 Unknown 1 0.0% 721 721 721
|
||||
22844 Ephemeral 1 0.0% 428 428 428
|
||||
22807 Ephemeral 1 0.0% 3205 3205 3205
|
||||
30066 Addressable 1 0.0% 675 675 675
|
||||
4245 Unknown 1 0.0% 444 444 444
|
||||
7376 Unknown 1 0.0% 521 521 521
|
||||
22450 Ephemeral 1 0.0% 443 443 443
|
||||
22261 Ephemeral 1 0.0% 443 443 443
|
||||
4243 Unknown 1 0.0% 564 564 564
|
||||
22242 Ephemeral 1 0.0% 443 443 443
|
||||
10063 Unknown 1 0.0% 415 415 415
|
||||
22306 Ephemeral 1 0.0% 443 443 443
|
||||
22174 Ephemeral 1 0.0% 443 443 443
|
||||
22831 Ephemeral 1 0.0% 3182 3182 3182
|
||||
22227 Ephemeral 1 0.0% 443 443 443
|
||||
7375 Unknown 1 0.0% 8629 8629 8629
|
||||
22685 Ephemeral 1 0.0% 553 553 553
|
||||
22299 Ephemeral 1 0.0% 443 443 443
|
||||
22193 Ephemeral 1 0.0% 443 443 443
|
||||
22975 Ephemeral 1 0.0% 3195 3195 3195
|
||||
30380 Addressable 1 0.0% 454 454 454
|
||||
20 Picture 1 0.0% 860 860 860
|
||||
10030 Emoji list 1 0.0% 405 405 405
|
||||
30087 Addressable 1 0.0% 7325 7325 7325
|
||||
30090 Addressable 1 0.0% 1515 1515 1515
|
||||
22220 Ephemeral 1 0.0% 443 443 443
|
||||
39019 Addressable 1 0.0% 961 961 961
|
||||
39015 Addressable 1 0.0% 696 696 696
|
||||
30617 Addressable 1 0.0% 1089 1089 1089
|
||||
30618 Addressable 1 0.0% 733 733 733
|
||||
31991 Addressable 1 0.0% 461 461 461
|
||||
1080 Unknown 1 0.0% 949 949 949
|
||||
3434 Unknown 1 0.0% 705 705 705
|
||||
33333 Addressable 1 0.0% 2346 2346 2346
|
||||
22735 Ephemeral 1 0.0% 430 430 430
|
||||
22415 Ephemeral 1 0.0% 443 443 443
|
||||
21966 Ephemeral 1 0.0% 443 443 443
|
||||
11316 Unknown 1 0.0% 725 725 725
|
||||
11317 Unknown 1 0.0% 12051 12051 12051
|
||||
25195 Ephemeral 1 0.0% 678 678 678
|
||||
25196 Ephemeral 1 0.0% 1362 1362 1362
|
||||
22402 Ephemeral 1 0.0% 443 443 443
|
||||
31510 Addressable 1 0.0% 979 979 979
|
||||
1078 Unknown 1 0.0% 14200 14200 14200
|
||||
38383 Addressable 1 0.0% 685 685 685
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 09:38:02 2026
|
||||
# Config: cache_all_test_config.jsonc
|
||||
# Duration: 120 seconds
|
||||
[2026-08-02 09:38:07] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 09:38:07] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 09:38:07] [RELAY] wss://relay.damus.io CONNECTED
|
||||
[2026-08-02 09:38:08] [RELAY] wss://relay.primal.net EOSE
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 2m 0s
|
||||
Config: cache_all_test_config.jsonc
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 5012
|
||||
Total bytes: 8091410 (7.72 MB)
|
||||
Avg event size: 1614 bytes
|
||||
Max event: 52672 bytes (kind 3)
|
||||
Unique pubkeys: 2034
|
||||
Relays contacted: 3
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://relay.primal.net 1599 1 0 0 0 0 OK
|
||||
wss://nos.lol 2389 0 0 0 0 0 OK
|
||||
wss://relay.damus.io 1024 0 0 0 0 0 OK
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
21059 Gift wrap (NIP-59) 1361 27.2% 4189338 3078 5314
|
||||
5 Deletion 579 11.6% 254363 439 624
|
||||
22668 Ephemeral 265 5.3% 113685 429 429
|
||||
30078 App data 190 3.8% 702178 3696 14343
|
||||
20001 Ephemeral (key xchg) 181 3.6% 108257 598 1489
|
||||
22639 Ephemeral 176 3.5% 136058 773 1228
|
||||
4515 Unknown 168 3.4% 319242 1900 14220
|
||||
24133 Ephemeral 152 3.0% 464764 3058 14162
|
||||
22734 Ephemeral 135 2.7% 57645 427 427
|
||||
31991 Addressable 116 2.3% 53476 461 461
|
||||
21050 Ephemeral 84 1.7% 81900 975 2558
|
||||
1 Text note 80 1.6% 58412 730 1443
|
||||
22795 Ephemeral 76 1.5% 104000 1368 1848
|
||||
22850 Ephemeral 75 1.5% 33353 445 1169
|
||||
38501 App data (btc) 69 1.4% 51105 741 744
|
||||
22842 Ephemeral 55 1.1% 92475 1681 1849
|
||||
10002 Relay list 48 1.0% 19784 412 537
|
||||
0 Profile metadata 47 0.9% 34961 744 1356
|
||||
37195 Addressable 38 0.8% 28214 742 771
|
||||
7 Reaction 38 0.8% 21600 568 779
|
||||
25050 Ephemeral 36 0.7% 15972 444 465
|
||||
24242 Ephemeral 34 0.7% 19686 579 579
|
||||
1059 Gift wrap seal 33 0.7% 58147 1762 3298
|
||||
22484 Ephemeral 32 0.6% 29156 911 1164
|
||||
22507 Ephemeral 28 0.6% 24308 868 1165
|
||||
22613 Ephemeral 25 0.5% 17238 690 691
|
||||
29333 Ephemeral 25 0.5% 12300 492 492
|
||||
22601 Ephemeral 24 0.5% 10272 428 428
|
||||
5300 Unknown 23 0.5% 14096 613 701
|
||||
22751 Ephemeral 23 0.5% 9798 426 426
|
||||
22699 Ephemeral 22 0.4% 9416 428 428
|
||||
11998 Unknown 22 0.4% 10182 463 465
|
||||
22676 Ephemeral 22 0.4% 9394 427 427
|
||||
13194 NWC info 21 0.4% 10617 506 514
|
||||
22774 Ephemeral 20 0.4% 8560 428 428
|
||||
23003 Ephemeral 20 0.4% 8560 428 428
|
||||
22655 Ephemeral 19 0.4% 8132 428 428
|
||||
22543 Ephemeral 19 0.4% 34993 1842 1848
|
||||
22455 Ephemeral 19 0.4% 34943 1839 1844
|
||||
25555 Ephemeral 19 0.4% 94673 4983 17111
|
||||
30443 Addressable 19 0.4% 22379 1178 1260
|
||||
22777 Ephemeral 19 0.4% 16685 878 1651
|
||||
22891 Ephemeral 18 0.4% 33189 1844 1848
|
||||
31990 App handler info 17 0.3% 15825 931 1465
|
||||
20000 Ephemeral 16 0.3% 7206 450 522
|
||||
32123 Addressable 14 0.3% 10528 752 900
|
||||
22456 Ephemeral 13 0.3% 6110 470 470
|
||||
20004 Ephemeral 13 0.3% 6741 519 549
|
||||
22591 Ephemeral 13 0.3% 6348 488 697
|
||||
20787 Ephemeral 12 0.2% 16864 1405 2478
|
||||
4 Encrypted DM 12 0.2% 7972 664 786
|
||||
20387 Ephemeral 12 0.2% 6168 514 514
|
||||
38502 Addressable 12 0.2% 4620 385 385
|
||||
10100 Unknown 11 0.2% 20938 1903 3825
|
||||
20050 Ephemeral 11 0.2% 9711 883 891
|
||||
3 Follow list 10 0.2% 72137 7214 52672
|
||||
9735 Zap receipt 10 0.2% 20833 2083 2143
|
||||
445 Encrypted group msg 10 0.2% 17866 1787 4126
|
||||
22626 Ephemeral 10 0.2% 4280 428 428
|
||||
7368 Unknown 9 0.2% 9343 1038 1041
|
||||
22736 Ephemeral 9 0.2% 3816 424 424
|
||||
1985 Label 8 0.2% 3810 476 483
|
||||
30091 Addressable 8 0.2% 4927 616 629
|
||||
30315 User status 8 0.2% 4522 565 872
|
||||
25055 Ephemeral 8 0.2% 10605 1326 1764
|
||||
22791 Ephemeral 8 0.2% 3416 427 427
|
||||
22816 Ephemeral 8 0.2% 3432 429 429
|
||||
4004 Unknown 8 0.2% 9352 1169 1169
|
||||
30088 Addressable 8 0.2% 14929 1866 1871
|
||||
31234 Addressable 8 0.2% 14048 1756 1756
|
||||
22813 Ephemeral 7 0.1% 2996 428 428
|
||||
22957 Ephemeral 7 0.1% 3010 430 430
|
||||
30089 Chunked data 7 0.1% 45972 6567 27988
|
||||
32678 Addressable 7 0.1% 5704 815 900
|
||||
22832 Ephemeral 6 0.1% 2574 429 429
|
||||
22897 Ephemeral 6 0.1% 2586 431 431
|
||||
22549 Ephemeral 6 0.1% 2574 429 429
|
||||
22702 Ephemeral 6 0.1% 4753 792 2618
|
||||
20333 Ephemeral 6 0.1% 4780 797 798
|
||||
30023 Long-form article 6 0.1% 21101 3517 5056
|
||||
22568 Ephemeral 5 0.1% 2135 427 427
|
||||
38385 Addressable 5 0.1% 6849 1370 1496
|
||||
4244 Unknown 5 0.1% 2820 564 564
|
||||
22717 Ephemeral 5 0.1% 2135 427 427
|
||||
21617 Ephemeral 4 0.1% 1980 495 495
|
||||
38225 Addressable 4 0.1% 4061 1015 1039
|
||||
6 Repost 4 0.1% 8823 2206 3647
|
||||
22333 Ephemeral 4 0.1% 1773 443 444
|
||||
22962 Ephemeral 3 0.1% 1290 430 430
|
||||
33334 Addressable 3 0.1% 2229 743 831
|
||||
1002 Unknown 3 0.1% 2793 931 979
|
||||
22244 Ephemeral 3 0.1% 1330 443 444
|
||||
22907 Ephemeral 3 0.1% 1287 429 429
|
||||
10011 Unknown 3 0.1% 1229 410 431
|
||||
22258 Ephemeral 3 0.1% 1330 443 444
|
||||
22245 Ephemeral 3 0.1% 1331 444 444
|
||||
30618 Addressable 3 0.1% 1755 585 733
|
||||
22296 Ephemeral 3 0.1% 1331 444 444
|
||||
38503 Addressable 3 0.1% 1659 553 553
|
||||
22338 Ephemeral 3 0.1% 1330 443 444
|
||||
22195 Ephemeral 3 0.1% 1331 444 444
|
||||
22342 Ephemeral 3 0.1% 1331 444 444
|
||||
10050 DM relays 3 0.1% 1350 450 450
|
||||
30311 Addressable 3 0.1% 3414 1138 1197
|
||||
32680 Addressable 2 0.0% 1376 688 688
|
||||
30380 Addressable 2 0.0% 908 454 454
|
||||
22611 Ephemeral 2 0.0% 852 426 426
|
||||
4243 Unknown 2 0.0% 1128 564 564
|
||||
22526 Ephemeral 2 0.0% 860 430 430
|
||||
22320 Ephemeral 2 0.0% 887 444 444
|
||||
4245 Unknown 2 0.0% 888 444 444
|
||||
1984 Report 2 0.0% 873 436 446
|
||||
1111 Comment 2 0.0% 3115 1558 1558
|
||||
22311 Ephemeral 2 0.0% 886 443 443
|
||||
22662 Ephemeral 2 0.0% 858 429 429
|
||||
22089 Ephemeral 2 0.0% 886 443 443
|
||||
22221 Ephemeral 2 0.0% 887 444 444
|
||||
22157 Ephemeral 2 0.0% 887 444 444
|
||||
38384 Addressable 2 0.0% 1486 743 743
|
||||
20384 Ephemeral 2 0.0% 1278 639 639
|
||||
30080 Addressable 2 0.0% 1679 840 985
|
||||
39101 Addressable 2 0.0% 1066 533 533
|
||||
6300 Unknown 2 0.0% 11904 5952 6898
|
||||
10003 Bookmarks 2 0.0% 14466 7233 7233
|
||||
30515 Addressable 2 0.0% 9248 4624 4624
|
||||
22829 Ephemeral 2 0.0% 6387 3194 3194
|
||||
22106 Ephemeral 2 0.0% 887 444 444
|
||||
31927 Addressable 2 0.0% 3000 1500 1500
|
||||
31510 Addressable 2 0.0% 1959 980 980
|
||||
3927 Unknown 2 0.0% 1066 533 533
|
||||
1040 Unknown 2 0.0% 2096 1048 1048
|
||||
31000 Addressable 2 0.0% 1204 602 616
|
||||
22201 Ephemeral 2 0.0% 886 443 443
|
||||
22269 Ephemeral 2 0.0% 887 444 444
|
||||
22818 Ephemeral 2 0.0% 852 426 426
|
||||
22364 Ephemeral 2 0.0% 887 444 444
|
||||
25195 Ephemeral 1 0.0% 678 678 678
|
||||
25196 Ephemeral 1 0.0% 1362 1362 1362
|
||||
22283 Ephemeral 1 0.0% 443 443 443
|
||||
10030 Emoji list 1 0.0% 405 405 405
|
||||
22706 Ephemeral 1 0.0% 3192 3192 3192
|
||||
22236 Ephemeral 1 0.0% 737 737 737
|
||||
31339 Addressable 1 0.0% 1470 1470 1470
|
||||
22651 Ephemeral 1 0.0% 428 428 428
|
||||
38500 Addressable 1 0.0% 713 713 713
|
||||
10000 Mute list 1 0.0% 1311 1311 1311
|
||||
31926 Addressable 1 0.0% 1038 1038 1038
|
||||
22757 Ephemeral 1 0.0% 428 428 428
|
||||
39015 Addressable 1 0.0% 696 696 696
|
||||
30617 Addressable 1 0.0% 1089 1089 1089
|
||||
22234 Ephemeral 1 0.0% 443 443 443
|
||||
30815 Addressable 1 0.0% 37534 37534 37534
|
||||
1078 Unknown 1 0.0% 13939 13939 13939
|
||||
39050 Addressable 1 0.0% 1843 1843 1843
|
||||
22281 Ephemeral 1 0.0% 443 443 443
|
||||
30166 Addressable 1 0.0% 808 808 808
|
||||
22772 Ephemeral 1 0.0% 429 429 429
|
||||
22356 Ephemeral 1 0.0% 443 443 443
|
||||
30554 Addressable 1 0.0% 609 609 609
|
||||
38422 Addressable 1 0.0% 20025 20025 20025
|
||||
38000 Addressable 1 0.0% 562 562 562
|
||||
22069 Ephemeral 1 0.0% 443 443 443
|
||||
1050 Unknown 1 0.0% 437 437 437
|
||||
33051 Addressable 1 0.0% 522 522 522
|
||||
39036 Addressable 1 0.0% 1138 1138 1138
|
||||
23194 NWC request 1 0.0% 510 510 510
|
||||
30081 Addressable 1 0.0% 1370 1370 1370
|
||||
22299 Ephemeral 1 0.0% 443 443 443
|
||||
22556 Ephemeral 1 0.0% 427 427 427
|
||||
22302 Ephemeral 1 0.0% 443 443 443
|
||||
39019 Addressable 1 0.0% 961 961 961
|
||||
30000 Follow sets 1 0.0% 823 823 823
|
||||
38383 Addressable 1 0.0% 657 657 657
|
||||
30087 Addressable 1 0.0% 7325 7325 7325
|
||||
30090 Addressable 1 0.0% 1515 1515 1515
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 09:48:55 2026
|
||||
# Config: cache_all_test_config.jsonc
|
||||
# Duration: 120 seconds
|
||||
[2026-08-02 09:49:03] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 09:49:03] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 09:49:03] [RELAY] wss://relay.damus.io CONNECTED
|
||||
[2026-08-02 09:49:03] [RELAY] wss://relay.primal.net EOSE
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 0m 0s
|
||||
Config: cache_all_test_config.jsonc
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 0
|
||||
Total bytes: 0 (0.00 MB)
|
||||
Avg event size: 0 bytes
|
||||
Max event: 0 bytes (kind 0)
|
||||
Unique pubkeys: 0
|
||||
Relays contacted: 27
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://relay.primal.net 0 0 0 0 0 0 DOWN
|
||||
wss://nos.lol 0 0 0 0 0 0 DOWN
|
||||
wss://relay.damus.io 0 0 0 0 0 0 DOWN
|
||||
wss://relay.ditto.pub 0 0 0 0 0 0 DOWN
|
||||
wss://nostr.land 0 0 0 0 0 0 DOWN
|
||||
wss://nostr.wine 0 0 0 0 0 0 DOWN
|
||||
wss://nostr.oxtr.dev 0 0 0 0 0 0 DOWN
|
||||
wss://spatia-arcana.com/inbox 0 0 0 0 0 0 DOWN
|
||||
wss://eden.nostr.land 0 0 0 0 0 0 DOWN
|
||||
wss://relay.nostr.band 0 0 0 0 0 0 DOWN
|
||||
wss://theforest.nostr1.com 0 0 0 0 0 0 DOWN
|
||||
wss://wot.utxo.one 0 0 0 0 0 0 DOWN
|
||||
wss://premium.primal.net 0 0 0 0 0 0 DOWN
|
||||
wss://nostr.mom 0 0 0 0 0 0 DOWN
|
||||
wss://relay.mostr.pub 0 0 0 0 0 0 DOWN
|
||||
wss://offchain.pub 0 0 0 0 0 0 DOWN
|
||||
wss://relay.divine.video 0 0 0 0 0 0 DOWN
|
||||
wss://relay.nostrplebs.com 0 0 0 0 0 0 DOWN
|
||||
wss://nostr-pub.wellorder.net 0 0 0 0 0 0 DOWN
|
||||
wss://devrelay.azzamo.net 0 0 0 0 0 0 DOWN
|
||||
wss://relay.noderunners.network 0 0 0 0 0 0 DOWN
|
||||
wss://nostr-pub.semisol.dev 0 0 0 0 0 0 DOWN
|
||||
wss://relay.shosho.live 0 0 0 0 0 0 DOWN
|
||||
wss://relay.nostrcheck.me 0 0 0 0 0 0 DOWN
|
||||
wss://relay.nostr.info 0 0 0 0 0 0 DOWN
|
||||
wss://relay.momostr.pink 0 0 0 0 0 0 DOWN
|
||||
wss://bitsat.molonlabe.holdings 0 0 0 0 0 0 DOWN
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 10:01:51 2026
|
||||
# Config: cache_all_test_config.jsonc
|
||||
# Duration: 300 seconds
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 0m 0s
|
||||
Config: cache_all_test_config.jsonc
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 0
|
||||
Total bytes: 0 (0.00 MB)
|
||||
Avg event size: 0 bytes
|
||||
Max event: 0 bytes (kind 0)
|
||||
Unique pubkeys: 0
|
||||
Relays contacted: 15
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://relay.primal.net 0 0 0 0 0 0 DOWN
|
||||
wss://nos.lol 0 0 0 0 0 0 DOWN
|
||||
wss://relay.damus.io 0 0 0 0 0 0 DOWN
|
||||
wss://nostr.land 0 0 0 0 0 0 DOWN
|
||||
wss://relay.ditto.pub 0 0 0 0 0 0 DOWN
|
||||
wss://nostr.oxtr.dev 0 0 0 0 0 0 DOWN
|
||||
wss://pyramid.fiatjaf.com/inbox 0 0 0 0 0 0 DOWN
|
||||
wss://relay.mostr.pub 0 0 0 0 0 0 DOWN
|
||||
wss://relay.divine.video 0 0 0 0 0 0 DOWN
|
||||
wss://nostr.wine 0 0 0 0 0 0 DOWN
|
||||
wss://theforest.nostr1.com 0 0 0 0 0 0 DOWN
|
||||
wss://relay.nostrplebs.com 0 0 0 0 0 0 DOWN
|
||||
wss://relay.shosho.live 0 0 0 0 0 0 DOWN
|
||||
wss://relay.nostr.band 0 0 0 0 0 0 DOWN
|
||||
wss://relay.nostr.info 0 0 0 0 0 0 DOWN
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 10:10:55 2026
|
||||
# Config: cache_all_test_config.jsonc
|
||||
# Duration: 300 seconds
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 0m 0s
|
||||
Config: cache_all_test_config.jsonc
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 0
|
||||
Total bytes: 0 (0.00 MB)
|
||||
Avg event size: 0 bytes
|
||||
Max event: 0 bytes (kind 0)
|
||||
Unique pubkeys: 0
|
||||
Relays contacted: 11
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://relay.primal.net 0 0 0 0 0 0 DOWN
|
||||
wss://nos.lol 0 0 0 0 0 0 DOWN
|
||||
wss://relay.damus.io 0 0 0 0 0 0 DOWN
|
||||
wss://relay.ditto.pub 0 0 0 0 0 0 DOWN
|
||||
wss://nostr.bitcoiner.social 0 0 0 0 0 0 DOWN
|
||||
wss://nostr.land 0 0 0 0 0 0 DOWN
|
||||
wss://pyramid.fiatjaf.com/inbox 0 0 0 0 0 0 DOWN
|
||||
wss://relay.divine.video 0 0 0 0 0 0 DOWN
|
||||
wss://relay.nostrplebs.com 0 0 0 0 0 0 DOWN
|
||||
wss://eden.nostr.land 0 0 0 0 0 0 DOWN
|
||||
wss://relay.shosho.live 0 0 0 0 0 0 DOWN
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 10:17:20 2026
|
||||
# Config: cache_all_test_config.jsonc
|
||||
# Duration: 30 seconds
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 1m 54s
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 4719
|
||||
Total bytes: 6608416 (6.30 MB)
|
||||
Avg event size: 1400 bytes
|
||||
Max event: 44372 bytes (kind 30089)
|
||||
Unique pubkeys: 1333
|
||||
Relays: 15
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://laantungir.net 0 0 0 0 0 0 DOWN
|
||||
wss://nos.lol 804 0 0 0 0 3 OK
|
||||
wss://nostr-pub.wellorder.net 83 0 0 0 0 0 OK
|
||||
wss://nostr.mom 175 0 0 0 0 0 OK
|
||||
wss://nostr.oxtr.dev 108 0 0 0 0 0 OK
|
||||
wss://offchain.pub 627 0 0 0 0 0 OK
|
||||
wss://premium.primal.net 1 0 0 0 0 0 OK
|
||||
wss://relay.damus.io 0 0 0 0 0 0 DOWN
|
||||
wss://relay.ditto.pub 721 0 0 0 0 0 OK
|
||||
wss://relay.divine.video 3 0 0 0 0 0 OK
|
||||
wss://relay.momostr.pink 86 0 0 0 0 0 OK
|
||||
wss://relay.mostr.pub 836 0 0 0 0 0 OK
|
||||
wss://relay.nostrplebs.com 4 0 0 0 0 0 OK
|
||||
wss://relay.primal.net 1239 0 0 0 0 0 OK
|
||||
wss://theforest.nostr1.com 32 0 0 0 0 0 OK
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
21059 Gift wrap (NIP-59) 675 14.3% 2192938 3249 5314
|
||||
30382 Addressable 563 11.9% 255591 454 498
|
||||
5 Deletion 341 7.2% 153667 451 1404
|
||||
22639 Ephemeral 231 4.9% 178011 771 1230
|
||||
22551 Ephemeral 182 3.9% 78260 430 430
|
||||
20001 Ephemeral 143 3.0% 70427 492 1206
|
||||
30078 App data 141 3.0% 1361122 9653 44169
|
||||
0 Profile metadata 135 2.9% 119793 887 3483
|
||||
22734 Ephemeral 122 2.6% 52094 427 427
|
||||
24747 Ephemeral 101 2.1% 59352 588 594
|
||||
1 Text note 90 1.9% 92140 1024 4709
|
||||
22668 Ephemeral 88 1.9% 37752 429 429
|
||||
22850 Ephemeral 83 1.8% 35690 430 430
|
||||
22870 Ephemeral 76 1.6% 77061 1014 2202
|
||||
22951 Ephemeral 75 1.6% 77282 1030 2204
|
||||
10002 Relay list 75 1.6% 202196 2696 42385
|
||||
22912 Ephemeral 74 1.6% 31672 428 428
|
||||
38501 Addressable 65 1.4% 48152 741 744
|
||||
24133 Ephemeral 63 1.3% 72262 1147 2898
|
||||
6 Repost 50 1.1% 40985 820 3346
|
||||
37195 Addressable 48 1.0% 36225 755 771
|
||||
21050 Ephemeral 48 1.0% 46800 975 2558
|
||||
4515 Unknown 46 1.0% 81638 1775 6028
|
||||
25555 Ephemeral 45 1.0% 209551 4657 16603
|
||||
7 Reaction 40 0.8% 22486 562 805
|
||||
22917 Ephemeral 39 0.8% 35435 909 1166
|
||||
22699 Ephemeral 39 0.8% 26723 685 1166
|
||||
22690 Ephemeral 39 0.8% 16770 430 430
|
||||
22918 Ephemeral 38 0.8% 36470 960 1507
|
||||
22832 Ephemeral 37 0.8% 16128 436 446
|
||||
25050 Ephemeral 35 0.7% 15507 443 465
|
||||
30383 Addressable 35 0.7% 18766 536 541
|
||||
22713 Ephemeral 34 0.7% 14570 429 430
|
||||
22698 Ephemeral 34 0.7% 31371 923 1674
|
||||
22601 Ephemeral 28 0.6% 11984 428 428
|
||||
22655 Ephemeral 28 0.6% 11984 428 428
|
||||
1059 Gift wrap seal 23 0.5% 46912 2040 5285
|
||||
22751 Ephemeral 21 0.4% 8946 426 426
|
||||
22676 Ephemeral 21 0.4% 8967 427 427
|
||||
29333 Ephemeral 20 0.4% 9840 492 492
|
||||
5300 Unknown 20 0.4% 11959 598 630
|
||||
22743 Ephemeral 19 0.4% 8132 428 428
|
||||
22603 Ephemeral 19 0.4% 8094 426 426
|
||||
22693 Ephemeral 19 0.4% 8113 427 427
|
||||
22774 Ephemeral 19 0.4% 8132 428 428
|
||||
22808 Ephemeral 19 0.4% 8151 429 429
|
||||
22575 Ephemeral 19 0.4% 8075 425 425
|
||||
23003 Ephemeral 19 0.4% 8132 428 428
|
||||
22949 Ephemeral 19 0.4% 8151 429 429
|
||||
23334 Ephemeral 19 0.4% 8189 431 431
|
||||
24242 Ephemeral 17 0.4% 9843 579 579
|
||||
22816 Ephemeral 16 0.3% 6864 429 429
|
||||
20787 Ephemeral 16 0.3% 25100 1569 2478
|
||||
13194 NWC info 15 0.3% 7574 505 514
|
||||
38502 Addressable 14 0.3% 5390 385 385
|
||||
22236 Ephemeral 14 0.3% 11214 801 814
|
||||
22613 Ephemeral 13 0.3% 8977 691 694
|
||||
30088 Addressable 12 0.3% 22340 1862 1871
|
||||
22484 Ephemeral 12 0.3% 10948 912 1165
|
||||
30091 Addressable 12 0.3% 7385 615 629
|
||||
20004 Ephemeral 11 0.2% 5643 513 549
|
||||
31990 App handler info 11 0.2% 8711 792 1465
|
||||
445 Encrypted group msg 10 0.2% 17972 1797 4126
|
||||
22795 Ephemeral 9 0.2% 3861 429 429
|
||||
22507 Ephemeral 9 0.2% 8480 942 1165
|
||||
22922 Ephemeral 9 0.2% 3870 430 430
|
||||
24421 Ephemeral 9 0.2% 4644 516 516
|
||||
22830 Ephemeral 9 0.2% 7317 813 1168
|
||||
20000 Ephemeral 9 0.2% 3854 428 484
|
||||
22955 Ephemeral 9 0.2% 3852 428 428
|
||||
22793 Ephemeral 9 0.2% 3843 427 427
|
||||
30315 User status 8 0.2% 4604 576 926
|
||||
20387 Ephemeral 8 0.2% 4112 514 514
|
||||
7368 Unknown 8 0.2% 8309 1039 1041
|
||||
4004 Unknown 8 0.2% 9352 1169 1169
|
||||
443 Unknown 8 0.2% 8928 1116 1116
|
||||
11998 Unknown 7 0.1% 3255 465 465
|
||||
10100 Unknown 7 0.1% 11851 1693 3825
|
||||
22456 Ephemeral 7 0.1% 3290 470 470
|
||||
30089 Chunked data 7 0.1% 157322 22475 44372
|
||||
22737 Ephemeral 7 0.1% 4669 667 707
|
||||
23337 Ephemeral 7 0.1% 3557 508 509
|
||||
30515 Addressable 7 0.1% 18032 2576 2576
|
||||
30311 Addressable 6 0.1% 5818 970 1197
|
||||
1985 Unknown 6 0.1% 2860 477 482
|
||||
22859 Ephemeral 5 0.1% 8606 1721 2195
|
||||
4 Encrypted DM 5 0.1% 3222 644 722
|
||||
10011 Unknown 5 0.1% 2027 405 431
|
||||
22764 Ephemeral 4 0.1% 1712 428 428
|
||||
22777 Ephemeral 4 0.1% 2790 698 698
|
||||
4244 Unknown 4 0.1% 2256 564 564
|
||||
30023 Long-form article 4 0.1% 22789 5697 6817
|
||||
9735 Zap receipt 4 0.1% 7033 1758 1805
|
||||
20333 Ephemeral 4 0.1% 3188 797 798
|
||||
3 Follow list 3 0.1% 26232 8744 14166
|
||||
38503 Addressable 3 0.1% 1655 552 552
|
||||
10050 DM relays 3 0.1% 1411 470 511
|
||||
21617 Ephemeral 3 0.1% 1485 495 495
|
||||
1984 Report 3 0.1% 1986 662 662
|
||||
3927 Unknown 3 0.1% 1599 533 533
|
||||
3434 Unknown 3 0.1% 1907 636 665
|
||||
22514 Ephemeral 2 0.0% 856 428 428
|
||||
33334 Addressable 2 0.0% 1662 831 831
|
||||
38500 Addressable 2 0.0% 1424 712 713
|
||||
22526 Ephemeral 2 0.0% 860 430 430
|
||||
30380 Addressable 2 0.0% 908 454 454
|
||||
23194 NWC request 2 0.0% 1020 510 510
|
||||
23042 Ephemeral 2 0.0% 858 429 429
|
||||
38385 Addressable 2 0.0% 2692 1346 1478
|
||||
30443 Addressable 2 0.0% 2369 1184 1219
|
||||
22747 Ephemeral 2 0.0% 2064 1032 1288
|
||||
4245 Unknown 2 0.0% 888 444 444
|
||||
1111 Comment 2 0.0% 1936 968 981
|
||||
38383 Addressable 2 0.0% 1439 720 720
|
||||
4243 Unknown 2 0.0% 1128 564 564
|
||||
38225 Addressable 1 0.0% 978 978 978
|
||||
30618 Addressable 1 0.0% 733 733 733
|
||||
31510 Addressable 1 0.0% 981 981 981
|
||||
30617 Addressable 1 0.0% 1089 1089 1089
|
||||
1077 Unknown 1 0.0% 607 607 607
|
||||
20201 Ephemeral 1 0.0% 491 491 491
|
||||
20200 Ephemeral 1 0.0% 491 491 491
|
||||
1078 Unknown 1 0.0% 14173 14173 14173
|
||||
6300 Unknown 1 0.0% 3698 3698 3698
|
||||
11316 Unknown 1 0.0% 791 791 791
|
||||
11317 Unknown 1 0.0% 2873 2873 2873
|
||||
17 Unknown 1 0.0% 610 610 610
|
||||
23059 Ephemeral 1 0.0% 429 429 429
|
||||
22806 Ephemeral 1 0.0% 1520 1520 1520
|
||||
22120 Ephemeral 1 0.0% 1127 1127 1127
|
||||
13196 Unknown 1 0.0% 656 656 656
|
||||
24913 Ephemeral 1 0.0% 431 431 431
|
||||
12222 Unknown 1 0.0% 579 579 579
|
||||
1040 Unknown 1 0.0% 1048 1048 1048
|
||||
22119 Ephemeral 1 0.0% 845 845 845
|
||||
10312 Unknown 1 0.0% 472 472 472
|
||||
3079 Unknown 1 0.0% 909 909 909
|
||||
30000 Addressable 1 0.0% 594 594 594
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 10:25:47 2026
|
||||
# Config: cache_all_test_config.jsonc
|
||||
# Duration: 120 seconds
|
||||
[2026-08-02 10:26:23] [RELAY] wss://laantungir.net STATUS: ?
|
||||
[2026-08-02 10:26:23] [RELAY] wss://nos.lol STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://nostr-pub.wellorder.net STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://nostr.mom STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://nostr.oxtr.dev STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://offchain.pub STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://premium.primal.net STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://relay.damus.io STATUS: ?
|
||||
[2026-08-02 10:26:23] [RELAY] wss://relay.ditto.pub STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://relay.divine.video STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://relay.momostr.pink STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://relay.mostr.pub STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://relay.nostrplebs.com STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://relay.primal.net STATUS: connected
|
||||
[2026-08-02 10:26:23] [RELAY] wss://theforest.nostr1.com STATUS: connected
|
||||
[2026-08-02 10:26:59] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 10:26:59] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 10:27:59] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 10:27:59] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 10:28:09] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 10:28:10] [RELAY] wss://nos.lol CONNECTED
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 5m 0s
|
||||
Config: cache_all_test_config.jsonc
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 14714
|
||||
Total bytes: 20163747 (19.23 MB)
|
||||
Avg event size: 1370 bytes
|
||||
Max event: 51791 bytes (kind 30078)
|
||||
Unique pubkeys: 3435
|
||||
Relays contacted: 24
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://relay.primal.net 2820 0 0 0 0 2 OK
|
||||
wss://nos.lol 2964 0 0 0 0 3 OK
|
||||
wss://relay.damus.io 1999 0 0 0 0 0 OK
|
||||
wss://relay.ditto.pub 2049 0 0 0 0 0 OK
|
||||
wss://nostr.land 0 0 0 0 0 0 DOWN
|
||||
wss://nostr.wine 0 0 0 0 0 0 DOWN
|
||||
wss://nostr.oxtr.dev 599 0 0 0 0 1 OK
|
||||
wss://spatia-arcana.com/inbox 0 0 0 0 0 0 DOWN
|
||||
wss://nostrelites.org 0 0 0 0 0 0 DOWN
|
||||
wss://offchain.pub 1431 0 0 0 0 0 OK
|
||||
wss://relay.nostr.band 0 0 0 0 0 0 DOWN
|
||||
wss://premium.primal.net 7 0 0 0 0 0 OK
|
||||
wss://nostr.mom 412 0 0 0 0 0 OK
|
||||
wss://relay.mostr.pub 2134 0 0 0 0 1 OK
|
||||
wss://relay.divine.video 14 0 0 0 0 0 OK
|
||||
wss://relay.nostrplebs.com 4 0 0 0 0 0 OK
|
||||
wss://eden.nostr.land 0 0 0 0 0 0 DOWN
|
||||
wss://theforest.nostr1.com 67 0 0 0 0 0 OK
|
||||
wss://nostr-pub.wellorder.net 214 0 0 0 0 0 OK
|
||||
wss://devrelay.azzamo.net 0 0 0 0 0 0 DOWN
|
||||
wss://relay.noderunners.network 0 0 0 0 0 0 OK
|
||||
wss://relay.shosho.live 0 0 0 0 0 0 DOWN
|
||||
wss://relay.nostrcheck.me 0 0 0 0 0 0 DOWN
|
||||
wss://basspistol.org 0 0 0 0 0 0 DOWN
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
21059 Gift wrap (NIP-59) 2477 16.8% 8220486 3319 19622
|
||||
30382 Addressable 1558 10.6% 708564 455 498
|
||||
5 Deletion 1219 8.3% 542263 445 1404
|
||||
22639 Ephemeral 607 4.1% 467729 771 1230
|
||||
20001 Ephemeral (key xchg) 519 3.5% 251716 485 1431
|
||||
22551 Ephemeral 479 3.3% 205970 430 430
|
||||
30078 App data 432 2.9% 3024405 7001 51791
|
||||
24747 Ephemeral 317 2.2% 188378 594 650
|
||||
22734 Ephemeral 315 2.1% 134505 427 427
|
||||
22668 Ephemeral 307 2.1% 131703 429 429
|
||||
1 Text note 307 2.1% 270378 881 3665
|
||||
0 Profile metadata 300 2.0% 260832 869 9187
|
||||
22850 Ephemeral 242 1.6% 104060 430 430
|
||||
38501 App data (btc) 241 1.6% 178603 741 744
|
||||
22912 Ephemeral 238 1.6% 101864 428 428
|
||||
4515 Unknown 225 1.5% 376537 1673 6028
|
||||
10002 Relay list 211 1.4% 309808 1468 42385
|
||||
24133 Ephemeral 193 1.3% 237962 1233 14162
|
||||
22951 Ephemeral 179 1.2% 170939 955 2204
|
||||
22870 Ephemeral 172 1.2% 165571 963 2202
|
||||
25555 Ephemeral 157 1.1% 776467 4946 16603
|
||||
37195 Addressable 142 1.0% 107593 758 869
|
||||
21050 Ephemeral 141 1.0% 136906 971 2558
|
||||
6 Repost 139 0.9% 113883 819 4053
|
||||
7 Reaction 116 0.8% 65547 565 786
|
||||
22832 Ephemeral 112 0.8% 48745 435 446
|
||||
22690 Ephemeral 109 0.7% 46870 430 430
|
||||
30383 Addressable 100 0.7% 53571 536 543
|
||||
22713 Ephemeral 98 0.7% 41994 429 430
|
||||
22601 Ephemeral 93 0.6% 39804 428 428
|
||||
25050 Ephemeral 87 0.6% 38343 441 465
|
||||
1059 Gift wrap seal 84 0.6% 158090 1882 5285
|
||||
22699 Ephemeral 83 0.6% 55625 670 1872
|
||||
22655 Ephemeral 80 0.5% 34240 428 428
|
||||
22917 Ephemeral 75 0.5% 67279 897 1166
|
||||
22676 Ephemeral 72 0.5% 30744 427 427
|
||||
29333 Ephemeral 70 0.5% 34440 492 492
|
||||
22918 Ephemeral 67 0.5% 65746 981 1876
|
||||
20787 Ephemeral 62 0.4% 84460 1362 2478
|
||||
22456 Ephemeral 61 0.4% 29310 480 790
|
||||
22808 Ephemeral 59 0.4% 25296 429 429
|
||||
24242 Ephemeral 57 0.4% 33003 579 579
|
||||
22816 Ephemeral 56 0.4% 24024 429 429
|
||||
22603 Ephemeral 55 0.4% 23430 426 426
|
||||
22743 Ephemeral 55 0.4% 23540 428 428
|
||||
22693 Ephemeral 54 0.4% 23058 427 427
|
||||
22575 Ephemeral 54 0.4% 22950 425 425
|
||||
23334 Ephemeral 53 0.4% 22843 431 431
|
||||
13194 NWC info 52 0.4% 26592 511 514
|
||||
22751 Ephemeral 51 0.3% 21726 426 426
|
||||
22949 Ephemeral 50 0.3% 21450 429 429
|
||||
11998 Unknown 50 0.3% 23202 464 465
|
||||
24421 Ephemeral 48 0.3% 24795 517 525
|
||||
22236 Ephemeral 47 0.3% 37103 789 814
|
||||
22484 Ephemeral 47 0.3% 42919 913 1165
|
||||
3927 Unknown 45 0.3% 23985 533 533
|
||||
23003 Ephemeral 45 0.3% 19260 428 428
|
||||
22774 Ephemeral 45 0.3% 19260 428 428
|
||||
31990 App handler info 44 0.3% 40657 924 1465
|
||||
5300 Unknown 43 0.3% 25958 604 701
|
||||
20387 Ephemeral 40 0.3% 20560 514 514
|
||||
20000 Ephemeral 38 0.3% 15672 412 487
|
||||
38502 Addressable 38 0.3% 14630 385 385
|
||||
22507 Ephemeral 38 0.3% 34749 914 1167
|
||||
445 Encrypted group msg 37 0.3% 62402 1687 4130
|
||||
22698 Ephemeral 34 0.2% 31371 923 1674
|
||||
4 Encrypted DM 33 0.2% 44743 1356 17018
|
||||
30315 User status 31 0.2% 20374 657 1166
|
||||
1985 Label 31 0.2% 28905 932 4831
|
||||
22859 Ephemeral 31 0.2% 30700 990 2195
|
||||
22613 Ephemeral 31 0.2% 21415 691 694
|
||||
20004 Ephemeral 29 0.2% 15525 535 549
|
||||
7368 Unknown 27 0.2% 28042 1039 1041
|
||||
30091 Addressable 27 0.2% 16620 616 629
|
||||
30088 Addressable 27 0.2% 50292 1863 1871
|
||||
22598 Ephemeral 27 0.2% 23198 859 1162
|
||||
22955 Ephemeral 25 0.2% 10700 428 428
|
||||
4004 Unknown 25 0.2% 29225 1169 1169
|
||||
22793 Ephemeral 25 0.2% 10675 427 427
|
||||
22922 Ephemeral 25 0.2% 10750 430 430
|
||||
22795 Ephemeral 25 0.2% 10725 429 429
|
||||
10100 Unknown 24 0.2% 39530 1647 3825
|
||||
22764 Ephemeral 22 0.1% 9416 428 428
|
||||
30089 Chunked data 18 0.1% 260436 14469 44372
|
||||
30311 Addressable 18 0.1% 18058 1003 1197
|
||||
20333 Ephemeral 18 0.1% 14340 797 798
|
||||
443 Unknown 18 0.1% 20088 1116 1116
|
||||
38383 Addressable 18 0.1% 13557 753 972
|
||||
22777 Ephemeral 16 0.1% 12435 777 1159
|
||||
30023 Long-form article 16 0.1% 92998 5812 8050
|
||||
4244 Unknown 15 0.1% 8460 564 564
|
||||
30515 Addressable 14 0.1% 36064 2576 2576
|
||||
22967 Ephemeral 13 0.1% 5603 431 431
|
||||
10011 Unknown 13 0.1% 5283 406 431
|
||||
3 Follow list 12 0.1% 97388 8116 24970
|
||||
38503 Addressable 12 0.1% 6624 552 553
|
||||
1077 Unknown 12 0.1% 7284 607 607
|
||||
22550 Ephemeral 12 0.1% 5112 426 426
|
||||
9735 Zap receipt 12 0.1% 21551 1796 1963
|
||||
22591 Ephemeral 11 0.1% 4686 426 426
|
||||
22830 Ephemeral 11 0.1% 8707 792 1168
|
||||
23337 Ephemeral 11 0.1% 5589 508 509
|
||||
38385 Addressable 9 0.1% 12290 1366 1478
|
||||
10050 DM relays 9 0.1% 4160 462 511
|
||||
39101 Addressable 8 0.1% 4264 533 533
|
||||
31510 Addressable 8 0.1% 7834 979 982
|
||||
1111 Comment 8 0.1% 9909 1239 1706
|
||||
1002 Unknown 7 0.0% 6647 950 1009
|
||||
22737 Ephemeral 7 0.0% 4669 667 707
|
||||
33334 Addressable 6 0.0% 4986 831 831
|
||||
38384 Addressable 6 0.0% 4458 743 743
|
||||
20384 Ephemeral 6 0.0% 3834 639 639
|
||||
22526 Ephemeral 6 0.0% 2580 430 430
|
||||
30443 Addressable 6 0.0% 7288 1215 1260
|
||||
3434 Unknown 6 0.0% 3902 650 665
|
||||
21617 Ephemeral 6 0.0% 2970 495 495
|
||||
38500 Addressable 6 0.0% 4272 712 713
|
||||
30380 Addressable 6 0.0% 2724 454 454
|
||||
22514 Ephemeral 5 0.0% 2140 428 428
|
||||
4245 Unknown 5 0.0% 2220 444 444
|
||||
4243 Unknown 5 0.0% 2820 564 564
|
||||
6300 Unknown 5 0.0% 19347 3869 4596
|
||||
30000 Follow sets 5 0.0% 3005 601 823
|
||||
22611 Ephemeral 5 0.0% 2130 426 426
|
||||
38225 Addressable 5 0.0% 4929 986 993
|
||||
23042 Ephemeral 5 0.0% 2145 429 429
|
||||
14 Unknown 4 0.0% 5446 1362 1550
|
||||
23059 Ephemeral 4 0.0% 2853 713 1162
|
||||
3079 Unknown 4 0.0% 3636 909 909
|
||||
1984 Report 4 0.0% 2648 662 662
|
||||
23194 NWC request 4 0.0% 2040 510 510
|
||||
21060 Ephemeral 4 0.0% 2280 570 570
|
||||
30080 Addressable 4 0.0% 3763 941 986
|
||||
31234 Addressable 4 0.0% 4512 1128 1856
|
||||
10003 Bookmarks 3 0.0% 10518 3506 3506
|
||||
1632 Unknown 3 0.0% 2187 729 729
|
||||
22120 Ephemeral 3 0.0% 3229 1076 1127
|
||||
1000 Unknown 3 0.0% 5178 1726 1734
|
||||
22119 Ephemeral 3 0.0% 2537 846 846
|
||||
11317 Unknown 2 0.0% 5746 2873 2873
|
||||
11316 Unknown 2 0.0% 1582 791 791
|
||||
30617 Addressable 2 0.0% 2178 1089 1089
|
||||
30618 Addressable 2 0.0% 1466 733 733
|
||||
17 External reaction 2 0.0% 1220 610 610
|
||||
31991 Addressable 2 0.0% 922 461 461
|
||||
24913 Ephemeral 2 0.0% 862 431 431
|
||||
31985 Addressable 2 0.0% 1267 634 667
|
||||
1060 Gift wrap (alt) 2 0.0% 2268 1134 1134
|
||||
22806 Ephemeral 2 0.0% 3040 1520 1520
|
||||
31339 Addressable 2 0.0% 2940 1470 1470
|
||||
30090 Addressable 2 0.0% 3030 1515 1515
|
||||
10000 Mute list 2 0.0% 1963 982 1034
|
||||
30087 Addressable 2 0.0% 14650 7325 7325
|
||||
10312 Unknown 2 0.0% 963 482 491
|
||||
30815 Addressable 2 0.0% 75068 37534 37534
|
||||
20200 Ephemeral 2 0.0% 982 491 491
|
||||
20201 Ephemeral 2 0.0% 982 491 491
|
||||
22747 Ephemeral 2 0.0% 2064 1032 1288
|
||||
30787 Addressable 1 0.0% 1370 1370 1370
|
||||
1078 Unknown 1 0.0% 14173 14173 14173
|
||||
13196 Unknown 1 0.0% 656 656 656
|
||||
7403 Unknown 1 0.0% 491 491 491
|
||||
15129 Unknown 1 0.0% 455 455 455
|
||||
12222 Unknown 1 0.0% 579 579 579
|
||||
10030 Emoji list 1 0.0% 405 405 405
|
||||
38111 Addressable 1 0.0% 748 748 748
|
||||
15750 Unknown 1 0.0% 616 616 616
|
||||
30421 Addressable 1 0.0% 995 995 995
|
||||
33333 Addressable 1 0.0% 2346 2346 2346
|
||||
30079 Addressable 1 0.0% 875 875 875
|
||||
39019 Addressable 1 0.0% 961 961 961
|
||||
39015 Addressable 1 0.0% 696 696 696
|
||||
5555 Unknown 1 0.0% 732 732 732
|
||||
34235 Addressable 1 0.0% 1071 1071 1071
|
||||
1040 Unknown 1 0.0% 1048 1048 1048
|
||||
31000 Addressable 1 0.0% 616 616 616
|
||||
10063 Unknown 1 0.0% 627 627 627
|
||||
30554 Addressable 1 0.0% 609 609 609
|
||||
25195 Ephemeral 1 0.0% 678 678 678
|
||||
25196 Ephemeral 1 0.0% 1362 1362 1362
|
||||
30213 Addressable 1 0.0% 632 632 632
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 10:18:44 2026
|
||||
# Config: cache_all_test_config.jsonc
|
||||
# Duration: 300 seconds
|
||||
[2026-08-02 10:25:43] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://relay.damus.io CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://relay.ditto.pub CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://nostr.oxtr.dev CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://offchain.pub CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://nostr.mom CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://relay.divine.video CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://relay.nostrplebs.com CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://theforest.nostr1.com CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://nostr-pub.wellorder.net CONNECTED
|
||||
[2026-08-02 10:25:43] [RELAY] wss://relay.noderunners.network CONNECTED
|
||||
[2026-08-02 10:26:30] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 10:26:30] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 10:27:00] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 10:27:00] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 10:28:30] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 10:28:30] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 10:28:55] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 10:28:55] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 10:29:49] [RELAY] wss://relay.mostr.pub DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 10:29:50] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 10:29:50] [RELAY] wss://nostr.oxtr.dev DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 10:29:51] [RELAY] wss://nostr.oxtr.dev CONNECTED
|
||||
[2026-08-02 10:30:00] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 10:30:00] [RELAY] wss://nos.lol CONNECTED
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 0m 32s
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 1485
|
||||
Total bytes: 1812166 (1.73 MB)
|
||||
Avg event size: 1220 bytes
|
||||
Max event: 44546 bytes (kind 31234)
|
||||
Unique pubkeys: 511
|
||||
Relays: 15
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://laantungir.net 0 0 0 0 0 0 DOWN
|
||||
wss://nos.lol 247 0 0 0 0 0 OK
|
||||
wss://nostr-pub.wellorder.net 37 0 0 0 0 0 OK
|
||||
wss://nostr.mom 38 0 0 0 0 0 OK
|
||||
wss://nostr.oxtr.dev 36 0 0 0 0 0 OK
|
||||
wss://offchain.pub 113 0 0 0 0 0 OK
|
||||
wss://premium.primal.net 1 0 0 0 0 0 OK
|
||||
wss://relay.damus.io 194 0 0 0 0 0 OK
|
||||
wss://relay.ditto.pub 277 0 0 0 0 1 OK
|
||||
wss://relay.divine.video 2 0 0 0 0 0 OK
|
||||
wss://relay.momostr.pink 27 0 0 0 0 0 OK
|
||||
wss://relay.mostr.pub 148 0 0 0 0 0 OK
|
||||
wss://relay.nostrplebs.com 0 0 0 0 0 0 OK
|
||||
wss://relay.primal.net 360 0 0 0 0 0 OK
|
||||
wss://theforest.nostr1.com 5 0 0 0 0 0 OK
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
21059 Gift wrap (NIP-59) 184 12.4% 623532 3389 5314
|
||||
22591 Ephemeral 139 9.4% 107560 774 1223
|
||||
30382 Addressable 119 8.0% 53663 451 458
|
||||
30383 Addressable 119 8.0% 53605 450 536
|
||||
5 Deletion 91 6.1% 39950 439 624
|
||||
30078 App data 54 3.6% 179695 3328 14343
|
||||
20001 Ephemeral 49 3.3% 35635 727 1871
|
||||
0 Profile metadata 48 3.2% 39906 831 1468
|
||||
22668 Ephemeral 48 3.2% 20592 429 429
|
||||
1 Text note 45 3.0% 38547 857 2413
|
||||
22734 Ephemeral 26 1.8% 11102 427 427
|
||||
4515 Unknown 26 1.8% 38218 1470 2956
|
||||
10002 Relay list 25 1.7% 11707 468 565
|
||||
22850 Ephemeral 24 1.6% 10320 430 430
|
||||
7 Reaction 24 1.6% 13528 564 780
|
||||
22551 Ephemeral 24 1.6% 10320 430 430
|
||||
31991 Addressable 20 1.3% 9220 461 461
|
||||
38501 Addressable 18 1.2% 13341 741 744
|
||||
22663 Ephemeral 17 1.1% 7276 428 428
|
||||
25555 Ephemeral 15 1.0% 90493 6033 16887
|
||||
22912 Ephemeral 13 0.9% 5564 428 428
|
||||
1059 Gift wrap seal 13 0.9% 23775 1829 1883
|
||||
22832 Ephemeral 12 0.8% 5233 436 446
|
||||
22690 Ephemeral 11 0.7% 4730 430 430
|
||||
22545 Ephemeral 11 0.7% 4697 427 427
|
||||
25050 Ephemeral 10 0.7% 4394 439 465
|
||||
37195 Addressable 10 0.7% 7494 749 771
|
||||
22601 Ephemeral 10 0.7% 4280 428 428
|
||||
22795 Ephemeral 10 0.7% 11639 1164 1487
|
||||
22891 Ephemeral 9 0.6% 13331 1481 1490
|
||||
22655 Ephemeral 9 0.6% 3852 428 428
|
||||
22911 Ephemeral 9 0.6% 13328 1481 1487
|
||||
24133 Ephemeral 9 0.6% 8250 917 1534
|
||||
13194 NWC info 8 0.5% 4112 514 514
|
||||
22647 Ephemeral 8 0.5% 3416 427 427
|
||||
22695 Ephemeral 7 0.5% 10339 1477 1481
|
||||
22653 Ephemeral 7 0.5% 10368 1481 1487
|
||||
22455 Ephemeral 7 0.5% 10339 1477 1485
|
||||
22543 Ephemeral 7 0.5% 10354 1479 1487
|
||||
30315 User status 7 0.5% 2714 388 398
|
||||
22676 Ephemeral 6 0.4% 2562 427 427
|
||||
22575 Ephemeral 6 0.4% 2550 425 425
|
||||
22689 Ephemeral 6 0.4% 8851 1475 1484
|
||||
22913 Ephemeral 6 0.4% 2586 431 431
|
||||
22774 Ephemeral 6 0.4% 2568 428 428
|
||||
24242 Ephemeral 6 0.4% 3474 579 579
|
||||
22808 Ephemeral 6 0.4% 2574 429 429
|
||||
22842 Ephemeral 6 0.4% 8891 1482 1488
|
||||
22603 Ephemeral 5 0.3% 2130 426 426
|
||||
6 Repost 5 0.3% 10814 2163 7298
|
||||
31990 App handler info 5 0.3% 4305 861 1321
|
||||
22384 Ephemeral 5 0.3% 2130 426 426
|
||||
22699 Ephemeral 5 0.3% 2140 428 428
|
||||
22613 Ephemeral 5 0.3% 3443 689 691
|
||||
38502 Addressable 5 0.3% 1925 385 385
|
||||
23003 Ephemeral 5 0.3% 2140 428 428
|
||||
22743 Ephemeral 5 0.3% 2140 428 428
|
||||
29333 Ephemeral 5 0.3% 2460 492 492
|
||||
20004 Ephemeral 4 0.3% 1800 450 549
|
||||
4 Encrypted DM 4 0.3% 3072 768 826
|
||||
20387 Ephemeral 4 0.3% 2056 514 514
|
||||
22816 Ephemeral 4 0.3% 1716 429 429
|
||||
20000 Ephemeral 4 0.3% 1872 468 628
|
||||
22934 Ephemeral 3 0.2% 5535 1845 1846
|
||||
1985 Unknown 2 0.1% 948 474 474
|
||||
31234 Addressable 2 0.1% 89092 44546 44546
|
||||
10777 Unknown 2 0.1% 976 488 488
|
||||
4004 Unknown 2 0.1% 2338 1169 1169
|
||||
9735 Zap receipt 2 0.1% 3926 1963 2135
|
||||
1000 Unknown 2 0.1% 3415 1708 1712
|
||||
25195 Ephemeral 2 0.1% 1356 678 678
|
||||
30311 Addressable 2 0.1% 2210 1105 1198
|
||||
25196 Ephemeral 2 0.1% 3576 1788 2214
|
||||
1040 Unknown 2 0.1% 1920 960 960
|
||||
38383 Addressable 2 0.1% 1532 766 815
|
||||
30515 Addressable 2 0.1% 5152 2576 2576
|
||||
30091 Addressable 2 0.1% 1221 610 611
|
||||
30088 Addressable 2 0.1% 3717 1858 1859
|
||||
21617 Ephemeral 1 0.1% 494 494 494
|
||||
30380 Addressable 1 0.1% 454 454 454
|
||||
22611 Ephemeral 1 0.1% 426 426 426
|
||||
30079 Addressable 1 0.1% 875 875 875
|
||||
22767 Ephemeral 1 0.1% 429 429 429
|
||||
38500 Addressable 1 0.1% 711 711 711
|
||||
30312 Addressable 1 0.1% 461 461 461
|
||||
7368 Unknown 1 0.1% 1039 1039 1039
|
||||
22967 Ephemeral 1 0.1% 431 431 431
|
||||
39101 Addressable 1 0.1% 533 533 533
|
||||
445 Encrypted group msg 1 0.1% 4130 4130 4130
|
||||
10000 Mute list 1 0.1% 1722 1722 1722
|
||||
30617 Addressable 1 0.1% 1089 1089 1089
|
||||
22526 Ephemeral 1 0.1% 430 430 430
|
||||
20787 Ephemeral 1 0.1% 926 926 926
|
||||
443 Unknown 1 0.1% 800 800 800
|
||||
16 Generic repost 1 0.1% 780 780 780
|
||||
10011 Unknown 1 0.1% 397 397 397
|
||||
22679 Ephemeral 1 0.1% 693 693 693
|
||||
23042 Ephemeral 1 0.1% 429 429 429
|
||||
22514 Ephemeral 1 0.1% 428 428 428
|
||||
30023 Long-form article 1 0.1% 8164 8164 8164
|
||||
5300 Unknown 1 0.1% 630 630 630
|
||||
22605 Ephemeral 1 0.1% 692 692 692
|
||||
34237 Addressable 1 0.1% 418 418 418
|
||||
30618 Addressable 1 0.1% 733 733 733
|
||||
38421 Addressable 1 0.1% 1069 1069 1069
|
||||
10100 Unknown 1 0.1% 1036 1036 1036
|
||||
30080 Addressable 1 0.1% 925 925 925
|
||||
38385 Addressable 1 0.1% 1214 1214 1214
|
||||
38225 Addressable 1 0.1% 1012 1012 1012
|
||||
11998 Unknown 1 0.1% 465 465 465
|
||||
22236 Ephemeral 1 0.1% 747 747 747
|
||||
22823 Ephemeral 1 0.1% 1852 1852 1852
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 11:20:28 2026
|
||||
# Config: cache_all_test_config.jsonc
|
||||
# Duration: 86400 seconds
|
||||
[2026-08-02 11:21:06] [RELAY] wss://laantungir.net STATUS: ?
|
||||
[2026-08-02 11:21:06] [RELAY] wss://nos.lol STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://nostr-pub.wellorder.net STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://nostr.mom STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://nostr.oxtr.dev STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://offchain.pub STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://premium.primal.net STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://relay.damus.io STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://relay.ditto.pub STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://relay.divine.video STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://relay.momostr.pink STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://relay.mostr.pub STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://relay.nostrplebs.com STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://relay.primal.net STATUS: connected
|
||||
[2026-08-02 11:21:06] [RELAY] wss://theforest.nostr1.com STATUS: connected
|
||||
[2026-08-02 11:21:26] [RELAY] wss://relay.ditto.pub DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:21:26] [RELAY] wss://relay.ditto.pub CONNECTED
|
||||
|
||||
@@ -0,0 +1,423 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 40m 5s
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 40082
|
||||
Total bytes: 52985157 (50.53 MB)
|
||||
Avg event size: 1322 bytes
|
||||
Max event: 58662 bytes (kind 3)
|
||||
Unique pubkeys: 7202
|
||||
Relays: 15
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://laantungir.net 0 0 0 0 0 0 DOWN
|
||||
wss://nos.lol 7469 0 0 0 0 11 OK
|
||||
wss://nostr-pub.wellorder.net 697 0 0 0 0 0 OK
|
||||
wss://nostr.mom 1389 0 0 0 0 0 OK
|
||||
wss://nostr.oxtr.dev 1009 0 0 0 0 0 OK
|
||||
wss://offchain.pub 4338 0 0 0 0 0 OK
|
||||
wss://premium.primal.net 226 0 0 0 0 36 OK
|
||||
wss://relay.damus.io 4929 0 0 0 0 6 OK
|
||||
wss://relay.ditto.pub 5951 0 0 0 0 0 OK
|
||||
wss://relay.divine.video 127 0 0 0 0 0 OK
|
||||
wss://relay.momostr.pink 857 0 0 0 0 0 OK
|
||||
wss://relay.mostr.pub 4182 0 0 0 0 1 OK
|
||||
wss://relay.nostrplebs.com 23 0 0 0 0 1 OK
|
||||
wss://relay.primal.net 8596 0 0 0 0 10 OK
|
||||
wss://theforest.nostr1.com 289 0 0 0 0 0 OK
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
21059 Gift wrap (NIP-59) 5631 14.0% 18980562 3371 5314
|
||||
30382 Addressable 4179 10.4% 1900908 455 483
|
||||
22591 Ephemeral 3320 8.3% 2581724 778 1814
|
||||
5 Deletion 2848 7.1% 1264487 444 1659
|
||||
20001 Ephemeral 1602 4.0% 1333680 833 5870
|
||||
1 Text note 1556 3.9% 1359052 873 2843
|
||||
30078 App data 1118 2.8% 4202383 3759 52067
|
||||
22668 Ephemeral 1014 2.5% 435006 429 429
|
||||
24133 Ephemeral 965 2.4% 2468722 2558 19622
|
||||
0 Profile metadata 959 2.4% 865512 903 6506
|
||||
7 Reaction 766 1.9% 465618 608 1403
|
||||
22551 Ephemeral 703 1.8% 305982 435 1819
|
||||
22734 Ephemeral 684 1.7% 292068 427 427
|
||||
38501 Addressable 583 1.5% 432057 741 744
|
||||
22912 Ephemeral 582 1.5% 249096 428 428
|
||||
10002 Relay list 579 1.4% 898767 1552 42385
|
||||
22850 Ephemeral 543 1.4% 233490 430 430
|
||||
37195 Addressable 436 1.1% 329238 755 934
|
||||
25555 Ephemeral 407 1.0% 2047337 5030 16903
|
||||
30383 Addressable 379 0.9% 197360 521 544
|
||||
22832 Ephemeral 342 0.9% 149404 437 446
|
||||
22690 Ephemeral 309 0.8% 132870 430 430
|
||||
22651 Ephemeral 305 0.8% 130235 427 427
|
||||
22236 Ephemeral 301 0.8% 226221 752 815
|
||||
6 Repost 299 0.7% 301866 1010 9866
|
||||
4515 Unknown 291 0.7% 533897 1835 16952
|
||||
22601 Ephemeral 252 0.6% 107856 428 428
|
||||
25050 Ephemeral 233 0.6% 102329 439 465
|
||||
31991 Addressable 229 0.6% 105569 461 461
|
||||
22655 Ephemeral 218 0.5% 93304 428 428
|
||||
29333 Ephemeral 215 0.5% 105780 492 492
|
||||
22795 Ephemeral 188 0.5% 214828 1143 1847
|
||||
22676 Ephemeral 188 0.5% 80276 427 427
|
||||
22808 Ephemeral 178 0.4% 84072 472 1253
|
||||
22384 Ephemeral 175 0.4% 74550 426 426
|
||||
31990 App handler info 167 0.4% 183247 1097 6861
|
||||
22913 Ephemeral 160 0.4% 68960 431 431
|
||||
13194 NWC info 156 0.4% 80184 514 514
|
||||
22603 Ephemeral 155 0.4% 66030 426 426
|
||||
22743 Ephemeral 155 0.4% 66340 428 428
|
||||
22575 Ephemeral 154 0.4% 65450 425 425
|
||||
20000 Ephemeral 151 0.4% 67354 446 1198
|
||||
7368 Unknown 149 0.4% 154743 1039 1059
|
||||
23049 Ephemeral 147 0.4% 63210 430 430
|
||||
24242 Ephemeral 144 0.4% 83376 579 579
|
||||
11998 Unknown 142 0.4% 65790 463 465
|
||||
445 Encrypted group msg 140 0.3% 293740 2098 5194
|
||||
22456 Ephemeral 131 0.3% 63614 486 790
|
||||
20787 Ephemeral 131 0.3% 179206 1368 2478
|
||||
20387 Ephemeral 128 0.3% 65792 514 514
|
||||
22911 Ephemeral 125 0.3% 190126 1521 1849
|
||||
22653 Ephemeral 124 0.3% 188585 1521 1848
|
||||
22455 Ephemeral 124 0.3% 188540 1520 1844
|
||||
22695 Ephemeral 124 0.3% 188335 1519 1850
|
||||
22891 Ephemeral 122 0.3% 185731 1522 1850
|
||||
1059 Gift wrap seal 122 0.3% 235480 1930 5285
|
||||
22543 Ephemeral 122 0.3% 185791 1523 1846
|
||||
22689 Ephemeral 119 0.3% 181177 1522 1845
|
||||
22816 Ephemeral 118 0.3% 50622 429 429
|
||||
22774 Ephemeral 115 0.3% 49220 428 428
|
||||
23003 Ephemeral 113 0.3% 48364 428 428
|
||||
22842 Ephemeral 111 0.3% 169484 1527 1848
|
||||
443 Unknown 111 0.3% 163453 1473 22480
|
||||
23337 Ephemeral 108 0.3% 57242 530 531
|
||||
30315 User status 107 0.3% 66269 619 1166
|
||||
22699 Ephemeral 106 0.3% 48256 455 1505
|
||||
1985 Unknown 104 0.3% 63816 614 4833
|
||||
22663 Ephemeral 101 0.3% 43228 428 428
|
||||
38502 Addressable 101 0.3% 38885 385 385
|
||||
23004 Ephemeral 100 0.2% 43100 431 431
|
||||
4004 Unknown 100 0.2% 116900 1169 1169
|
||||
3 Follow list 96 0.2% 1944563 20256 58662
|
||||
4 Encrypted DM 95 0.2% 95818 1009 17018
|
||||
9735 Zap receipt 94 0.2% 183437 1951 2436
|
||||
22647 Ephemeral 83 0.2% 35441 427 427
|
||||
31234 Addressable 81 0.2% 177493 2191 44546
|
||||
5300 Unknown 80 0.2% 48788 610 744
|
||||
23334 Ephemeral 75 0.2% 33681 449 454
|
||||
10100 Unknown 74 0.2% 110084 1488 3826
|
||||
22613 Ephemeral 74 0.2% 53289 720 1814
|
||||
20004 Ephemeral 71 0.2% 37593 529 549
|
||||
22631 Ephemeral 67 0.2% 61813 923 1822
|
||||
20333 Ephemeral 67 0.2% 53378 797 798
|
||||
22657 Ephemeral 67 0.2% 53820 803 1279
|
||||
10050 DM relays 64 0.2% 27983 437 536
|
||||
22545 Ephemeral 61 0.2% 26047 427 427
|
||||
30023 Long-form article 56 0.1% 369281 6594 16772
|
||||
30311 Addressable 55 0.1% 56530 1028 1198
|
||||
1111 Comment 51 0.1% 72307 1418 2352
|
||||
30166 Addressable 49 0.1% 26188 534 808
|
||||
4244 Unknown 41 0.1% 23124 564 564
|
||||
30088 Addressable 41 0.1% 76377 1863 1871
|
||||
30091 Addressable 40 0.1% 24624 616 629
|
||||
38503 Addressable 40 0.1% 22081 552 553
|
||||
22782 Ephemeral 40 0.1% 36524 913 1167
|
||||
22611 Ephemeral 38 0.1% 16263 428 429
|
||||
22605 Ephemeral 36 0.1% 42806 1189 1849
|
||||
22767 Ephemeral 35 0.1% 15015 429 429
|
||||
22967 Ephemeral 34 0.1% 14654 431 431
|
||||
38383 Addressable 33 0.1% 28002 849 3207
|
||||
10011 Unknown 32 0.1% 13152 411 431
|
||||
8108 Unknown 30 0.1% 39052 1302 1574
|
||||
22623 Ephemeral 30 0.1% 24536 818 1283
|
||||
30089 Chunked data 29 0.1% 370012 12759 44372
|
||||
30515 Addressable 29 0.1% 74704 2576 2576
|
||||
10777 Unknown 26 0.1% 12688 488 488
|
||||
38385 Addressable 26 0.1% 34815 1339 1496
|
||||
22679 Ephemeral 24 0.1% 28787 1199 1852
|
||||
25195 Ephemeral 24 0.1% 14928 622 678
|
||||
21060 Ephemeral 23 0.1% 13110 570 570
|
||||
22738 Ephemeral 23 0.1% 18515 805 1252
|
||||
30380 Addressable 23 0.1% 10442 454 454
|
||||
33334 Addressable 22 0.1% 18282 831 831
|
||||
22547 Ephemeral 22 0.1% 20278 922 1164
|
||||
21617 Ephemeral 21 0.1% 10544 502 517
|
||||
33301 Addressable 20 0.0% 35736 1787 2162
|
||||
38500 Addressable 19 0.0% 13531 712 713
|
||||
38384 Addressable 19 0.0% 14115 743 743
|
||||
22526 Ephemeral 19 0.0% 8170 430 430
|
||||
6300 Unknown 19 0.0% 64041 3371 6898
|
||||
30443 Addressable 19 0.0% 22604 1190 1260
|
||||
22919 Ephemeral 18 0.0% 32466 1804 1849
|
||||
22724 Ephemeral 18 0.0% 13222 735 1253
|
||||
22789 Ephemeral 17 0.0% 28521 1678 3267
|
||||
1002 Unknown 17 0.0% 16010 942 981
|
||||
3434 Unknown 17 0.0% 11585 681 705
|
||||
22507 Ephemeral 16 0.0% 9927 620 1163
|
||||
20384 Ephemeral 16 0.0% 10223 639 639
|
||||
30080 Addressable 16 0.0% 15048 940 987
|
||||
22672 Ephemeral 16 0.0% 24987 1562 1847
|
||||
22844 Ephemeral 15 0.0% 6435 429 429
|
||||
4245 Unknown 15 0.0% 6660 444 444
|
||||
4243 Unknown 15 0.0% 8460 564 564
|
||||
30009 Addressable 15 0.0% 6949 463 479
|
||||
22514 Ephemeral 14 0.0% 5992 428 428
|
||||
14 Unknown 14 0.0% 15322 1094 1551
|
||||
3927 Unknown 14 0.0% 7484 535 544
|
||||
23042 Ephemeral 14 0.0% 6006 429 429
|
||||
10000 Mute list 14 0.0% 32097 2293 8671
|
||||
30618 Addressable 13 0.0% 25947 1996 8739
|
||||
1040 Unknown 13 0.0% 13272 1021 1048
|
||||
31510 Addressable 13 0.0% 12731 979 982
|
||||
30617 Addressable 12 0.0% 13112 1093 1146
|
||||
25196 Ephemeral 12 0.0% 19580 1632 2214
|
||||
38225 Addressable 12 0.0% 11742 978 1006
|
||||
39101 Addressable 11 0.0% 5863 533 533
|
||||
26428 Ephemeral 10 0.0% 8765 876 877
|
||||
30213 Addressable 10 0.0% 6224 622 632
|
||||
26429 Ephemeral 10 0.0% 4910 491 491
|
||||
30000 Addressable 9 0.0% 17509 1945 5660
|
||||
22639 Ephemeral 9 0.0% 3852 428 428
|
||||
31339 Addressable 9 0.0% 13230 1470 1470
|
||||
30312 Addressable 8 0.0% 3555 444 461
|
||||
9321 Unknown 7 0.0% 16541 2363 2363
|
||||
7403 Unknown 7 0.0% 3435 491 491
|
||||
1010 Unknown 7 0.0% 5098 728 748
|
||||
16 Generic repost 7 0.0% 5460 780 780
|
||||
7375 Unknown 7 0.0% 8120 1160 1160
|
||||
22839 Ephemeral 7 0.0% 2996 428 428
|
||||
7376 Unknown 7 0.0% 5817 831 831
|
||||
3079 Unknown 6 0.0% 5454 909 909
|
||||
22658 Ephemeral 6 0.0% 6269 1045 1813
|
||||
30090 Addressable 5 0.0% 7575 1515 1515
|
||||
34236 Addressable 5 0.0% 61577 12315 21112
|
||||
22120 Ephemeral 5 0.0% 5493 1099 1133
|
||||
22119 Ephemeral 5 0.0% 4227 845 846
|
||||
23194 NWC request 5 0.0% 2554 511 534
|
||||
1984 Report 5 0.0% 2714 543 662
|
||||
31000 Addressable 5 0.0% 3024 605 616
|
||||
1078 Unknown 5 0.0% 70534 14107 14226
|
||||
10003 Bookmarks 5 0.0% 15698 3140 4954
|
||||
1000 Unknown 4 0.0% 6474 1618 1782
|
||||
30087 Addressable 4 0.0% 29300 7325 7325
|
||||
38111 Addressable 4 0.0% 2996 749 752
|
||||
25055 Ephemeral 4 0.0% 6286 1572 1788
|
||||
30421 Addressable 4 0.0% 4079 1020 1028
|
||||
30079 Addressable 4 0.0% 3500 875 875
|
||||
30815 Addressable 4 0.0% 150136 37534 37534
|
||||
13302 Unknown 4 0.0% 30097 7524 22303
|
||||
22865 Ephemeral 4 0.0% 2785 696 699
|
||||
10012 Unknown 3 0.0% 1388 463 622
|
||||
39015 Addressable 3 0.0% 2088 696 696
|
||||
30787 Addressable 3 0.0% 4118 1373 1374
|
||||
10001 Pinned notes 3 0.0% 1758 586 586
|
||||
15129 Unknown 3 0.0% 1365 455 455
|
||||
37779 Addressable 3 0.0% 1569 523 523
|
||||
8 Unknown 3 0.0% 1527 509 509
|
||||
30003 Addressable 3 0.0% 1167 389 389
|
||||
31512 Addressable 3 0.0% 10234 3411 3414
|
||||
39050 Addressable 3 0.0% 5529 1843 1843
|
||||
31237 Addressable 3 0.0% 2439 813 821
|
||||
30554 Addressable 3 0.0% 1827 609 609
|
||||
22778 Ephemeral 3 0.0% 4059 1353 1847
|
||||
30402 Addressable 3 0.0% 2036 679 680
|
||||
10063 Unknown 3 0.0% 1639 546 627
|
||||
1631 Unknown 2 0.0% 2620 1310 1310
|
||||
1315 Unknown 2 0.0% 990 495 495
|
||||
22760 Ephemeral 2 0.0% 3624 1812 1814
|
||||
30495 Addressable 2 0.0% 4074 2037 2037
|
||||
10051 Unknown 2 0.0% 878 439 439
|
||||
13196 Unknown 2 0.0% 1312 656 656
|
||||
38421 Addressable 2 0.0% 2140 1070 1070
|
||||
23333 Ephemeral 2 0.0% 1636 818 818
|
||||
2333 Unknown 2 0.0% 1812 906 906
|
||||
24913 Ephemeral 2 0.0% 1164 582 582
|
||||
22882 Ephemeral 2 0.0% 2000 1000 1164
|
||||
22617 Ephemeral 2 0.0% 852 426 426
|
||||
22729 Ephemeral 2 0.0% 1860 930 930
|
||||
22733 Ephemeral 2 0.0% 3330 1665 1848
|
||||
23013 Ephemeral 2 0.0% 2965 1482 1485
|
||||
9 Unknown 2 0.0% 4085 2042 2157
|
||||
31986 Addressable 2 0.0% 1182 591 591
|
||||
1063 File metadata 1 0.0% 909 909 909
|
||||
1060 Unknown 1 0.0% 1207 1207 1207
|
||||
10312 Unknown 1 0.0% 472 472 472
|
||||
37368 Addressable 1 0.0% 1236 1236 1236
|
||||
15750 Unknown 1 0.0% 626 626 626
|
||||
22598 Ephemeral 1 0.0% 1666 1666 1666
|
||||
17375 Unknown 1 0.0% 606 606 606
|
||||
22496 Ephemeral 1 0.0% 1518 1518 1518
|
||||
20200 Ephemeral 1 0.0% 491 491 491
|
||||
39019 Addressable 1 0.0% 961 961 961
|
||||
34238 Addressable 1 0.0% 920 920 920
|
||||
22732 Ephemeral 1 0.0% 1334 1334 1334
|
||||
20201 Ephemeral 1 0.0% 491 491 491
|
||||
12222 Unknown 1 0.0% 579 579 579
|
||||
31337 Addressable 1 0.0% 818 818 818
|
||||
23071 Ephemeral 1 0.0% 1910 1910 1910
|
||||
33333 Addressable 1 0.0% 2346 2346 2346
|
||||
20 Picture 1 0.0% 445 445 445
|
||||
1808 Unknown 1 0.0% 683 683 683
|
||||
30113 Addressable 1 0.0% 770 770 770
|
||||
34235 Addressable 1 0.0% 1501 1501 1501
|
||||
10377 Unknown 1 0.0% 664 664 664
|
||||
11111 Unknown 1 0.0% 382 382 382
|
||||
10133 Unknown 1 0.0% 499 499 499
|
||||
30081 Addressable 1 0.0% 1370 1370 1370
|
||||
10009 Unknown 1 0.0% 422 422 422
|
||||
30005 Addressable 1 0.0% 9671 9671 9671
|
||||
10443 Unknown 1 0.0% 676 676 676
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 11:21:56 2026
|
||||
# Config: cache_all_test_config.jsonc
|
||||
# Duration: 86400 seconds
|
||||
[2026-08-02 11:22:33] [RELAY] wss://laantungir.net STATUS: ?
|
||||
[2026-08-02 11:22:33] [RELAY] wss://nos.lol STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://nostr-pub.wellorder.net STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://nostr.mom STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://nostr.oxtr.dev STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://offchain.pub STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://premium.primal.net STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://relay.damus.io STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://relay.ditto.pub STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://relay.divine.video STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://relay.momostr.pink STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://relay.mostr.pub STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://relay.nostrplebs.com STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://relay.primal.net STATUS: connected
|
||||
[2026-08-02 11:22:33] [RELAY] wss://theforest.nostr1.com STATUS: connected
|
||||
[2026-08-02 11:23:06] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:23:06] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:23:07] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:23:08] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:23:08] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:23:09] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:23:38] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 11:23:38] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 11:23:45] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 11:23:45] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 11:24:08] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 11:24:08] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 11:26:10] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:26:10] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:26:14] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:26:15] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:26:15] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 11:26:15] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 11:26:28] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:26:29] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:26:38] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 11:26:38] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 11:26:43] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:26:43] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:26:44] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:26:45] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:26:47] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:26:48] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:26:49] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:26:50] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:26:53] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:26:53] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:27:17] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:27:17] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 11:27:31] [RELAY] wss://relay.mostr.pub DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:27:32] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 11:27:58] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:27:58] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 11:28:10] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:28:11] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:28:12] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:28:12] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:28:15] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 11:28:15] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 11:28:15] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:28:16] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:28:17] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:28:18] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:28:20] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:28:20] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:28:22] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:28:22] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:28:24] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:28:25] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:28:44] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:28:45] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:28:45] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 11:28:45] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 11:28:46] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:28:47] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:28:51] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:28:51] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:28:56] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:28:56] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:29:28] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 11:29:28] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 11:29:59] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:00] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:01] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:01] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:02] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:03] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:03] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:04] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:06] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:07] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:07] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:08] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:10] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:11] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:14] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:15] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:17] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:18] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:18] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:19] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:19] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 11:30:19] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 11:30:20] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:20] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:22] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:23] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:25] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:30:26] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 11:30:58] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 11:30:58] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 11:31:19] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 11:31:19] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 11:31:28] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 11:31:28] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 11:32:19] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 11:32:19] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 11:32:28] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 11:32:28] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 11:32:46] [RELAY] wss://relay.damus.io DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:32:52] [RELAY] wss://relay.damus.io CONNECTED
|
||||
[2026-08-02 11:33:03] [RELAY] wss://relay.damus.io DISCONNECTED: Failed to create WebSocket client for relay wss://relay.damus.io
|
||||
[2026-08-02 11:33:13] [RELAY] wss://relay.damus.io CONNECTED
|
||||
[2026-08-02 11:33:19] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 11:33:19] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 11:33:54] [RELAY] wss://relay.damus.io DISCONNECTED: Failed to create WebSocket client for relay wss://relay.damus.io
|
||||
[2026-08-02 11:33:54] [RELAY] wss://relay.damus.io CONNECTED
|
||||
[2026-08-02 11:34:12] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 11:34:12] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 11:34:24] [RELAY] wss://relay.damus.io DISCONNECTED:
|
||||
[2026-08-02 11:34:24] [RELAY] wss://relay.damus.io CONNECTED
|
||||
[2026-08-02 11:35:13] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 11:35:13] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 11:35:24] [RELAY] wss://relay.damus.io DISCONNECTED:
|
||||
[2026-08-02 11:35:24] [RELAY] wss://relay.damus.io CONNECTED
|
||||
[2026-08-02 11:36:18] [RELAY] wss://relay.damus.io DISCONNECTED: Failed to create WebSocket client for relay wss://relay.damus.io
|
||||
[2026-08-02 11:36:19] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 11:36:19] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 11:36:28] [RELAY] wss://relay.damus.io CONNECTED
|
||||
[2026-08-02 11:36:49] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 11:36:49] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 11:37:14] [RELAY] wss://relay.nostrplebs.com DISCONNECTED:
|
||||
[2026-08-02 11:37:14] [RELAY] wss://relay.nostrplebs.com CONNECTED
|
||||
[2026-08-02 11:37:19] [RELAY] wss://premium.primal.net DISCONNECTED:
|
||||
[2026-08-02 11:37:19] [RELAY] wss://premium.primal.net CONNECTED
|
||||
|
||||
@@ -0,0 +1,646 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 58m 5s
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 140345
|
||||
Total bytes: 182488517 (174.03 MB)
|
||||
Avg event size: 1300 bytes
|
||||
Max event: 62825 bytes (kind 1)
|
||||
Unique pubkeys: 26918
|
||||
Relays: 15
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://laantungir.net 0 0 0 0 0 0 DOWN
|
||||
wss://nos.lol 25038 0 0 0 0 54 OK
|
||||
wss://nostr-pub.wellorder.net 3608 0 0 0 0 0 OK
|
||||
wss://nostr.mom 8692 0 0 0 0 0 OK
|
||||
wss://nostr.oxtr.dev 4360 0 0 0 0 7 OK
|
||||
wss://offchain.pub 17857 0 0 0 0 0 OK
|
||||
wss://premium.primal.net 171 0 0 0 0 26 OK
|
||||
wss://relay.damus.io 21539 0 0 0 0 0 OK
|
||||
wss://relay.ditto.pub 22251 0 0 0 0 7 OK
|
||||
wss://relay.divine.video 281 0 0 0 0 0 OK
|
||||
wss://relay.momostr.pink 1812 0 0 0 0 7 OK
|
||||
wss://relay.mostr.pub 20917 0 0 0 0 10 OK
|
||||
wss://relay.nostrplebs.com 23 0 0 0 0 0 OK
|
||||
wss://relay.primal.net 12945 0 0 0 0 57 OK
|
||||
wss://theforest.nostr1.com 851 0 0 0 0 0 OK
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
21059 Gift wrap (NIP-59) 22589 16.1% 76886982 3404 22354
|
||||
30382 Addressable 15147 10.8% 6854204 453 484
|
||||
5 Deletion 10634 7.6% 4652532 438 955
|
||||
20001 Ephemeral 4553 3.2% 2990229 657 26578
|
||||
22591 Ephemeral 4464 3.2% 3384073 758 1230
|
||||
1 Text note 4307 3.1% 4175360 969 62825
|
||||
22668 Ephemeral 4214 3.0% 1807801 429 429
|
||||
22466 Ephemeral 3541 2.5% 1519089 429 429
|
||||
30383 Addressable 3125 2.2% 1507650 482 550
|
||||
0 Profile metadata 2878 2.1% 2533064 880 9187
|
||||
22551 Ephemeral 2857 2.0% 1233111 432 1160
|
||||
30078 App data 2566 1.8% 8335901 3249 55090
|
||||
38501 Addressable 2349 1.7% 1740867 741 744
|
||||
22912 Ephemeral 1869 1.3% 802701 429 3197
|
||||
22684 Ephemeral 1859 1.3% 803991 432 3193
|
||||
22734 Ephemeral 1629 1.2% 695583 427 427
|
||||
10002 Relay list 1604 1.1% 4950855 3087 42385
|
||||
7 Reaction 1435 1.0% 847949 591 1287
|
||||
29333 Ephemeral 1408 1.0% 690797 491 492
|
||||
24133 Ephemeral 1375 1.0% 1890802 1375 38738
|
||||
37195 Addressable 1338 1.0% 1004351 751 934
|
||||
25555 Ephemeral 1181 0.8% 5929927 5021 17075
|
||||
22690 Ephemeral 1081 0.8% 467584 433 3184
|
||||
22601 Ephemeral 990 0.7% 423742 428 429
|
||||
22850 Ephemeral 947 0.7% 407208 430 430
|
||||
4515 Unknown 868 0.6% 1923082 2216 55180
|
||||
23334 Ephemeral 859 0.6% 374353 436 439
|
||||
22655 Ephemeral 821 0.6% 351388 428 428
|
||||
6 Repost 811 0.6% 771135 951 10128
|
||||
22795 Ephemeral 778 0.6% 1060284 1363 3201
|
||||
4 Encrypted DM 767 0.5% 725743 946 19618
|
||||
22720 Ephemeral 749 0.5% 1079163 1441 3249
|
||||
22876 Ephemeral 724 0.5% 308478 426 431
|
||||
22676 Ephemeral 696 0.5% 297193 427 428
|
||||
22913 Ephemeral 678 0.5% 294988 435 3201
|
||||
22689 Ephemeral 663 0.5% 1094513 1651 5926
|
||||
22927 Ephemeral 607 0.4% 1017238 1676 1876
|
||||
22236 Ephemeral 595 0.4% 446548 751 814
|
||||
22911 Ephemeral 569 0.4% 951997 1673 1880
|
||||
22943 Ephemeral 563 0.4% 249401 443 1658
|
||||
22603 Ephemeral 543 0.4% 231317 426 427
|
||||
22743 Ephemeral 542 0.4% 231978 428 430
|
||||
22695 Ephemeral 538 0.4% 871272 1619 1850
|
||||
1059 Gift wrap seal 535 0.4% 2557163 4780 55121
|
||||
22842 Ephemeral 528 0.4% 882417 1671 1853
|
||||
24242 Ephemeral 527 0.4% 305133 579 579
|
||||
13194 NWC info 505 0.4% 259258 513 514
|
||||
22730 Ephemeral 474 0.3% 418919 884 1517
|
||||
11998 Unknown 449 0.3% 208257 464 465
|
||||
23337 Ephemeral 446 0.3% 252660 567 586
|
||||
7368 Unknown 443 0.3% 459822 1038 1059
|
||||
22816 Ephemeral 410 0.3% 183597 448 3196
|
||||
30315 User status 406 0.3% 280885 692 1166
|
||||
22456 Ephemeral 403 0.3% 196962 489 790
|
||||
22815 Ephemeral 386 0.3% 620350 1607 3199
|
||||
20387 Ephemeral 368 0.3% 189152 514 514
|
||||
20000 Ephemeral 351 0.3% 237048 675 17065
|
||||
5300 Unknown 350 0.2% 213715 611 701
|
||||
22774 Ephemeral 349 0.2% 149372 428 428
|
||||
31990 App handler info 343 0.2% 389821 1137 6861
|
||||
3 Follow list 325 0.2% 4492770 13824 58982
|
||||
23003 Ephemeral 317 0.2% 135676 428 428
|
||||
38502 Addressable 295 0.2% 113575 385 385
|
||||
1985 Unknown 287 0.2% 189598 661 4834
|
||||
22807 Ephemeral 279 0.2% 119596 429 430
|
||||
25050 Ephemeral 272 0.2% 113448 417 1362
|
||||
4004 Unknown 270 0.2% 315630 1169 1169
|
||||
20004 Ephemeral 233 0.2% 124155 533 549
|
||||
35000 Addressable 208 0.1% 160992 774 774
|
||||
22613 Ephemeral 208 0.1% 143395 689 1134
|
||||
22592 Ephemeral 201 0.1% 93351 464 3193
|
||||
20333 Ephemeral 197 0.1% 156942 797 798
|
||||
31950 Addressable 196 0.1% 170818 872 937
|
||||
22632 Ephemeral 195 0.1% 85266 437 3204
|
||||
9735 Zap receipt 193 0.1% 370520 1920 4167
|
||||
10100 Unknown 188 0.1% 279911 1489 3826
|
||||
30311 Addressable 187 0.1% 202343 1082 1197
|
||||
24913 Ephemeral 179 0.1% 79157 442 582
|
||||
23004 Ephemeral 179 0.1% 77149 431 431
|
||||
22854 Ephemeral 174 0.1% 137235 789 1660
|
||||
30384 Addressable 166 0.1% 85437 515 556
|
||||
22891 Ephemeral 164 0.1% 235679 1437 3243
|
||||
10050 DM relays 160 0.1% 72634 454 592
|
||||
30023 Long-form article 144 0.1% 954406 6628 13594
|
||||
6300 Unknown 144 0.1% 880738 6116 17462
|
||||
445 Encrypted group msg 140 0.1% 350204 2501 4134
|
||||
10000 Mute list 136 0.1% 274284 2017 27742
|
||||
22693 Ephemeral 130 0.1% 101515 781 2619
|
||||
30166 Addressable 128 0.1% 66754 522 808
|
||||
4244 Unknown 127 0.1% 71628 564 564
|
||||
38503 Addressable 125 0.1% 68916 551 552
|
||||
20787 Ephemeral 124 0.1% 181428 1463 2478
|
||||
22455 Ephemeral 112 0.1% 183137 1635 1847
|
||||
22616 Ephemeral 111 0.1% 98460 887 3453
|
||||
22543 Ephemeral 107 0.1% 172800 1615 1849
|
||||
22885 Ephemeral 106 0.1% 102539 967 3524
|
||||
22672 Ephemeral 104 0.1% 174090 1674 1849
|
||||
22717 Ephemeral 99 0.1% 120874 1221 1849
|
||||
22929 Ephemeral 90 0.1% 88203 980 1517
|
||||
10777 Unknown 89 0.1% 43507 489 489
|
||||
22829 Ephemeral 89 0.1% 43243 486 3200
|
||||
30088 Addressable 87 0.1% 162094 1863 1871
|
||||
30091 Addressable 85 0.1% 52311 615 629
|
||||
21584 Ephemeral 83 0.1% 36413 439 439
|
||||
38385 Addressable 82 0.1% 111350 1358 1496
|
||||
22864 Ephemeral 82 0.1% 56300 687 1223
|
||||
39101 Addressable 81 0.1% 43173 533 533
|
||||
22751 Ephemeral 81 0.1% 73608 909 4083
|
||||
1111 Comment 79 0.1% 93490 1183 2457
|
||||
3927 Unknown 78 0.1% 41585 533 544
|
||||
10011 Unknown 77 0.1% 33123 430 431
|
||||
21060 Ephemeral 74 0.1% 42180 570 570
|
||||
21617 Ephemeral 73 0.1% 36119 495 495
|
||||
33334 Addressable 70 0.0% 58170 831 831
|
||||
30380 Addressable 66 0.0% 29964 454 454
|
||||
38383 Addressable 66 0.0% 59966 909 3211
|
||||
38384 Addressable 62 0.0% 46066 743 743
|
||||
38500 Addressable 60 0.0% 42716 712 713
|
||||
20384 Ephemeral 59 0.0% 37701 639 639
|
||||
30089 Chunked data 53 0.0% 614992 11604 44372
|
||||
1002 Unknown 53 0.0% 48203 909 1011
|
||||
22840 Ephemeral 52 0.0% 22285 429 430
|
||||
23066 Ephemeral 50 0.0% 43751 875 1165
|
||||
22526 Ephemeral 50 0.0% 21469 429 430
|
||||
22405 Ephemeral 47 0.0% 20886 444 445
|
||||
23042 Ephemeral 44 0.0% 18876 429 429
|
||||
22514 Ephemeral 44 0.0% 18832 428 428
|
||||
22748 Ephemeral 44 0.0% 18874 429 429
|
||||
31510 Addressable 43 0.0% 42075 978 982
|
||||
3079 Unknown 42 0.0% 38178 909 909
|
||||
4243 Unknown 42 0.0% 23688 564 564
|
||||
22862 Ephemeral 41 0.0% 17578 429 429
|
||||
22475 Ephemeral 40 0.0% 43786 1095 3923
|
||||
22721 Ephemeral 40 0.0% 23480 587 1842
|
||||
22674 Ephemeral 39 0.0% 17992 461 1661
|
||||
4245 Unknown 39 0.0% 17316 444 444
|
||||
30080 Addressable 39 0.0% 37674 966 1011
|
||||
30443 Addressable 38 0.0% 46231 1217 1547
|
||||
30515 Addressable 38 0.0% 201552 5304 5304
|
||||
22212 Ephemeral 37 0.0% 16440 444 445
|
||||
10003 Bookmarks 37 0.0% 420277 11359 56461
|
||||
38225 Addressable 35 0.0% 33592 960 1021
|
||||
30815 Addressable 34 0.0% 1276156 37534 37534
|
||||
1984 Report 34 0.0% 22174 652 667
|
||||
22753 Ephemeral 33 0.0% 40204 1218 3766
|
||||
30618 Addressable 32 0.0% 45089 1409 8804
|
||||
1040 Unknown 32 0.0% 36596 1144 5164
|
||||
3434 Unknown 30 0.0% 20382 679 705
|
||||
7000 Unknown 28 0.0% 21752 777 822
|
||||
30385 Addressable 28 0.0% 22344 798 981
|
||||
33301 Addressable 27 0.0% 45586 1688 2162
|
||||
16 Generic repost 27 0.0% 21778 807 1604
|
||||
22119 Ephemeral 25 0.0% 21137 845 846
|
||||
22120 Ephemeral 25 0.0% 27207 1088 1128
|
||||
24421 Ephemeral 24 0.0% 12384 516 516
|
||||
22525 Ephemeral 24 0.0% 42802 1783 4259
|
||||
22756 Ephemeral 24 0.0% 32806 1367 3198
|
||||
31124 Addressable 23 0.0% 28396 1235 1445
|
||||
22733 Ephemeral 23 0.0% 15376 669 1224
|
||||
30617 Addressable 23 0.0% 25047 1089 1089
|
||||
22649 Ephemeral 22 0.0% 9459 430 430
|
||||
22680 Ephemeral 21 0.0% 14310 681 3193
|
||||
22874 Ephemeral 21 0.0% 24675 1175 1850
|
||||
31339 Addressable 21 0.0% 30870 1470 1470
|
||||
30000 Addressable 19 0.0% 16519 869 3185
|
||||
22688 Ephemeral 19 0.0% 18248 960 3195
|
||||
31991 Addressable 19 0.0% 8759 461 461
|
||||
39842 Addressable 18 0.0% 19919 1107 1385
|
||||
10312 Unknown 18 0.0% 9219 512 559
|
||||
7403 Unknown 17 0.0% 8336 490 491
|
||||
30280 Addressable 17 0.0% 8721 513 513
|
||||
14 Unknown 16 0.0% 17438 1090 1531
|
||||
31000 Addressable 16 0.0% 9716 607 616
|
||||
22645 Ephemeral 16 0.0% 9285 580 1838
|
||||
2333 Unknown 15 0.0% 10074 672 722
|
||||
34236 Addressable 15 0.0% 211139 14076 26491
|
||||
30079 Addressable 15 0.0% 47271 3151 4574
|
||||
23333 Ephemeral 15 0.0% 8754 584 634
|
||||
23194 NWC request 15 0.0% 8952 597 1086
|
||||
22778 Ephemeral 15 0.0% 6421 428 429
|
||||
38111 Addressable 14 0.0% 10495 750 752
|
||||
22747 Ephemeral 13 0.0% 8895 684 1657
|
||||
25000 Ephemeral 13 0.0% 23498 1808 2214
|
||||
22506 Ephemeral 13 0.0% 23855 1835 1841
|
||||
1000 Unknown 13 0.0% 21880 1683 1790
|
||||
26428 Ephemeral 12 0.0% 10516 876 877
|
||||
23195 NWC response 12 0.0% 9184 765 1183
|
||||
1078 Unknown 12 0.0% 169653 14138 14241
|
||||
30554 Addressable 12 0.0% 7292 608 608
|
||||
22361 Ephemeral 11 0.0% 4708 428 428
|
||||
30421 Addressable 11 0.0% 11427 1039 1066
|
||||
30085 Addressable 11 0.0% 7227 657 659
|
||||
10063 Unknown 11 0.0% 5982 544 627
|
||||
22402 Ephemeral 11 0.0% 4683 426 443
|
||||
39015 Addressable 11 0.0% 7656 696 696
|
||||
11125 Unknown 10 0.0% 10262 1026 1916
|
||||
30113 Addressable 10 0.0% 6987 699 770
|
||||
33051 Addressable 10 0.0% 5206 521 522
|
||||
30087 Addressable 9 0.0% 65925 7325 7325
|
||||
30213 Addressable 9 0.0% 5662 629 637
|
||||
1018 Unknown 8 0.0% 4500 562 677
|
||||
30090 Addressable 8 0.0% 12120 1515 1515
|
||||
1050 Unknown 8 0.0% 3496 437 437
|
||||
22619 Ephemeral 8 0.0% 11165 1396 1842
|
||||
10051 Unknown 7 0.0% 3205 458 489
|
||||
26429 Ephemeral 7 0.0% 3437 491 491
|
||||
38421 Addressable 7 0.0% 7485 1069 1070
|
||||
39019 Addressable 6 0.0% 5766 961 961
|
||||
9842 Unknown 6 0.0% 6742 1124 1260
|
||||
20200 Ephemeral 6 0.0% 2946 491 491
|
||||
25742 Ephemeral 6 0.0% 11756 1959 7334
|
||||
30081 Addressable 6 0.0% 8220 1370 1370
|
||||
20 Picture 6 0.0% 4558 760 852
|
||||
20201 Ephemeral 6 0.0% 2946 491 491
|
||||
22722 Ephemeral 5 0.0% 7756 1551 1660
|
||||
7336 Unknown 5 0.0% 3280 656 656
|
||||
22825 Ephemeral 5 0.0% 5660 1132 1848
|
||||
13196 Unknown 5 0.0% 3280 656 656
|
||||
9841 Unknown 5 0.0% 14029 2806 4468
|
||||
23336 Ephemeral 5 0.0% 3285 657 657
|
||||
1063 File metadata 5 0.0% 4593 919 941
|
||||
31344 Addressable 4 0.0% 2500 625 625
|
||||
31986 Addressable 4 0.0% 2372 593 593
|
||||
22432 Ephemeral 4 0.0% 5412 1353 1843
|
||||
31985 Addressable 4 0.0% 2534 634 667
|
||||
10015 Unknown 3 0.0% 11266 3755 4578
|
||||
1010 Unknown 3 0.0% 2505 835 1152
|
||||
37779 Addressable 3 0.0% 1569 523 523
|
||||
21734 Ephemeral 3 0.0% 1131 377 377
|
||||
22671 Ephemeral 3 0.0% 1281 427 427
|
||||
31343 Addressable 2 0.0% 53115 26558 45456
|
||||
16767 Unknown 2 0.0% 1974 987 987
|
||||
1058 Unknown 2 0.0% 1186 593 593
|
||||
22724 Ephemeral 2 0.0% 2103 1052 1674
|
||||
30005 Addressable 2 0.0% 11351 5676 9817
|
||||
21724 Ephemeral 2 0.0% 754 377 377
|
||||
20177 Ephemeral 2 0.0% 851 426 426
|
||||
2003 Unknown 2 0.0% 8711 4356 7015
|
||||
30003 Addressable 2 0.0% 778 389 389
|
||||
25582 Ephemeral 2 0.0% 4500 2250 3690
|
||||
38422 Addressable 2 0.0% 60198 30099 30212
|
||||
22387 Ephemeral 2 0.0% 887 444 444
|
||||
1618 Unknown 1 0.0% 2168 2168 2168
|
||||
10001 Pinned notes 1 0.0% 710 710 710
|
||||
30758 Addressable 1 0.0% 436 436 436
|
||||
32267 Addressable 1 0.0% 1693 1693 1693
|
||||
1069 Unknown 1 0.0% 757 757 757
|
||||
31345 Addressable 1 0.0% 8666 8666 8666
|
||||
21840 Ephemeral 1 0.0% 377 377 377
|
||||
21764 Ephemeral 1 0.0% 377 377 377
|
||||
31353 Addressable 1 0.0% 737 737 737
|
||||
1808 Unknown 1 0.0% 1696 1696 1696
|
||||
31633 Addressable 1 0.0% 592 592 592
|
||||
30066 Addressable 1 0.0% 675 675 675
|
||||
30063 Addressable 1 0.0% 2891 2891 2891
|
||||
21711 Ephemeral 1 0.0% 377 377 377
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 15:24:51 2026
|
||||
# Config: cache_all_test_config.jsonc
|
||||
# Duration: 86400 seconds
|
||||
[2026-08-02 15:25:27] [RELAY] wss://laantungir.net STATUS: ?
|
||||
[2026-08-02 15:25:27] [RELAY] wss://nos.lol STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://nostr-pub.wellorder.net STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://nostr.mom STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://nostr.oxtr.dev STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://offchain.pub STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://premium.primal.net STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://relay.damus.io STATUS: ?
|
||||
[2026-08-02 15:25:27] [RELAY] wss://relay.ditto.pub STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://relay.divine.video STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://relay.momostr.pink STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://relay.mostr.pub STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://relay.nostrplebs.com STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://relay.primal.net STATUS: connected
|
||||
[2026-08-02 15:25:27] [RELAY] wss://theforest.nostr1.com STATUS: connected
|
||||
[2026-08-02 15:25:39] [RELAY] wss://relay.damus.io CONNECTED
|
||||
[2026-08-02 15:26:24] [RELAY] wss://relay.mostr.pub DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:26:24] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 15:26:46] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:26:46] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:27:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:27:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:27:40] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:27:40] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:28:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:28:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:28:40] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:28:40] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:28:46] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:28:46] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:29:16] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:29:16] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:29:40] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:29:40] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:30:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:30:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:30:16] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:30:16] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:31:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:31:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:31:40] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:31:40] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:32:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:32:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:32:37] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:32:38] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:33:19] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:33:19] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:33:40] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:33:40] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:33:49] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:33:49] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:34:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:34:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:34:40] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:34:40] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:35:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:35:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:35:11] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:35:11] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:35:12] [RELAY] wss://relay.mostr.pub DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:35:13] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 15:35:40] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:35:40] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:35:41] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:35:41] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:35:54] [RELAY] wss://nostr.oxtr.dev DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:35:55] [RELAY] wss://nostr.oxtr.dev CONNECTED
|
||||
[2026-08-02 15:37:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:37:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:37:40] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:37:40] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:38:11] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:38:11] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:38:34] [RELAY] wss://relay.mostr.pub DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:38:35] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 15:39:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:39:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:39:17] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:39:18] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:39:32] [RELAY] wss://relay.momostr.pink DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:39:32] [RELAY] wss://relay.momostr.pink CONNECTED
|
||||
[2026-08-02 15:39:34] [RELAY] wss://relay.momostr.pink DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:39:34] [RELAY] wss://relay.momostr.pink CONNECTED
|
||||
[2026-08-02 15:39:59] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:39:59] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:40:07] [RELAY] wss://relay.momostr.pink DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:40:07] [RELAY] wss://relay.momostr.pink CONNECTED
|
||||
[2026-08-02 15:40:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:40:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:40:40] [RELAY] wss://relay.momostr.pink DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:40:41] [RELAY] wss://relay.momostr.pink CONNECTED
|
||||
[2026-08-02 15:41:29] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:41:29] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:41:39] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:41:40] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:41:40] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:41:40] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:42:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:42:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:42:51] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:42:51] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:44:41] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:44:41] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:45:00] [RELAY] wss://relay.momostr.pink DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:45:01] [RELAY] wss://relay.momostr.pink CONNECTED
|
||||
[2026-08-02 15:45:07] [RELAY] wss://relay.ditto.pub DISCONNECTED:
|
||||
[2026-08-02 15:45:07] [RELAY] wss://relay.ditto.pub CONNECTED
|
||||
[2026-08-02 15:45:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:45:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:45:26] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:45:27] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:45:37] [RELAY] wss://relay.ditto.pub DISCONNECTED:
|
||||
[2026-08-02 15:45:37] [RELAY] wss://relay.ditto.pub CONNECTED
|
||||
[2026-08-02 15:46:07] [RELAY] wss://relay.ditto.pub DISCONNECTED:
|
||||
[2026-08-02 15:46:07] [RELAY] wss://relay.ditto.pub CONNECTED
|
||||
[2026-08-02 15:46:08] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:46:08] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:46:10] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:46:10] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:46:37] [RELAY] wss://relay.ditto.pub DISCONNECTED:
|
||||
[2026-08-02 15:46:37] [RELAY] wss://relay.ditto.pub CONNECTED
|
||||
[2026-08-02 15:46:38] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:46:38] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:46:40] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:46:40] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:46:51] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:46:52] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:47:00] [RELAY] wss://nostr.oxtr.dev DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:47:01] [RELAY] wss://nostr.oxtr.dev CONNECTED
|
||||
[2026-08-02 15:47:01] [RELAY] wss://nostr.oxtr.dev DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:47:02] [RELAY] wss://nostr.oxtr.dev CONNECTED
|
||||
[2026-08-02 15:47:07] [RELAY] wss://relay.ditto.pub DISCONNECTED:
|
||||
[2026-08-02 15:47:07] [RELAY] wss://relay.ditto.pub CONNECTED
|
||||
[2026-08-02 15:47:07] [RELAY] wss://nostr.oxtr.dev DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:47:08] [RELAY] wss://nostr.oxtr.dev CONNECTED
|
||||
[2026-08-02 15:47:08] [RELAY] wss://nostr.oxtr.dev DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:47:09] [RELAY] wss://nostr.oxtr.dev CONNECTED
|
||||
[2026-08-02 15:47:17] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:47:18] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:47:18] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:47:19] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:47:33] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:47:33] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:48:33] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:48:33] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:48:41] [RELAY] wss://relay.momostr.pink DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:48:42] [RELAY] wss://relay.momostr.pink CONNECTED
|
||||
[2026-08-02 15:49:03] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:49:03] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:49:33] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:49:33] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:49:37] [RELAY] wss://relay.ditto.pub DISCONNECTED:
|
||||
[2026-08-02 15:49:37] [RELAY] wss://relay.ditto.pub CONNECTED
|
||||
[2026-08-02 15:50:02] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:50:02] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:50:05] [RELAY] wss://relay.ditto.pub DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:50:05] [RELAY] wss://relay.ditto.pub CONNECTED
|
||||
[2026-08-02 15:50:33] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:50:33] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:51:18] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:51:19] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:51:33] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:51:33] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:52:00] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:52:00] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:52:30] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:52:30] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:52:33] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:52:33] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:52:33] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:52:34] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:52:34] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:52:35] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:53:00] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:53:00] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:53:30] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 15:53:30] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:53:30] [RELAY] wss://nostr.oxtr.dev DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:53:30] [RELAY] wss://nostr.oxtr.dev CONNECTED
|
||||
[2026-08-02 15:53:33] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:53:33] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:54:19] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:54:19] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:54:54] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:54:55] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:54:56] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:54:56] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:54:57] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:54:58] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:54:58] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:54:59] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:55:01] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:55:02] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:55:02] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:55:04] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:55:04] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:55:04] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:55:04] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:55:05] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:55:06] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:55:06] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:55:07] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:55:07] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:55:08] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:55:09] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:55:09] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:55:09] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:55:11] [RELAY] wss://nostr.oxtr.dev DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:55:12] [RELAY] wss://nostr.oxtr.dev CONNECTED
|
||||
[2026-08-02 15:55:33] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 15:55:33] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:55:36] [RELAY] wss://relay.mostr.pub DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:55:37] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 15:55:50] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:55:50] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:56:09] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:56:10] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 15:56:12] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:56:13] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 15:57:22] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:57:23] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 15:58:04] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 15:58:04] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:00:01] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:00:01] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:00:31] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:00:31] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:00:54] [RELAY] wss://relay.mostr.pub DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:00:54] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 16:01:31] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:01:31] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:01:48] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:01:48] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:01:55] [RELAY] wss://relay.mostr.pub DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:01:55] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 16:02:29] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:02:29] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:02:59] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:02:59] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:03:01] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:03:01] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:03:29] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:03:29] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:03:31] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:03:31] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:03:59] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:03:59] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:04:29] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:04:29] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:04:59] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:04:59] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:05:10] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:05:11] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:05:12] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:05:13] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:05:15] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:05:16] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:05:17] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:05:18] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:05:19] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:05:20] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:05:21] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:05:21] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:05:24] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:05:25] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:05:59] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:05:59] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:06:09] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:06:09] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:08:00] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:08:01] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:08:09] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:08:09] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:08:42] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:08:42] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:10:20] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:10:21] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:11:09] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:11:09] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:11:26] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:11:27] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:11:30] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:11:30] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:11:32] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:11:32] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:11:39] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:11:39] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:11:46] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:11:47] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:12:58] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:12:58] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:13:25] [RELAY] wss://relay.mostr.pub DISCONNECTED:
|
||||
[2026-08-02 16:13:25] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 16:13:32] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:13:32] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:13:58] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:13:58] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:14:28] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:14:28] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:14:32] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:14:32] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:15:16] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:15:17] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:15:23] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:15:24] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:15:32] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:15:32] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:15:41] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:15:42] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:16:25] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:16:26] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:16:28] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:16:28] [RELAY] wss://premium.primal.net CONNECTED
|
||||
[2026-08-02 16:16:32] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:16:32] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:16:36] [RELAY] wss://relay.momostr.pink DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:16:36] [RELAY] wss://relay.momostr.pink CONNECTED
|
||||
[2026-08-02 16:17:02] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:17:02] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:17:25] [RELAY] wss://relay.mostr.pub DISCONNECTED:
|
||||
[2026-08-02 16:17:25] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 16:18:02] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:18:02] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:18:08] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:18:08] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:18:25] [RELAY] wss://relay.mostr.pub DISCONNECTED:
|
||||
[2026-08-02 16:18:25] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 16:18:49] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:18:49] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:18:55] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:18:56] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:19:37] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:19:37] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:19:40] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:19:40] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:20:37] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:20:37] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:21:07] [RELAY] wss://relay.primal.net DISCONNECTED:
|
||||
[2026-08-02 16:21:07] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:21:10] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:21:10] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:21:14] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:21:15] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:21:56] [RELAY] wss://nos.lol DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:21:56] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:22:26] [RELAY] wss://nos.lol DISCONNECTED:
|
||||
[2026-08-02 16:22:26] [RELAY] wss://nos.lol CONNECTED
|
||||
[2026-08-02 16:22:55] [RELAY] wss://relay.mostr.pub DISCONNECTED:
|
||||
[2026-08-02 16:22:55] [RELAY] wss://relay.mostr.pub CONNECTED
|
||||
[2026-08-02 16:23:32] [RELAY] wss://premium.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:23:33] [RELAY] wss://premium.primal.net CONNECTED
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 8m 23s
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 7884
|
||||
Total bytes: 12205231 (11.64 MB)
|
||||
Avg event size: 1548 bytes
|
||||
Max event: 56750 bytes (kind 3)
|
||||
Unique pubkeys: 2301
|
||||
Relays: 1
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://relay.primal.net 7884 0 0 0 0 10 OK
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
1059 Gift wrap seal 871 11.0% 1657832 1903 55121
|
||||
21059 Gift wrap (NIP-59) 740 9.4% 2308644 3120 22354
|
||||
30078 App data 622 7.9% 2651879 4263 55090
|
||||
30383 Addressable 520 6.6% 278610 536 548
|
||||
20001 Ephemeral 386 4.9% 403111 1044 2026
|
||||
22734 Ephemeral 357 4.5% 152451 427 428
|
||||
1 Text note 303 3.8% 303990 1003 4648
|
||||
30382 Addressable 288 3.7% 137207 476 484
|
||||
0 Profile metadata 189 2.4% 140594 744 2012
|
||||
29333 Ephemeral 165 2.1% 81180 492 492
|
||||
10002 Relay list 158 2.0% 571188 3615 42385
|
||||
22236 Ephemeral 158 2.0% 120802 765 801
|
||||
5 Deletion 154 2.0% 73847 480 664
|
||||
4515 Unknown 154 2.0% 463562 3010 38797
|
||||
22743 Ephemeral 134 1.7% 57352 428 428
|
||||
7 Reaction 113 1.4% 62452 553 727
|
||||
24133 Ephemeral 102 1.3% 132440 1298 7334
|
||||
22684 Ephemeral 99 1.3% 42669 431 431
|
||||
22850 Ephemeral 94 1.2% 40420 430 430
|
||||
22838 Ephemeral 88 1.1% 37752 429 429
|
||||
22774 Ephemeral 84 1.1% 35952 428 428
|
||||
23003 Ephemeral 84 1.1% 35952 428 428
|
||||
22876 Ephemeral 83 1.1% 35358 426 426
|
||||
22611 Ephemeral 75 1.0% 32175 429 429
|
||||
25555 Ephemeral 69 0.9% 281319 4077 16987
|
||||
4 Encrypted DM 66 0.8% 72028 1091 17018
|
||||
22613 Ephemeral 63 0.8% 43489 690 692
|
||||
25050 Ephemeral 61 0.8% 24461 401 401
|
||||
11998 Unknown 61 0.8% 28269 463 465
|
||||
443 Unknown 49 0.6% 68056 1389 22480
|
||||
30301 Addressable 47 0.6% 53284 1134 1912
|
||||
3927 Unknown 47 0.6% 25051 533 533
|
||||
20387 Ephemeral 44 0.6% 22616 514 514
|
||||
22761 Ephemeral 44 0.6% 18832 428 428
|
||||
13194 NWC info 43 0.5% 22043 513 514
|
||||
20004 Ephemeral 42 0.5% 22266 530 549
|
||||
5300 Unknown 42 0.5% 25437 606 637
|
||||
22546 Ephemeral 39 0.5% 16614 426 426
|
||||
22714 Ephemeral 37 0.5% 15836 428 428
|
||||
30166 Addressable 35 0.4% 17904 512 589
|
||||
9735 Zap receipt 35 0.4% 70344 2010 3538
|
||||
23334 Ephemeral 35 0.4% 15084 431 432
|
||||
1985 Unknown 34 0.4% 16232 477 483
|
||||
22816 Ephemeral 33 0.4% 14157 429 429
|
||||
21050 Ephemeral 33 0.4% 30862 935 1874
|
||||
30315 User status 32 0.4% 21166 661 925
|
||||
445 Encrypted group msg 32 0.4% 120956 3780 9346
|
||||
22698 Ephemeral 32 0.4% 13664 427 427
|
||||
4004 Unknown 32 0.4% 37408 1169 1169
|
||||
38501 Addressable 31 0.4% 23034 743 744
|
||||
31990 App handler info 25 0.3% 9675 387 387
|
||||
10100 Unknown 24 0.3% 27687 1154 1589
|
||||
20333 Ephemeral 24 0.3% 19120 797 798
|
||||
3 Follow list 23 0.3% 328284 14273 56750
|
||||
24913 Ephemeral 22 0.3% 9700 441 493
|
||||
30311 Addressable 21 0.3% 22061 1051 1197
|
||||
6 Repost 21 0.3% 49793 2371 12925
|
||||
10050 DM relays 19 0.2% 8172 430 450
|
||||
22712 Ephemeral 18 0.2% 7704 428 428
|
||||
22808 Ephemeral 17 0.2% 7293 429 429
|
||||
10000 Mute list 16 0.2% 26659 1666 12630
|
||||
4244 Unknown 15 0.2% 8460 564 564
|
||||
23025 Ephemeral 15 0.2% 6465 431 431
|
||||
31234 Addressable 14 0.2% 24051 1718 2268
|
||||
38503 Addressable 13 0.2% 7174 552 552
|
||||
22630 Ephemeral 12 0.2% 11762 980 1654
|
||||
37195 Addressable 12 0.2% 8752 729 934
|
||||
6300 Unknown 12 0.2% 77247 6437 17248
|
||||
10777 Unknown 12 0.2% 5861 488 489
|
||||
30091 Addressable 11 0.1% 6763 615 629
|
||||
20000 Ephemeral 11 0.1% 3806 346 346
|
||||
30515 Addressable 11 0.1% 58344 5304 5304
|
||||
30088 Addressable 11 0.1% 20483 1862 1871
|
||||
22361 Ephemeral 10 0.1% 4439 444 445
|
||||
30280 Addressable 9 0.1% 4617 513 513
|
||||
22902 Ephemeral 9 0.1% 3861 429 429
|
||||
22506 Ephemeral 8 0.1% 3416 427 427
|
||||
7368 Unknown 8 0.1% 8304 1038 1040
|
||||
22645 Ephemeral 8 0.1% 3432 429 429
|
||||
38500 Addressable 8 0.1% 5696 712 713
|
||||
33334 Addressable 8 0.1% 6648 831 831
|
||||
30380 Addressable 8 0.1% 3632 454 454
|
||||
22688 Ephemeral 7 0.1% 2989 427 427
|
||||
22656 Ephemeral 7 0.1% 3017 431 431
|
||||
22316 Ephemeral 7 0.1% 3106 444 444
|
||||
30089 Chunked data 6 0.1% 123676 20613 44372
|
||||
22456 Ephemeral 6 0.1% 3140 523 790
|
||||
22739 Ephemeral 6 0.1% 2580 430 430
|
||||
22882 Ephemeral 6 0.1% 5292 882 1449
|
||||
22862 Ephemeral 6 0.1% 2574 429 429
|
||||
1111 Comment 6 0.1% 7227 1204 1698
|
||||
4245 Unknown 5 0.1% 2220 444 444
|
||||
30512 Addressable 5 0.1% 7504 1501 1506
|
||||
22641 Ephemeral 5 0.1% 2145 429 429
|
||||
22586 Ephemeral 5 0.1% 2135 427 427
|
||||
4243 Unknown 5 0.1% 2820 564 564
|
||||
22835 Ephemeral 5 0.1% 2145 429 429
|
||||
22620 Ephemeral 5 0.1% 2145 429 429
|
||||
22298 Ephemeral 5 0.1% 2218 444 444
|
||||
22852 Ephemeral 5 0.1% 2140 428 428
|
||||
22726 Ephemeral 5 0.1% 2150 430 430
|
||||
22362 Ephemeral 5 0.1% 2218 444 444
|
||||
22772 Ephemeral 5 0.1% 4051 810 1132
|
||||
22805 Ephemeral 4 0.1% 1712 428 428
|
||||
9734 Zap request 4 0.1% 3756 939 1033
|
||||
22200 Ephemeral 4 0.1% 1774 444 444
|
||||
31510 Addressable 4 0.1% 3922 980 982
|
||||
22570 Ephemeral 4 0.1% 1716 429 429
|
||||
25195 Ephemeral 4 0.1% 2712 678 678
|
||||
22752 Ephemeral 3 0.0% 4047 1349 3191
|
||||
31339 Addressable 3 0.0% 4410 1470 1470
|
||||
22949 Ephemeral 3 0.0% 1287 429 429
|
||||
22358 Ephemeral 3 0.0% 1331 444 444
|
||||
22474 Ephemeral 3 0.0% 1330 443 444
|
||||
22185 Ephemeral 3 0.0% 1330 443 444
|
||||
22936 Ephemeral 3 0.0% 1290 430 430
|
||||
25196 Ephemeral 3 0.0% 4938 1646 2214
|
||||
22439 Ephemeral 3 0.0% 1330 443 444
|
||||
22824 Ephemeral 3 0.0% 1281 427 427
|
||||
22270 Ephemeral 3 0.0% 1330 443 444
|
||||
22263 Ephemeral 3 0.0% 1330 443 444
|
||||
22755 Ephemeral 3 0.0% 1284 428 428
|
||||
10051 Unknown 3 0.0% 1317 439 439
|
||||
34775 Addressable 3 0.0% 7599 2533 2561
|
||||
30300 Addressable 3 0.0% 5502 1834 1834
|
||||
22234 Ephemeral 3 0.0% 1330 443 444
|
||||
7403 Unknown 2 0.0% 978 489 489
|
||||
22626 Ephemeral 2 0.0% 1916 958 1486
|
||||
30079 Addressable 2 0.0% 1750 875 875
|
||||
15750 Unknown 2 0.0% 1242 621 626
|
||||
23337 Ephemeral 2 0.0% 1027 514 514
|
||||
30815 Addressable 2 0.0% 75068 37534 37534
|
||||
30213 Addressable 2 0.0% 1264 632 632
|
||||
22716 Ephemeral 2 0.0% 854 427 427
|
||||
22492 Ephemeral 2 0.0% 887 444 444
|
||||
30000 Addressable 2 0.0% 1646 823 823
|
||||
22463 Ephemeral 2 0.0% 887 444 444
|
||||
22304 Ephemeral 2 0.0% 887 444 444
|
||||
10003 Bookmarks 2 0.0% 20016 10008 15003
|
||||
30443 Addressable 2 0.0% 2572 1286 1312
|
||||
22233 Ephemeral 2 0.0% 886 443 443
|
||||
22275 Ephemeral 2 0.0% 887 444 444
|
||||
30087 Addressable 2 0.0% 11238 5619 7325
|
||||
20078 Ephemeral 2 0.0% 1458 729 729
|
||||
22057 Ephemeral 2 0.0% 887 444 444
|
||||
22251 Ephemeral 2 0.0% 887 444 444
|
||||
22181 Ephemeral 2 0.0% 887 444 444
|
||||
22678 Ephemeral 2 0.0% 1388 694 694
|
||||
22747 Ephemeral 2 0.0% 858 429 429
|
||||
22410 Ephemeral 2 0.0% 887 444 444
|
||||
22334 Ephemeral 2 0.0% 887 444 444
|
||||
22249 Ephemeral 2 0.0% 887 444 444
|
||||
22258 Ephemeral 2 0.0% 887 444 444
|
||||
30090 Addressable 2 0.0% 2588 1294 1515
|
||||
10312 Unknown 1 0.0% 472 472 472
|
||||
22853 Ephemeral 1 0.0% 1673 1673 1673
|
||||
22303 Ephemeral 1 0.0% 443 443 443
|
||||
22306 Ephemeral 1 0.0% 443 443 443
|
||||
20200 Ephemeral 1 0.0% 491 491 491
|
||||
22132 Ephemeral 1 0.0% 443 443 443
|
||||
20201 Ephemeral 1 0.0% 491 491 491
|
||||
22245 Ephemeral 1 0.0% 443 443 443
|
||||
22352 Ephemeral 1 0.0% 443 443 443
|
||||
22240 Ephemeral 1 0.0% 443 443 443
|
||||
34236 Addressable 1 0.0% 931 931 931
|
||||
17 Unknown 1 0.0% 610 610 610
|
||||
22286 Ephemeral 1 0.0% 443 443 443
|
||||
13196 Unknown 1 0.0% 656 656 656
|
||||
20242 Ephemeral 1 0.0% 346 346 346
|
||||
7376 Unknown 1 0.0% 670 670 670
|
||||
38385 Addressable 1 0.0% 1350 1350 1350
|
||||
22355 Ephemeral 1 0.0% 443 443 443
|
||||
23333 Ephemeral 1 0.0% 571 571 571
|
||||
22737 Ephemeral 1 0.0% 556 556 556
|
||||
22291 Ephemeral 1 0.0% 443 443 443
|
||||
30421 Addressable 1 0.0% 995 995 995
|
||||
22860 Ephemeral 1 0.0% 553 553 553
|
||||
2333 Unknown 1 0.0% 659 659 659
|
||||
22219 Ephemeral 1 0.0% 443 443 443
|
||||
22382 Ephemeral 1 0.0% 443 443 443
|
||||
23032 Ephemeral 1 0.0% 430 430 430
|
||||
7375 Unknown 1 0.0% 1822 1822 1822
|
||||
22579 Ephemeral 1 0.0% 1670 1670 1670
|
||||
10007 Unknown 1 0.0% 715 715 715
|
||||
10086 Unknown 1 0.0% 715 715 715
|
||||
22729 Ephemeral 1 0.0% 3030 3030 3030
|
||||
22540 Ephemeral 1 0.0% 426 426 426
|
||||
22671 Ephemeral 1 0.0% 3194 3194 3194
|
||||
30618 Addressable 1 0.0% 460 460 460
|
||||
23118 Ephemeral 1 0.0% 430 430 430
|
||||
38421 Addressable 1 0.0% 1069 1069 1069
|
||||
10377 Unknown 1 0.0% 664 664 664
|
||||
11111 Unknown 1 0.0% 382 382 382
|
||||
34550 Community def 1 0.0% 867 867 867
|
||||
22307 Ephemeral 1 0.0% 443 443 443
|
||||
1078 Unknown 1 0.0% 13969 13969 13969
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 16:24:15 2026
|
||||
# Config: cache_all_test_primal.jsonc
|
||||
# Duration: 3600 seconds
|
||||
[2026-08-02 16:24:32] [RELAY] wss://relay.primal.net STATUS: connected
|
||||
[2026-08-02 16:24:33] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:24:34] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:24:37] [RELAY] ? EOSE
|
||||
[2026-08-02 16:28:28] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:28:29] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:29:27] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:29:28] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:29:32] [RELAY] ? EOSE
|
||||
[2026-08-02 16:29:45] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:29:46] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:30:42] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:30:43] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:30:54] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:30:55] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:32:29] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:32:30] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:32:30] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:32:31] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:32:31] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:32:32] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:32:48] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:32:49] [RELAY] wss://relay.primal.net CONNECTED
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
=== Cache-All Feasibility Test Report ===
|
||||
Duration: 0h 6m 16s
|
||||
|
||||
=== Global Summary ===
|
||||
Total events: 5992
|
||||
Total bytes: 8743262 (8.34 MB)
|
||||
Avg event size: 1459 bytes
|
||||
Max event: 61894 bytes (kind 3)
|
||||
Unique pubkeys: 1142
|
||||
Relays: 1
|
||||
|
||||
=== Relay Summary ===
|
||||
Relay Events EOSE CLOSED NOTICE Err Disc Status
|
||||
wss://relay.primal.net 5992 0 0 0 0 3 OK
|
||||
|
||||
=== Kind Distribution ===
|
||||
Kind Name Count % Total Bytes Avg Max
|
||||
30078 App data 495 8.3% 2024957 4091 54029
|
||||
21059 Gift wrap (NIP-59) 386 6.4% 1099128 2847 5314
|
||||
4515 Unknown 374 6.2% 781718 2090 14221
|
||||
22591 Ephemeral 371 6.2% 286839 773 1228
|
||||
20001 Ephemeral 271 4.5% 315643 1165 2029
|
||||
22734 Ephemeral 264 4.4% 112728 427 427
|
||||
30382 Addressable 255 4.3% 121375 476 483
|
||||
30383 Addressable 237 4.0% 126938 536 547
|
||||
1 Text note 212 3.5% 211399 997 2011
|
||||
5 Deletion 183 3.1% 91915 502 664
|
||||
22236 Ephemeral 146 2.4% 104252 714 810
|
||||
0 Profile metadata 145 2.4% 103418 713 2012
|
||||
7 Reaction 138 2.3% 79421 576 1036
|
||||
22743 Ephemeral 134 2.2% 57352 428 428
|
||||
1059 Gift wrap seal 132 2.2% 430222 3259 5285
|
||||
29333 Ephemeral 130 2.2% 63960 492 492
|
||||
22611 Ephemeral 117 2.0% 50147 429 429
|
||||
10002 Relay list 114 1.9% 510211 4476 42449
|
||||
23456 Ephemeral 72 1.2% 121616 1689 1874
|
||||
22850 Ephemeral 71 1.2% 30530 430 430
|
||||
22684 Ephemeral 70 1.2% 30170 431 431
|
||||
22838 Ephemeral 63 1.1% 27027 429 429
|
||||
23003 Ephemeral 63 1.1% 26964 428 428
|
||||
22774 Ephemeral 62 1.0% 26536 428 428
|
||||
22876 Ephemeral 61 1.0% 28880 473 3193
|
||||
22583 Ephemeral 61 1.0% 26047 427 427
|
||||
22613 Ephemeral 60 1.0% 43172 720 1133
|
||||
4 Encrypted DM 58 1.0% 61778 1065 17018
|
||||
25555 Ephemeral 56 0.9% 249772 4460 16895
|
||||
25050 Ephemeral 51 0.9% 20451 401 401
|
||||
11998 Unknown 48 0.8% 22272 464 465
|
||||
22728 Ephemeral 48 0.8% 20592 429 429
|
||||
31234 Addressable 33 0.6% 77859 2359 2612
|
||||
13194 NWC info 32 0.5% 16448 514 514
|
||||
20387 Ephemeral 32 0.5% 16448 514 514
|
||||
24133 Ephemeral 32 0.5% 23680 740 2214
|
||||
3 Follow list 31 0.5% 167289 5396 61894
|
||||
4004 Unknown 26 0.4% 30394 1169 1169
|
||||
22816 Ephemeral 26 0.4% 11154 429 429
|
||||
20004 Ephemeral 26 0.4% 13878 534 549
|
||||
30315 User status 26 0.4% 17657 679 872
|
||||
443 Unknown 25 0.4% 43504 1740 22480
|
||||
38501 Addressable 24 0.4% 17819 742 744
|
||||
1985 Unknown 24 0.4% 11435 476 483
|
||||
22882 Ephemeral 23 0.4% 20949 911 1455
|
||||
5300 Unknown 22 0.4% 13434 611 701
|
||||
31990 App handler info 22 0.4% 21777 990 6861
|
||||
22790 Ephemeral 21 0.4% 8988 428 428
|
||||
21050 Ephemeral 19 0.3% 17510 922 1874
|
||||
10100 Unknown 19 0.3% 22108 1164 1589
|
||||
20333 Ephemeral 18 0.3% 14340 797 798
|
||||
30088 Addressable 16 0.3% 29798 1862 1871
|
||||
6 Repost 16 0.3% 28131 1758 3369
|
||||
30091 Addressable 16 0.3% 9842 615 629
|
||||
6300 Unknown 15 0.3% 45643 3043 8157
|
||||
22658 Ephemeral 15 0.3% 11909 794 1161
|
||||
30311 Addressable 15 0.3% 16556 1104 1197
|
||||
445 Encrypted group msg 15 0.3% 45070 3005 4130
|
||||
10777 Unknown 14 0.2% 6840 489 489
|
||||
9735 Zap receipt 14 0.2% 27231 1945 2777
|
||||
4244 Unknown 12 0.2% 6768 564 564
|
||||
22456 Ephemeral 12 0.2% 6808 567 790
|
||||
38503 Addressable 11 0.2% 6070 552 552
|
||||
10050 DM relays 11 0.2% 4882 444 592
|
||||
30515 Addressable 10 0.2% 53040 5304 5304
|
||||
30512 Addressable 10 0.2% 15210 1521 1596
|
||||
30089 Chunked data 10 0.2% 164434 16443 44372
|
||||
10000 Mute list 10 0.2% 16448 1645 4287
|
||||
22809 Ephemeral 9 0.2% 3852 428 428
|
||||
22486 Ephemeral 9 0.2% 3834 426 426
|
||||
22376 Ephemeral 8 0.1% 3550 444 444
|
||||
7368 Unknown 8 0.1% 8294 1037 1040
|
||||
38500 Addressable 8 0.1% 5696 712 713
|
||||
30380 Addressable 7 0.1% 3178 454 454
|
||||
20000 Ephemeral 7 0.1% 2422 346 346
|
||||
22104 Ephemeral 7 0.1% 3105 444 444
|
||||
23025 Ephemeral 7 0.1% 3017 431 431
|
||||
22896 Ephemeral 7 0.1% 3003 429 429
|
||||
33334 Addressable 7 0.1% 5817 831 831
|
||||
22835 Ephemeral 6 0.1% 2574 429 429
|
||||
30443 Addressable 6 0.1% 7297 1216 1260
|
||||
22633 Ephemeral 6 0.1% 6097 1016 1668
|
||||
22392 Ephemeral 6 0.1% 2662 444 444
|
||||
1984 Report 6 0.1% 3180 530 530
|
||||
30064 Addressable 6 0.1% 4438 740 991
|
||||
22715 Ephemeral 6 0.1% 2562 427 427
|
||||
30280 Addressable 6 0.1% 3078 513 513
|
||||
22559 Ephemeral 6 0.1% 2574 429 429
|
||||
22813 Ephemeral 6 0.1% 2562 427 427
|
||||
22635 Ephemeral 6 0.1% 2556 426 426
|
||||
22746 Ephemeral 5 0.1% 2155 431 431
|
||||
22364 Ephemeral 5 0.1% 2135 427 427
|
||||
37195 Addressable 5 0.1% 3664 733 786
|
||||
22571 Ephemeral 5 0.1% 4055 811 1127
|
||||
23004 Ephemeral 5 0.1% 2145 429 429
|
||||
22834 Ephemeral 5 0.1% 4050 810 1126
|
||||
22636 Ephemeral 5 0.1% 3280 656 1164
|
||||
22786 Ephemeral 4 0.1% 1720 430 430
|
||||
25195 Ephemeral 4 0.1% 2712 678 678
|
||||
4243 Unknown 4 0.1% 2256 564 564
|
||||
22168 Ephemeral 4 0.1% 1774 444 444
|
||||
22760 Ephemeral 4 0.1% 2239 560 695
|
||||
22733 Ephemeral 4 0.1% 1696 424 424
|
||||
22878 Ephemeral 3 0.1% 4059 1353 3203
|
||||
22902 Ephemeral 3 0.1% 5023 1674 1675
|
||||
22428 Ephemeral 3 0.1% 1331 444 444
|
||||
25196 Ephemeral 3 0.1% 4938 1646 2214
|
||||
22325 Ephemeral 3 0.1% 1331 444 444
|
||||
4245 Unknown 3 0.1% 1332 444 444
|
||||
22258 Ephemeral 3 0.1% 1331 444 444
|
||||
22625 Ephemeral 3 0.1% 1284 428 428
|
||||
22631 Ephemeral 3 0.1% 1281 427 427
|
||||
22551 Ephemeral 3 0.1% 1816 605 695
|
||||
22763 Ephemeral 3 0.1% 2988 996 1331
|
||||
3927 Unknown 2 0.0% 1066 533 533
|
||||
22186 Ephemeral 2 0.0% 887 444 444
|
||||
30213 Addressable 2 0.0% 1264 632 632
|
||||
22367 Ephemeral 2 0.0% 887 444 444
|
||||
22783 Ephemeral 2 0.0% 1391 696 697
|
||||
22616 Ephemeral 2 0.0% 858 429 429
|
||||
22268 Ephemeral 2 0.0% 887 444 444
|
||||
22279 Ephemeral 2 0.0% 887 444 444
|
||||
22474 Ephemeral 2 0.0% 887 444 444
|
||||
22407 Ephemeral 2 0.0% 887 444 444
|
||||
22729 Ephemeral 2 0.0% 854 427 427
|
||||
22234 Ephemeral 2 0.0% 887 444 444
|
||||
10003 Bookmarks 2 0.0% 18782 9391 15076
|
||||
30815 Addressable 2 0.0% 75068 37534 37534
|
||||
1111 Comment 2 0.0% 1775 888 922
|
||||
30087 Addressable 2 0.0% 13286 6643 7325
|
||||
22256 Ephemeral 2 0.0% 886 443 443
|
||||
22299 Ephemeral 2 0.0% 887 444 444
|
||||
30090 Addressable 2 0.0% 2911 1456 1515
|
||||
22260 Ephemeral 2 0.0% 887 444 444
|
||||
7376 Unknown 2 0.0% 1340 670 670
|
||||
22012 Ephemeral 2 0.0% 887 444 444
|
||||
30618 Addressable 2 0.0% 920 460 460
|
||||
1078 Unknown 2 0.0% 28397 14198 14219
|
||||
22313 Ephemeral 2 0.0% 887 444 444
|
||||
31339 Addressable 2 0.0% 2940 1470 1470
|
||||
15750 Unknown 2 0.0% 1184 592 620
|
||||
20 Picture 2 0.0% 1664 832 834
|
||||
22326 Ephemeral 2 0.0% 887 444 444
|
||||
22841 Ephemeral 1 0.0% 428 428 428
|
||||
22738 Ephemeral 1 0.0% 1668 1668 1668
|
||||
22295 Ephemeral 1 0.0% 443 443 443
|
||||
22296 Ephemeral 1 0.0% 443 443 443
|
||||
31510 Addressable 1 0.0% 979 979 979
|
||||
22691 Ephemeral 1 0.0% 431 431 431
|
||||
22340 Ephemeral 1 0.0% 443 443 443
|
||||
30003 Addressable 1 0.0% 387 387 387
|
||||
22197 Ephemeral 1 0.0% 443 443 443
|
||||
22257 Ephemeral 1 0.0% 443 443 443
|
||||
30079 Addressable 1 0.0% 875 875 875
|
||||
22811 Ephemeral 1 0.0% 3211 3211 3211
|
||||
38385 Addressable 1 0.0% 1350 1350 1350
|
||||
22339 Ephemeral 1 0.0% 443 443 443
|
||||
13196 Unknown 1 0.0% 656 656 656
|
||||
20200 Ephemeral 1 0.0% 491 491 491
|
||||
20201 Ephemeral 1 0.0% 491 491 491
|
||||
22395 Ephemeral 1 0.0% 443 443 443
|
||||
30023 Long-form article 1 0.0% 27062 27062 27062
|
||||
7403 Unknown 1 0.0% 490 490 490
|
||||
22618 Ephemeral 1 0.0% 1668 1668 1668
|
||||
17 Unknown 1 0.0% 593 593 593
|
||||
30000 Addressable 1 0.0% 823 823 823
|
||||
22558 Ephemeral 1 0.0% 428 428 428
|
||||
22143 Ephemeral 1 0.0% 443 443 443
|
||||
22198 Ephemeral 1 0.0% 443 443 443
|
||||
7375 Unknown 1 0.0% 2846 2846 2846
|
||||
22506 Ephemeral 1 0.0% 426 426 426
|
||||
22243 Ephemeral 1 0.0% 443 443 443
|
||||
23086 Ephemeral 1 0.0% 431 431 431
|
||||
22688 Ephemeral 1 0.0% 3201 3201 3201
|
||||
22975 Ephemeral 1 0.0% 429 429 429
|
||||
22270 Ephemeral 1 0.0% 443 443 443
|
||||
22584 Ephemeral 1 0.0% 1675 1675 1675
|
||||
22764 Ephemeral 1 0.0% 551 551 551
|
||||
23071 Ephemeral 1 0.0% 1675 1675 1675
|
||||
22817 Ephemeral 1 0.0% 559 559 559
|
||||
22614 Ephemeral 1 0.0% 3200 3200 3200
|
||||
22330 Ephemeral 1 0.0% 443 443 443
|
||||
22229 Ephemeral 1 0.0% 443 443 443
|
||||
24421 Ephemeral 1 0.0% 525 525 525
|
||||
|
||||
=== Raw Relay Response Log ===
|
||||
# Cache-All Feasibility Test - Raw Relay Log
|
||||
# Started: Sun Aug 2 16:34:39 2026
|
||||
# Config: cache_all_test_primal.jsonc
|
||||
# Duration: 3600 seconds
|
||||
[2026-08-02 16:34:56] [RELAY] wss://relay.primal.net STATUS: connected
|
||||
[2026-08-02 16:34:57] [RELAY] ? EOSE
|
||||
[2026-08-02 16:38:58] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:38:58] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:39:56] [RELAY] ? EOSE
|
||||
[2026-08-02 16:40:16] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:40:17] [RELAY] wss://relay.primal.net CONNECTED
|
||||
[2026-08-02 16:40:17] [RELAY] wss://relay.primal.net DISCONNECTED: Connection state transitioned to 2 during poll
|
||||
[2026-08-02 16:40:18] [RELAY] wss://relay.primal.net CONNECTED
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,921 @@
|
||||
{
|
||||
"duration_seconds": 120,
|
||||
"total_events": 4267,
|
||||
"total_bytes": 6726611,
|
||||
"max_event_bytes": 42385,
|
||||
"max_event_kind": 10002,
|
||||
"unique_pubkeys": 1860,
|
||||
"relay_count": 3,
|
||||
"relays": [{
|
||||
"url": "wss://relay.primal.net",
|
||||
"events": 1670,
|
||||
"eose": 1,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nos.lol",
|
||||
"events": 1792,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.damus.io",
|
||||
"events": 805,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true,
|
||||
"raw_responses": []
|
||||
}],
|
||||
"kinds": [{
|
||||
"kind": 21059,
|
||||
"count": 1199,
|
||||
"total_bytes": 3547818,
|
||||
"max_bytes": 5314
|
||||
}, {
|
||||
"kind": 5,
|
||||
"count": 466,
|
||||
"total_bytes": 204587,
|
||||
"max_bytes": 1064
|
||||
}, {
|
||||
"kind": 30078,
|
||||
"count": 222,
|
||||
"total_bytes": 948782,
|
||||
"max_bytes": 40337
|
||||
}, {
|
||||
"kind": 22668,
|
||||
"count": 221,
|
||||
"total_bytes": 94809,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 20001,
|
||||
"count": 152,
|
||||
"total_bytes": 106536,
|
||||
"max_bytes": 1755
|
||||
}, {
|
||||
"kind": 4515,
|
||||
"count": 152,
|
||||
"total_bytes": 260732,
|
||||
"max_bytes": 8759
|
||||
}, {
|
||||
"kind": 22734,
|
||||
"count": 108,
|
||||
"total_bytes": 46116,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 1,
|
||||
"count": 105,
|
||||
"total_bytes": 83026,
|
||||
"max_bytes": 3482
|
||||
}, {
|
||||
"kind": 21050,
|
||||
"count": 91,
|
||||
"total_bytes": 89206,
|
||||
"max_bytes": 2558
|
||||
}, {
|
||||
"kind": 24747,
|
||||
"count": 85,
|
||||
"total_bytes": 42775,
|
||||
"max_bytes": 671
|
||||
}, {
|
||||
"kind": 22850,
|
||||
"count": 77,
|
||||
"total_bytes": 33110,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22591,
|
||||
"count": 66,
|
||||
"total_bytes": 53607,
|
||||
"max_bytes": 1222
|
||||
}, {
|
||||
"kind": 38501,
|
||||
"count": 61,
|
||||
"total_bytes": 45175,
|
||||
"max_bytes": 744
|
||||
}, {
|
||||
"kind": 10002,
|
||||
"count": 51,
|
||||
"total_bytes": 63749,
|
||||
"max_bytes": 42385
|
||||
}, {
|
||||
"kind": 0,
|
||||
"count": 47,
|
||||
"total_bytes": 33672,
|
||||
"max_bytes": 1611
|
||||
}, {
|
||||
"kind": 37195,
|
||||
"count": 44,
|
||||
"total_bytes": 32855,
|
||||
"max_bytes": 771
|
||||
}, {
|
||||
"kind": 24242,
|
||||
"count": 37,
|
||||
"total_bytes": 21423,
|
||||
"max_bytes": 579
|
||||
}, {
|
||||
"kind": 25050,
|
||||
"count": 36,
|
||||
"total_bytes": 15972,
|
||||
"max_bytes": 465
|
||||
}, {
|
||||
"kind": 7,
|
||||
"count": 36,
|
||||
"total_bytes": 18965,
|
||||
"max_bytes": 646
|
||||
}, {
|
||||
"kind": 22613,
|
||||
"count": 35,
|
||||
"total_bytes": 26154,
|
||||
"max_bytes": 1134
|
||||
}, {
|
||||
"kind": 22484,
|
||||
"count": 32,
|
||||
"total_bytes": 29125,
|
||||
"max_bytes": 1163
|
||||
}, {
|
||||
"kind": 22749,
|
||||
"count": 29,
|
||||
"total_bytes": 12441,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 24133,
|
||||
"count": 25,
|
||||
"total_bytes": 37446,
|
||||
"max_bytes": 7334
|
||||
}, {
|
||||
"kind": 22601,
|
||||
"count": 25,
|
||||
"total_bytes": 10700,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22507,
|
||||
"count": 24,
|
||||
"total_bytes": 22582,
|
||||
"max_bytes": 1165
|
||||
}, {
|
||||
"kind": 1059,
|
||||
"count": 23,
|
||||
"total_bytes": 41391,
|
||||
"max_bytes": 2897
|
||||
}, {
|
||||
"kind": 22699,
|
||||
"count": 23,
|
||||
"total_bytes": 9844,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22676,
|
||||
"count": 23,
|
||||
"total_bytes": 9821,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22774,
|
||||
"count": 20,
|
||||
"total_bytes": 8560,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22795,
|
||||
"count": 20,
|
||||
"total_bytes": 8580,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22655,
|
||||
"count": 20,
|
||||
"total_bytes": 8560,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 23003,
|
||||
"count": 20,
|
||||
"total_bytes": 8560,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 30382,
|
||||
"count": 20,
|
||||
"total_bytes": 9960,
|
||||
"max_bytes": 498
|
||||
}, {
|
||||
"kind": 29333,
|
||||
"count": 20,
|
||||
"total_bytes": 9840,
|
||||
"max_bytes": 492
|
||||
}, {
|
||||
"kind": 25555,
|
||||
"count": 18,
|
||||
"total_bytes": 62434,
|
||||
"max_bytes": 17003
|
||||
}, {
|
||||
"kind": 11998,
|
||||
"count": 18,
|
||||
"total_bytes": 8322,
|
||||
"max_bytes": 465
|
||||
}, {
|
||||
"kind": 31990,
|
||||
"count": 18,
|
||||
"total_bytes": 16845,
|
||||
"max_bytes": 1465
|
||||
}, {
|
||||
"kind": 4,
|
||||
"count": 18,
|
||||
"total_bytes": 28064,
|
||||
"max_bytes": 17018
|
||||
}, {
|
||||
"kind": 13194,
|
||||
"count": 18,
|
||||
"total_bytes": 9252,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 22689,
|
||||
"count": 17,
|
||||
"total_bytes": 7259,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 5300,
|
||||
"count": 17,
|
||||
"total_bytes": 10495,
|
||||
"max_bytes": 701
|
||||
}, {
|
||||
"kind": 445,
|
||||
"count": 17,
|
||||
"total_bytes": 81892,
|
||||
"max_bytes": 19620
|
||||
}, {
|
||||
"kind": 20000,
|
||||
"count": 15,
|
||||
"total_bytes": 7045,
|
||||
"max_bytes": 546
|
||||
}, {
|
||||
"kind": 20387,
|
||||
"count": 14,
|
||||
"total_bytes": 7196,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 20004,
|
||||
"count": 14,
|
||||
"total_bytes": 7488,
|
||||
"max_bytes": 549
|
||||
}, {
|
||||
"kind": 7368,
|
||||
"count": 13,
|
||||
"total_bytes": 13476,
|
||||
"max_bytes": 1040
|
||||
}, {
|
||||
"kind": 22456,
|
||||
"count": 13,
|
||||
"total_bytes": 6110,
|
||||
"max_bytes": 470
|
||||
}, {
|
||||
"kind": 9735,
|
||||
"count": 13,
|
||||
"total_bytes": 26072,
|
||||
"max_bytes": 2331
|
||||
}, {
|
||||
"kind": 22551,
|
||||
"count": 13,
|
||||
"total_bytes": 11042,
|
||||
"max_bytes": 1161
|
||||
}, {
|
||||
"kind": 22760,
|
||||
"count": 13,
|
||||
"total_bytes": 11014,
|
||||
"max_bytes": 1161
|
||||
}, {
|
||||
"kind": 22658,
|
||||
"count": 13,
|
||||
"total_bytes": 11050,
|
||||
"max_bytes": 1164
|
||||
}, {
|
||||
"kind": 10100,
|
||||
"count": 11,
|
||||
"total_bytes": 20684,
|
||||
"max_bytes": 3825
|
||||
}, {
|
||||
"kind": 30315,
|
||||
"count": 11,
|
||||
"total_bytes": 8899,
|
||||
"max_bytes": 1038
|
||||
}, {
|
||||
"kind": 20787,
|
||||
"count": 11,
|
||||
"total_bytes": 15458,
|
||||
"max_bytes": 2474
|
||||
}, {
|
||||
"kind": 22236,
|
||||
"count": 10,
|
||||
"total_bytes": 7818,
|
||||
"max_bytes": 814
|
||||
}, {
|
||||
"kind": 22832,
|
||||
"count": 10,
|
||||
"total_bytes": 4286,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 38502,
|
||||
"count": 8,
|
||||
"total_bytes": 3080,
|
||||
"max_bytes": 385
|
||||
}, {
|
||||
"kind": 4004,
|
||||
"count": 8,
|
||||
"total_bytes": 9352,
|
||||
"max_bytes": 1169
|
||||
}, {
|
||||
"kind": 22785,
|
||||
"count": 8,
|
||||
"total_bytes": 3432,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 3,
|
||||
"count": 8,
|
||||
"total_bytes": 35850,
|
||||
"max_bytes": 9845
|
||||
}, {
|
||||
"kind": 1985,
|
||||
"count": 8,
|
||||
"total_bytes": 3792,
|
||||
"max_bytes": 474
|
||||
}, {
|
||||
"kind": 22584,
|
||||
"count": 8,
|
||||
"total_bytes": 3416,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22816,
|
||||
"count": 8,
|
||||
"total_bytes": 3432,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22752,
|
||||
"count": 8,
|
||||
"total_bytes": 6212,
|
||||
"max_bytes": 3199
|
||||
}, {
|
||||
"kind": 6,
|
||||
"count": 7,
|
||||
"total_bytes": 10112,
|
||||
"max_bytes": 1872
|
||||
}, {
|
||||
"kind": 443,
|
||||
"count": 7,
|
||||
"total_bytes": 7780,
|
||||
"max_bytes": 1116
|
||||
}, {
|
||||
"kind": 22651,
|
||||
"count": 6,
|
||||
"total_bytes": 2568,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 1077,
|
||||
"count": 6,
|
||||
"total_bytes": 3642,
|
||||
"max_bytes": 607
|
||||
}, {
|
||||
"kind": 26428,
|
||||
"count": 6,
|
||||
"total_bytes": 5254,
|
||||
"max_bytes": 876
|
||||
}, {
|
||||
"kind": 22616,
|
||||
"count": 6,
|
||||
"total_bytes": 2574,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22626,
|
||||
"count": 6,
|
||||
"total_bytes": 2568,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22914,
|
||||
"count": 6,
|
||||
"total_bytes": 2580,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22614,
|
||||
"count": 6,
|
||||
"total_bytes": 2568,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22419,
|
||||
"count": 5,
|
||||
"total_bytes": 2218,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22847,
|
||||
"count": 5,
|
||||
"total_bytes": 2155,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 30088,
|
||||
"count": 5,
|
||||
"total_bytes": 9317,
|
||||
"max_bytes": 1871
|
||||
}, {
|
||||
"kind": 10050,
|
||||
"count": 5,
|
||||
"total_bytes": 2250,
|
||||
"max_bytes": 450
|
||||
}, {
|
||||
"kind": 30091,
|
||||
"count": 5,
|
||||
"total_bytes": 3085,
|
||||
"max_bytes": 629
|
||||
}, {
|
||||
"kind": 30311,
|
||||
"count": 5,
|
||||
"total_bytes": 5153,
|
||||
"max_bytes": 1197
|
||||
}, {
|
||||
"kind": 23080,
|
||||
"count": 5,
|
||||
"total_bytes": 2155,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 38225,
|
||||
"count": 4,
|
||||
"total_bytes": 4077,
|
||||
"max_bytes": 1036
|
||||
}, {
|
||||
"kind": 4244,
|
||||
"count": 4,
|
||||
"total_bytes": 2256,
|
||||
"max_bytes": 564
|
||||
}, {
|
||||
"kind": 26429,
|
||||
"count": 4,
|
||||
"total_bytes": 1964,
|
||||
"max_bytes": 491
|
||||
}, {
|
||||
"kind": 3927,
|
||||
"count": 4,
|
||||
"total_bytes": 2132,
|
||||
"max_bytes": 533
|
||||
}, {
|
||||
"kind": 22806,
|
||||
"count": 4,
|
||||
"total_bytes": 1712,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 30000,
|
||||
"count": 4,
|
||||
"total_bytes": 9358,
|
||||
"max_bytes": 2845
|
||||
}, {
|
||||
"kind": 21617,
|
||||
"count": 4,
|
||||
"total_bytes": 1980,
|
||||
"max_bytes": 495
|
||||
}, {
|
||||
"kind": 20333,
|
||||
"count": 4,
|
||||
"total_bytes": 3188,
|
||||
"max_bytes": 798
|
||||
}, {
|
||||
"kind": 22548,
|
||||
"count": 4,
|
||||
"total_bytes": 1720,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 38503,
|
||||
"count": 4,
|
||||
"total_bytes": 2212,
|
||||
"max_bytes": 553
|
||||
}, {
|
||||
"kind": 30515,
|
||||
"count": 4,
|
||||
"total_bytes": 18496,
|
||||
"max_bytes": 4624
|
||||
}, {
|
||||
"kind": 22740,
|
||||
"count": 4,
|
||||
"total_bytes": 1708,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22226,
|
||||
"count": 3,
|
||||
"total_bytes": 1331,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 10011,
|
||||
"count": 3,
|
||||
"total_bytes": 1375,
|
||||
"max_bytes": 513
|
||||
}, {
|
||||
"kind": 30089,
|
||||
"count": 3,
|
||||
"total_bytes": 6944,
|
||||
"max_bytes": 3412
|
||||
}, {
|
||||
"kind": 30023,
|
||||
"count": 3,
|
||||
"total_bytes": 19822,
|
||||
"max_bytes": 7860
|
||||
}, {
|
||||
"kind": 21060,
|
||||
"count": 3,
|
||||
"total_bytes": 1710,
|
||||
"max_bytes": 570
|
||||
}, {
|
||||
"kind": 22526,
|
||||
"count": 3,
|
||||
"total_bytes": 1290,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22511,
|
||||
"count": 3,
|
||||
"total_bytes": 2383,
|
||||
"max_bytes": 1163
|
||||
}, {
|
||||
"kind": 22167,
|
||||
"count": 3,
|
||||
"total_bytes": 1331,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30213,
|
||||
"count": 3,
|
||||
"total_bytes": 1866,
|
||||
"max_bytes": 632
|
||||
}, {
|
||||
"kind": 22748,
|
||||
"count": 3,
|
||||
"total_bytes": 1284,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 31234,
|
||||
"count": 3,
|
||||
"total_bytes": 4248,
|
||||
"max_bytes": 1416
|
||||
}, {
|
||||
"kind": 22838,
|
||||
"count": 2,
|
||||
"total_bytes": 860,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 38500,
|
||||
"count": 2,
|
||||
"total_bytes": 1424,
|
||||
"max_bytes": 713
|
||||
}, {
|
||||
"kind": 38384,
|
||||
"count": 2,
|
||||
"total_bytes": 1486,
|
||||
"max_bytes": 743
|
||||
}, {
|
||||
"kind": 30443,
|
||||
"count": 2,
|
||||
"total_bytes": 2379,
|
||||
"max_bytes": 1220
|
||||
}, {
|
||||
"kind": 20384,
|
||||
"count": 2,
|
||||
"total_bytes": 1278,
|
||||
"max_bytes": 639
|
||||
}, {
|
||||
"kind": 34237,
|
||||
"count": 2,
|
||||
"total_bytes": 836,
|
||||
"max_bytes": 418
|
||||
}, {
|
||||
"kind": 22280,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 23194,
|
||||
"count": 2,
|
||||
"total_bytes": 1020,
|
||||
"max_bytes": 510
|
||||
}, {
|
||||
"kind": 22320,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30080,
|
||||
"count": 2,
|
||||
"total_bytes": 1971,
|
||||
"max_bytes": 986
|
||||
}, {
|
||||
"kind": 22205,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22770,
|
||||
"count": 2,
|
||||
"total_bytes": 862,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22305,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22356,
|
||||
"count": 2,
|
||||
"total_bytes": 886,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22611,
|
||||
"count": 2,
|
||||
"total_bytes": 852,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22217,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22884,
|
||||
"count": 2,
|
||||
"total_bytes": 860,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 33334,
|
||||
"count": 2,
|
||||
"total_bytes": 1662,
|
||||
"max_bytes": 831
|
||||
}, {
|
||||
"kind": 6300,
|
||||
"count": 2,
|
||||
"total_bytes": 8371,
|
||||
"max_bytes": 5058
|
||||
}, {
|
||||
"kind": 22169,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22190,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30079,
|
||||
"count": 2,
|
||||
"total_bytes": 1750,
|
||||
"max_bytes": 875
|
||||
}, {
|
||||
"kind": 39101,
|
||||
"count": 2,
|
||||
"total_bytes": 1066,
|
||||
"max_bytes": 533
|
||||
}, {
|
||||
"kind": 22345,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22310,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 1111,
|
||||
"count": 2,
|
||||
"total_bytes": 2557,
|
||||
"max_bytes": 1564
|
||||
}, {
|
||||
"kind": 22235,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 38385,
|
||||
"count": 2,
|
||||
"total_bytes": 2552,
|
||||
"max_bytes": 1319
|
||||
}, {
|
||||
"kind": 4747,
|
||||
"count": 1,
|
||||
"total_bytes": 721,
|
||||
"max_bytes": 721
|
||||
}, {
|
||||
"kind": 22844,
|
||||
"count": 1,
|
||||
"total_bytes": 428,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22807,
|
||||
"count": 1,
|
||||
"total_bytes": 3205,
|
||||
"max_bytes": 3205
|
||||
}, {
|
||||
"kind": 30066,
|
||||
"count": 1,
|
||||
"total_bytes": 675,
|
||||
"max_bytes": 675
|
||||
}, {
|
||||
"kind": 4245,
|
||||
"count": 1,
|
||||
"total_bytes": 444,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 7376,
|
||||
"count": 1,
|
||||
"total_bytes": 521,
|
||||
"max_bytes": 521
|
||||
}, {
|
||||
"kind": 22450,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22261,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 4243,
|
||||
"count": 1,
|
||||
"total_bytes": 564,
|
||||
"max_bytes": 564
|
||||
}, {
|
||||
"kind": 22242,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 10063,
|
||||
"count": 1,
|
||||
"total_bytes": 415,
|
||||
"max_bytes": 415
|
||||
}, {
|
||||
"kind": 22306,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22174,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22831,
|
||||
"count": 1,
|
||||
"total_bytes": 3182,
|
||||
"max_bytes": 3182
|
||||
}, {
|
||||
"kind": 22227,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 7375,
|
||||
"count": 1,
|
||||
"total_bytes": 8629,
|
||||
"max_bytes": 8629
|
||||
}, {
|
||||
"kind": 22685,
|
||||
"count": 1,
|
||||
"total_bytes": 553,
|
||||
"max_bytes": 553
|
||||
}, {
|
||||
"kind": 22299,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22193,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22975,
|
||||
"count": 1,
|
||||
"total_bytes": 3195,
|
||||
"max_bytes": 3195
|
||||
}, {
|
||||
"kind": 30380,
|
||||
"count": 1,
|
||||
"total_bytes": 454,
|
||||
"max_bytes": 454
|
||||
}, {
|
||||
"kind": 20,
|
||||
"count": 1,
|
||||
"total_bytes": 860,
|
||||
"max_bytes": 860
|
||||
}, {
|
||||
"kind": 10030,
|
||||
"count": 1,
|
||||
"total_bytes": 405,
|
||||
"max_bytes": 405
|
||||
}, {
|
||||
"kind": 30087,
|
||||
"count": 1,
|
||||
"total_bytes": 7325,
|
||||
"max_bytes": 7325
|
||||
}, {
|
||||
"kind": 30090,
|
||||
"count": 1,
|
||||
"total_bytes": 1515,
|
||||
"max_bytes": 1515
|
||||
}, {
|
||||
"kind": 22220,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 39019,
|
||||
"count": 1,
|
||||
"total_bytes": 961,
|
||||
"max_bytes": 961
|
||||
}, {
|
||||
"kind": 39015,
|
||||
"count": 1,
|
||||
"total_bytes": 696,
|
||||
"max_bytes": 696
|
||||
}, {
|
||||
"kind": 30617,
|
||||
"count": 1,
|
||||
"total_bytes": 1089,
|
||||
"max_bytes": 1089
|
||||
}, {
|
||||
"kind": 30618,
|
||||
"count": 1,
|
||||
"total_bytes": 733,
|
||||
"max_bytes": 733
|
||||
}, {
|
||||
"kind": 31991,
|
||||
"count": 1,
|
||||
"total_bytes": 461,
|
||||
"max_bytes": 461
|
||||
}, {
|
||||
"kind": 1080,
|
||||
"count": 1,
|
||||
"total_bytes": 949,
|
||||
"max_bytes": 949
|
||||
}, {
|
||||
"kind": 3434,
|
||||
"count": 1,
|
||||
"total_bytes": 705,
|
||||
"max_bytes": 705
|
||||
}, {
|
||||
"kind": 33333,
|
||||
"count": 1,
|
||||
"total_bytes": 2346,
|
||||
"max_bytes": 2346
|
||||
}, {
|
||||
"kind": 22735,
|
||||
"count": 1,
|
||||
"total_bytes": 430,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22415,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 21966,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 11316,
|
||||
"count": 1,
|
||||
"total_bytes": 725,
|
||||
"max_bytes": 725
|
||||
}, {
|
||||
"kind": 11317,
|
||||
"count": 1,
|
||||
"total_bytes": 12051,
|
||||
"max_bytes": 12051
|
||||
}, {
|
||||
"kind": 25195,
|
||||
"count": 1,
|
||||
"total_bytes": 678,
|
||||
"max_bytes": 678
|
||||
}, {
|
||||
"kind": 25196,
|
||||
"count": 1,
|
||||
"total_bytes": 1362,
|
||||
"max_bytes": 1362
|
||||
}, {
|
||||
"kind": 22402,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 31510,
|
||||
"count": 1,
|
||||
"total_bytes": 979,
|
||||
"max_bytes": 979
|
||||
}, {
|
||||
"kind": 1078,
|
||||
"count": 1,
|
||||
"total_bytes": 14200,
|
||||
"max_bytes": 14200
|
||||
}, {
|
||||
"kind": 38383,
|
||||
"count": 1,
|
||||
"total_bytes": 685,
|
||||
"max_bytes": 685
|
||||
}]
|
||||
}
|
||||
@@ -0,0 +1,916 @@
|
||||
{
|
||||
"duration_seconds": 120,
|
||||
"total_events": 5012,
|
||||
"total_bytes": 8091410,
|
||||
"max_event_bytes": 52672,
|
||||
"max_event_kind": 3,
|
||||
"unique_pubkeys": 2034,
|
||||
"relay_count": 3,
|
||||
"relays": [{
|
||||
"url": "wss://relay.primal.net",
|
||||
"events": 1599,
|
||||
"eose": 1,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nos.lol",
|
||||
"events": 2389,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.damus.io",
|
||||
"events": 1024,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true,
|
||||
"raw_responses": []
|
||||
}],
|
||||
"kinds": [{
|
||||
"kind": 21059,
|
||||
"count": 1361,
|
||||
"total_bytes": 4189338,
|
||||
"max_bytes": 5314
|
||||
}, {
|
||||
"kind": 5,
|
||||
"count": 579,
|
||||
"total_bytes": 254363,
|
||||
"max_bytes": 624
|
||||
}, {
|
||||
"kind": 22668,
|
||||
"count": 265,
|
||||
"total_bytes": 113685,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 30078,
|
||||
"count": 190,
|
||||
"total_bytes": 702178,
|
||||
"max_bytes": 14343
|
||||
}, {
|
||||
"kind": 20001,
|
||||
"count": 181,
|
||||
"total_bytes": 108257,
|
||||
"max_bytes": 1489
|
||||
}, {
|
||||
"kind": 22639,
|
||||
"count": 176,
|
||||
"total_bytes": 136058,
|
||||
"max_bytes": 1228
|
||||
}, {
|
||||
"kind": 4515,
|
||||
"count": 168,
|
||||
"total_bytes": 319242,
|
||||
"max_bytes": 14220
|
||||
}, {
|
||||
"kind": 24133,
|
||||
"count": 152,
|
||||
"total_bytes": 464764,
|
||||
"max_bytes": 14162
|
||||
}, {
|
||||
"kind": 22734,
|
||||
"count": 135,
|
||||
"total_bytes": 57645,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 31991,
|
||||
"count": 116,
|
||||
"total_bytes": 53476,
|
||||
"max_bytes": 461
|
||||
}, {
|
||||
"kind": 21050,
|
||||
"count": 84,
|
||||
"total_bytes": 81900,
|
||||
"max_bytes": 2558
|
||||
}, {
|
||||
"kind": 1,
|
||||
"count": 80,
|
||||
"total_bytes": 58412,
|
||||
"max_bytes": 1443
|
||||
}, {
|
||||
"kind": 22795,
|
||||
"count": 76,
|
||||
"total_bytes": 104000,
|
||||
"max_bytes": 1848
|
||||
}, {
|
||||
"kind": 22850,
|
||||
"count": 75,
|
||||
"total_bytes": 33353,
|
||||
"max_bytes": 1169
|
||||
}, {
|
||||
"kind": 38501,
|
||||
"count": 69,
|
||||
"total_bytes": 51105,
|
||||
"max_bytes": 744
|
||||
}, {
|
||||
"kind": 22842,
|
||||
"count": 55,
|
||||
"total_bytes": 92475,
|
||||
"max_bytes": 1849
|
||||
}, {
|
||||
"kind": 10002,
|
||||
"count": 48,
|
||||
"total_bytes": 19784,
|
||||
"max_bytes": 537
|
||||
}, {
|
||||
"kind": 0,
|
||||
"count": 47,
|
||||
"total_bytes": 34961,
|
||||
"max_bytes": 1356
|
||||
}, {
|
||||
"kind": 37195,
|
||||
"count": 38,
|
||||
"total_bytes": 28214,
|
||||
"max_bytes": 771
|
||||
}, {
|
||||
"kind": 7,
|
||||
"count": 38,
|
||||
"total_bytes": 21600,
|
||||
"max_bytes": 779
|
||||
}, {
|
||||
"kind": 25050,
|
||||
"count": 36,
|
||||
"total_bytes": 15972,
|
||||
"max_bytes": 465
|
||||
}, {
|
||||
"kind": 24242,
|
||||
"count": 34,
|
||||
"total_bytes": 19686,
|
||||
"max_bytes": 579
|
||||
}, {
|
||||
"kind": 1059,
|
||||
"count": 33,
|
||||
"total_bytes": 58147,
|
||||
"max_bytes": 3298
|
||||
}, {
|
||||
"kind": 22484,
|
||||
"count": 32,
|
||||
"total_bytes": 29156,
|
||||
"max_bytes": 1164
|
||||
}, {
|
||||
"kind": 22507,
|
||||
"count": 28,
|
||||
"total_bytes": 24308,
|
||||
"max_bytes": 1165
|
||||
}, {
|
||||
"kind": 22613,
|
||||
"count": 25,
|
||||
"total_bytes": 17238,
|
||||
"max_bytes": 691
|
||||
}, {
|
||||
"kind": 29333,
|
||||
"count": 25,
|
||||
"total_bytes": 12300,
|
||||
"max_bytes": 492
|
||||
}, {
|
||||
"kind": 22601,
|
||||
"count": 24,
|
||||
"total_bytes": 10272,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 5300,
|
||||
"count": 23,
|
||||
"total_bytes": 14096,
|
||||
"max_bytes": 701
|
||||
}, {
|
||||
"kind": 22751,
|
||||
"count": 23,
|
||||
"total_bytes": 9798,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22699,
|
||||
"count": 22,
|
||||
"total_bytes": 9416,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 11998,
|
||||
"count": 22,
|
||||
"total_bytes": 10182,
|
||||
"max_bytes": 465
|
||||
}, {
|
||||
"kind": 22676,
|
||||
"count": 22,
|
||||
"total_bytes": 9394,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 13194,
|
||||
"count": 21,
|
||||
"total_bytes": 10617,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 22774,
|
||||
"count": 20,
|
||||
"total_bytes": 8560,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 23003,
|
||||
"count": 20,
|
||||
"total_bytes": 8560,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22655,
|
||||
"count": 19,
|
||||
"total_bytes": 8132,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22543,
|
||||
"count": 19,
|
||||
"total_bytes": 34993,
|
||||
"max_bytes": 1848
|
||||
}, {
|
||||
"kind": 22455,
|
||||
"count": 19,
|
||||
"total_bytes": 34943,
|
||||
"max_bytes": 1844
|
||||
}, {
|
||||
"kind": 25555,
|
||||
"count": 19,
|
||||
"total_bytes": 94673,
|
||||
"max_bytes": 17111
|
||||
}, {
|
||||
"kind": 30443,
|
||||
"count": 19,
|
||||
"total_bytes": 22379,
|
||||
"max_bytes": 1260
|
||||
}, {
|
||||
"kind": 22777,
|
||||
"count": 19,
|
||||
"total_bytes": 16685,
|
||||
"max_bytes": 1651
|
||||
}, {
|
||||
"kind": 22891,
|
||||
"count": 18,
|
||||
"total_bytes": 33189,
|
||||
"max_bytes": 1848
|
||||
}, {
|
||||
"kind": 31990,
|
||||
"count": 17,
|
||||
"total_bytes": 15825,
|
||||
"max_bytes": 1465
|
||||
}, {
|
||||
"kind": 20000,
|
||||
"count": 16,
|
||||
"total_bytes": 7206,
|
||||
"max_bytes": 522
|
||||
}, {
|
||||
"kind": 32123,
|
||||
"count": 14,
|
||||
"total_bytes": 10528,
|
||||
"max_bytes": 900
|
||||
}, {
|
||||
"kind": 22456,
|
||||
"count": 13,
|
||||
"total_bytes": 6110,
|
||||
"max_bytes": 470
|
||||
}, {
|
||||
"kind": 20004,
|
||||
"count": 13,
|
||||
"total_bytes": 6741,
|
||||
"max_bytes": 549
|
||||
}, {
|
||||
"kind": 22591,
|
||||
"count": 13,
|
||||
"total_bytes": 6348,
|
||||
"max_bytes": 697
|
||||
}, {
|
||||
"kind": 20787,
|
||||
"count": 12,
|
||||
"total_bytes": 16864,
|
||||
"max_bytes": 2478
|
||||
}, {
|
||||
"kind": 4,
|
||||
"count": 12,
|
||||
"total_bytes": 7972,
|
||||
"max_bytes": 786
|
||||
}, {
|
||||
"kind": 20387,
|
||||
"count": 12,
|
||||
"total_bytes": 6168,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 38502,
|
||||
"count": 12,
|
||||
"total_bytes": 4620,
|
||||
"max_bytes": 385
|
||||
}, {
|
||||
"kind": 10100,
|
||||
"count": 11,
|
||||
"total_bytes": 20938,
|
||||
"max_bytes": 3825
|
||||
}, {
|
||||
"kind": 20050,
|
||||
"count": 11,
|
||||
"total_bytes": 9711,
|
||||
"max_bytes": 891
|
||||
}, {
|
||||
"kind": 3,
|
||||
"count": 10,
|
||||
"total_bytes": 72137,
|
||||
"max_bytes": 52672
|
||||
}, {
|
||||
"kind": 9735,
|
||||
"count": 10,
|
||||
"total_bytes": 20833,
|
||||
"max_bytes": 2143
|
||||
}, {
|
||||
"kind": 445,
|
||||
"count": 10,
|
||||
"total_bytes": 17866,
|
||||
"max_bytes": 4126
|
||||
}, {
|
||||
"kind": 22626,
|
||||
"count": 10,
|
||||
"total_bytes": 4280,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 7368,
|
||||
"count": 9,
|
||||
"total_bytes": 9343,
|
||||
"max_bytes": 1041
|
||||
}, {
|
||||
"kind": 22736,
|
||||
"count": 9,
|
||||
"total_bytes": 3816,
|
||||
"max_bytes": 424
|
||||
}, {
|
||||
"kind": 1985,
|
||||
"count": 8,
|
||||
"total_bytes": 3810,
|
||||
"max_bytes": 483
|
||||
}, {
|
||||
"kind": 30091,
|
||||
"count": 8,
|
||||
"total_bytes": 4927,
|
||||
"max_bytes": 629
|
||||
}, {
|
||||
"kind": 30315,
|
||||
"count": 8,
|
||||
"total_bytes": 4522,
|
||||
"max_bytes": 872
|
||||
}, {
|
||||
"kind": 25055,
|
||||
"count": 8,
|
||||
"total_bytes": 10605,
|
||||
"max_bytes": 1764
|
||||
}, {
|
||||
"kind": 22791,
|
||||
"count": 8,
|
||||
"total_bytes": 3416,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22816,
|
||||
"count": 8,
|
||||
"total_bytes": 3432,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 4004,
|
||||
"count": 8,
|
||||
"total_bytes": 9352,
|
||||
"max_bytes": 1169
|
||||
}, {
|
||||
"kind": 30088,
|
||||
"count": 8,
|
||||
"total_bytes": 14929,
|
||||
"max_bytes": 1871
|
||||
}, {
|
||||
"kind": 31234,
|
||||
"count": 8,
|
||||
"total_bytes": 14048,
|
||||
"max_bytes": 1756
|
||||
}, {
|
||||
"kind": 22813,
|
||||
"count": 7,
|
||||
"total_bytes": 2996,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22957,
|
||||
"count": 7,
|
||||
"total_bytes": 3010,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 30089,
|
||||
"count": 7,
|
||||
"total_bytes": 45972,
|
||||
"max_bytes": 27988
|
||||
}, {
|
||||
"kind": 32678,
|
||||
"count": 7,
|
||||
"total_bytes": 5704,
|
||||
"max_bytes": 900
|
||||
}, {
|
||||
"kind": 22832,
|
||||
"count": 6,
|
||||
"total_bytes": 2574,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22897,
|
||||
"count": 6,
|
||||
"total_bytes": 2586,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22549,
|
||||
"count": 6,
|
||||
"total_bytes": 2574,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22702,
|
||||
"count": 6,
|
||||
"total_bytes": 4753,
|
||||
"max_bytes": 2618
|
||||
}, {
|
||||
"kind": 20333,
|
||||
"count": 6,
|
||||
"total_bytes": 4780,
|
||||
"max_bytes": 798
|
||||
}, {
|
||||
"kind": 30023,
|
||||
"count": 6,
|
||||
"total_bytes": 21101,
|
||||
"max_bytes": 5056
|
||||
}, {
|
||||
"kind": 22568,
|
||||
"count": 5,
|
||||
"total_bytes": 2135,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 38385,
|
||||
"count": 5,
|
||||
"total_bytes": 6849,
|
||||
"max_bytes": 1496
|
||||
}, {
|
||||
"kind": 4244,
|
||||
"count": 5,
|
||||
"total_bytes": 2820,
|
||||
"max_bytes": 564
|
||||
}, {
|
||||
"kind": 22717,
|
||||
"count": 5,
|
||||
"total_bytes": 2135,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 21617,
|
||||
"count": 4,
|
||||
"total_bytes": 1980,
|
||||
"max_bytes": 495
|
||||
}, {
|
||||
"kind": 38225,
|
||||
"count": 4,
|
||||
"total_bytes": 4061,
|
||||
"max_bytes": 1039
|
||||
}, {
|
||||
"kind": 6,
|
||||
"count": 4,
|
||||
"total_bytes": 8823,
|
||||
"max_bytes": 3647
|
||||
}, {
|
||||
"kind": 22333,
|
||||
"count": 4,
|
||||
"total_bytes": 1773,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22962,
|
||||
"count": 3,
|
||||
"total_bytes": 1290,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 33334,
|
||||
"count": 3,
|
||||
"total_bytes": 2229,
|
||||
"max_bytes": 831
|
||||
}, {
|
||||
"kind": 1002,
|
||||
"count": 3,
|
||||
"total_bytes": 2793,
|
||||
"max_bytes": 979
|
||||
}, {
|
||||
"kind": 22244,
|
||||
"count": 3,
|
||||
"total_bytes": 1330,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22907,
|
||||
"count": 3,
|
||||
"total_bytes": 1287,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 10011,
|
||||
"count": 3,
|
||||
"total_bytes": 1229,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22258,
|
||||
"count": 3,
|
||||
"total_bytes": 1330,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22245,
|
||||
"count": 3,
|
||||
"total_bytes": 1331,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30618,
|
||||
"count": 3,
|
||||
"total_bytes": 1755,
|
||||
"max_bytes": 733
|
||||
}, {
|
||||
"kind": 22296,
|
||||
"count": 3,
|
||||
"total_bytes": 1331,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 38503,
|
||||
"count": 3,
|
||||
"total_bytes": 1659,
|
||||
"max_bytes": 553
|
||||
}, {
|
||||
"kind": 22338,
|
||||
"count": 3,
|
||||
"total_bytes": 1330,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22195,
|
||||
"count": 3,
|
||||
"total_bytes": 1331,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22342,
|
||||
"count": 3,
|
||||
"total_bytes": 1331,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 10050,
|
||||
"count": 3,
|
||||
"total_bytes": 1350,
|
||||
"max_bytes": 450
|
||||
}, {
|
||||
"kind": 30311,
|
||||
"count": 3,
|
||||
"total_bytes": 3414,
|
||||
"max_bytes": 1197
|
||||
}, {
|
||||
"kind": 32680,
|
||||
"count": 2,
|
||||
"total_bytes": 1376,
|
||||
"max_bytes": 688
|
||||
}, {
|
||||
"kind": 30380,
|
||||
"count": 2,
|
||||
"total_bytes": 908,
|
||||
"max_bytes": 454
|
||||
}, {
|
||||
"kind": 22611,
|
||||
"count": 2,
|
||||
"total_bytes": 852,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 4243,
|
||||
"count": 2,
|
||||
"total_bytes": 1128,
|
||||
"max_bytes": 564
|
||||
}, {
|
||||
"kind": 22526,
|
||||
"count": 2,
|
||||
"total_bytes": 860,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22320,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 4245,
|
||||
"count": 2,
|
||||
"total_bytes": 888,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 1984,
|
||||
"count": 2,
|
||||
"total_bytes": 873,
|
||||
"max_bytes": 446
|
||||
}, {
|
||||
"kind": 1111,
|
||||
"count": 2,
|
||||
"total_bytes": 3115,
|
||||
"max_bytes": 1558
|
||||
}, {
|
||||
"kind": 22311,
|
||||
"count": 2,
|
||||
"total_bytes": 886,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22662,
|
||||
"count": 2,
|
||||
"total_bytes": 858,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22089,
|
||||
"count": 2,
|
||||
"total_bytes": 886,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22221,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22157,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 38384,
|
||||
"count": 2,
|
||||
"total_bytes": 1486,
|
||||
"max_bytes": 743
|
||||
}, {
|
||||
"kind": 20384,
|
||||
"count": 2,
|
||||
"total_bytes": 1278,
|
||||
"max_bytes": 639
|
||||
}, {
|
||||
"kind": 30080,
|
||||
"count": 2,
|
||||
"total_bytes": 1679,
|
||||
"max_bytes": 985
|
||||
}, {
|
||||
"kind": 39101,
|
||||
"count": 2,
|
||||
"total_bytes": 1066,
|
||||
"max_bytes": 533
|
||||
}, {
|
||||
"kind": 6300,
|
||||
"count": 2,
|
||||
"total_bytes": 11904,
|
||||
"max_bytes": 6898
|
||||
}, {
|
||||
"kind": 10003,
|
||||
"count": 2,
|
||||
"total_bytes": 14466,
|
||||
"max_bytes": 7233
|
||||
}, {
|
||||
"kind": 30515,
|
||||
"count": 2,
|
||||
"total_bytes": 9248,
|
||||
"max_bytes": 4624
|
||||
}, {
|
||||
"kind": 22829,
|
||||
"count": 2,
|
||||
"total_bytes": 6387,
|
||||
"max_bytes": 3194
|
||||
}, {
|
||||
"kind": 22106,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 31927,
|
||||
"count": 2,
|
||||
"total_bytes": 3000,
|
||||
"max_bytes": 1500
|
||||
}, {
|
||||
"kind": 31510,
|
||||
"count": 2,
|
||||
"total_bytes": 1959,
|
||||
"max_bytes": 980
|
||||
}, {
|
||||
"kind": 3927,
|
||||
"count": 2,
|
||||
"total_bytes": 1066,
|
||||
"max_bytes": 533
|
||||
}, {
|
||||
"kind": 1040,
|
||||
"count": 2,
|
||||
"total_bytes": 2096,
|
||||
"max_bytes": 1048
|
||||
}, {
|
||||
"kind": 31000,
|
||||
"count": 2,
|
||||
"total_bytes": 1204,
|
||||
"max_bytes": 616
|
||||
}, {
|
||||
"kind": 22201,
|
||||
"count": 2,
|
||||
"total_bytes": 886,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22269,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22818,
|
||||
"count": 2,
|
||||
"total_bytes": 852,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22364,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 25195,
|
||||
"count": 1,
|
||||
"total_bytes": 678,
|
||||
"max_bytes": 678
|
||||
}, {
|
||||
"kind": 25196,
|
||||
"count": 1,
|
||||
"total_bytes": 1362,
|
||||
"max_bytes": 1362
|
||||
}, {
|
||||
"kind": 22283,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 10030,
|
||||
"count": 1,
|
||||
"total_bytes": 405,
|
||||
"max_bytes": 405
|
||||
}, {
|
||||
"kind": 22706,
|
||||
"count": 1,
|
||||
"total_bytes": 3192,
|
||||
"max_bytes": 3192
|
||||
}, {
|
||||
"kind": 22236,
|
||||
"count": 1,
|
||||
"total_bytes": 737,
|
||||
"max_bytes": 737
|
||||
}, {
|
||||
"kind": 31339,
|
||||
"count": 1,
|
||||
"total_bytes": 1470,
|
||||
"max_bytes": 1470
|
||||
}, {
|
||||
"kind": 22651,
|
||||
"count": 1,
|
||||
"total_bytes": 428,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 38500,
|
||||
"count": 1,
|
||||
"total_bytes": 713,
|
||||
"max_bytes": 713
|
||||
}, {
|
||||
"kind": 10000,
|
||||
"count": 1,
|
||||
"total_bytes": 1311,
|
||||
"max_bytes": 1311
|
||||
}, {
|
||||
"kind": 31926,
|
||||
"count": 1,
|
||||
"total_bytes": 1038,
|
||||
"max_bytes": 1038
|
||||
}, {
|
||||
"kind": 22757,
|
||||
"count": 1,
|
||||
"total_bytes": 428,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 39015,
|
||||
"count": 1,
|
||||
"total_bytes": 696,
|
||||
"max_bytes": 696
|
||||
}, {
|
||||
"kind": 30617,
|
||||
"count": 1,
|
||||
"total_bytes": 1089,
|
||||
"max_bytes": 1089
|
||||
}, {
|
||||
"kind": 22234,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 30815,
|
||||
"count": 1,
|
||||
"total_bytes": 37534,
|
||||
"max_bytes": 37534
|
||||
}, {
|
||||
"kind": 1078,
|
||||
"count": 1,
|
||||
"total_bytes": 13939,
|
||||
"max_bytes": 13939
|
||||
}, {
|
||||
"kind": 39050,
|
||||
"count": 1,
|
||||
"total_bytes": 1843,
|
||||
"max_bytes": 1843
|
||||
}, {
|
||||
"kind": 22281,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 30166,
|
||||
"count": 1,
|
||||
"total_bytes": 808,
|
||||
"max_bytes": 808
|
||||
}, {
|
||||
"kind": 22772,
|
||||
"count": 1,
|
||||
"total_bytes": 429,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22356,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 30554,
|
||||
"count": 1,
|
||||
"total_bytes": 609,
|
||||
"max_bytes": 609
|
||||
}, {
|
||||
"kind": 38422,
|
||||
"count": 1,
|
||||
"total_bytes": 20025,
|
||||
"max_bytes": 20025
|
||||
}, {
|
||||
"kind": 38000,
|
||||
"count": 1,
|
||||
"total_bytes": 562,
|
||||
"max_bytes": 562
|
||||
}, {
|
||||
"kind": 22069,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 1050,
|
||||
"count": 1,
|
||||
"total_bytes": 437,
|
||||
"max_bytes": 437
|
||||
}, {
|
||||
"kind": 33051,
|
||||
"count": 1,
|
||||
"total_bytes": 522,
|
||||
"max_bytes": 522
|
||||
}, {
|
||||
"kind": 39036,
|
||||
"count": 1,
|
||||
"total_bytes": 1138,
|
||||
"max_bytes": 1138
|
||||
}, {
|
||||
"kind": 23194,
|
||||
"count": 1,
|
||||
"total_bytes": 510,
|
||||
"max_bytes": 510
|
||||
}, {
|
||||
"kind": 30081,
|
||||
"count": 1,
|
||||
"total_bytes": 1370,
|
||||
"max_bytes": 1370
|
||||
}, {
|
||||
"kind": 22299,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22556,
|
||||
"count": 1,
|
||||
"total_bytes": 427,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22302,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 39019,
|
||||
"count": 1,
|
||||
"total_bytes": 961,
|
||||
"max_bytes": 961
|
||||
}, {
|
||||
"kind": 30000,
|
||||
"count": 1,
|
||||
"total_bytes": 823,
|
||||
"max_bytes": 823
|
||||
}, {
|
||||
"kind": 38383,
|
||||
"count": 1,
|
||||
"total_bytes": 657,
|
||||
"max_bytes": 657
|
||||
}, {
|
||||
"kind": 30087,
|
||||
"count": 1,
|
||||
"total_bytes": 7325,
|
||||
"max_bytes": 7325
|
||||
}, {
|
||||
"kind": 30090,
|
||||
"count": 1,
|
||||
"total_bytes": 1515,
|
||||
"max_bytes": 1515
|
||||
}]
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
{
|
||||
"duration_seconds": 0,
|
||||
"total_events": 0,
|
||||
"total_bytes": 0,
|
||||
"max_event_bytes": 0,
|
||||
"max_event_kind": 0,
|
||||
"unique_pubkeys": 0,
|
||||
"relay_count": 27,
|
||||
"relays": [{
|
||||
"url": "wss://relay.primal.net",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nos.lol",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.damus.io",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.ditto.pub",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nostr.land",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nostr.wine",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nostr.oxtr.dev",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://spatia-arcana.com/inbox",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://eden.nostr.land",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.nostr.band",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://theforest.nostr1.com",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://wot.utxo.one",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://premium.primal.net",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nostr.mom",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.mostr.pub",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://offchain.pub",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.divine.video",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.nostrplebs.com",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nostr-pub.wellorder.net",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://devrelay.azzamo.net",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.noderunners.network",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nostr-pub.semisol.dev",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.shosho.live",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.nostrcheck.me",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.nostr.info",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.momostr.pink",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://bitsat.molonlabe.holdings",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}],
|
||||
"kinds": []
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
{
|
||||
"duration_seconds": 0,
|
||||
"total_events": 0,
|
||||
"total_bytes": 0,
|
||||
"max_event_bytes": 0,
|
||||
"max_event_kind": 0,
|
||||
"unique_pubkeys": 0,
|
||||
"relay_count": 15,
|
||||
"relays": [{
|
||||
"url": "wss://relay.primal.net",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nos.lol",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.damus.io",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nostr.land",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.ditto.pub",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nostr.oxtr.dev",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://pyramid.fiatjaf.com/inbox",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.mostr.pub",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.divine.video",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nostr.wine",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://theforest.nostr1.com",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.nostrplebs.com",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.shosho.live",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.nostr.band",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.nostr.info",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}],
|
||||
"kinds": []
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"duration_seconds": 0,
|
||||
"total_events": 0,
|
||||
"total_bytes": 0,
|
||||
"max_event_bytes": 0,
|
||||
"max_event_kind": 0,
|
||||
"unique_pubkeys": 0,
|
||||
"relay_count": 11,
|
||||
"relays": [{
|
||||
"url": "wss://relay.primal.net",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nos.lol",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.damus.io",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.ditto.pub",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nostr.bitcoiner.social",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://nostr.land",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://pyramid.fiatjaf.com/inbox",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.divine.video",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.nostrplebs.com",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://eden.nostr.land",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}, {
|
||||
"url": "wss://relay.shosho.live",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false,
|
||||
"raw_responses": []
|
||||
}],
|
||||
"kinds": []
|
||||
}
|
||||
@@ -0,0 +1,834 @@
|
||||
{
|
||||
"duration_seconds": 114,
|
||||
"total_events": 4719,
|
||||
"total_bytes": 6608416,
|
||||
"unique_pubkeys": 1333,
|
||||
"relay_count": 15,
|
||||
"relays": [{
|
||||
"url": "wss://laantungir.net",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false
|
||||
}, {
|
||||
"url": "wss://nos.lol",
|
||||
"events": 804,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 3,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://nostr-pub.wellorder.net",
|
||||
"events": 83,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://nostr.mom",
|
||||
"events": 175,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://nostr.oxtr.dev",
|
||||
"events": 108,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://offchain.pub",
|
||||
"events": 627,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://premium.primal.net",
|
||||
"events": 1,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.damus.io",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false
|
||||
}, {
|
||||
"url": "wss://relay.ditto.pub",
|
||||
"events": 721,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.divine.video",
|
||||
"events": 3,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.momostr.pink",
|
||||
"events": 86,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.mostr.pub",
|
||||
"events": 836,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.nostrplebs.com",
|
||||
"events": 4,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.primal.net",
|
||||
"events": 1239,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://theforest.nostr1.com",
|
||||
"events": 32,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}],
|
||||
"kinds": [{
|
||||
"kind": 21059,
|
||||
"count": 675,
|
||||
"total_bytes": 2192938,
|
||||
"max_bytes": 5314
|
||||
}, {
|
||||
"kind": 30382,
|
||||
"count": 563,
|
||||
"total_bytes": 255591,
|
||||
"max_bytes": 498
|
||||
}, {
|
||||
"kind": 5,
|
||||
"count": 341,
|
||||
"total_bytes": 153667,
|
||||
"max_bytes": 1404
|
||||
}, {
|
||||
"kind": 22639,
|
||||
"count": 231,
|
||||
"total_bytes": 178011,
|
||||
"max_bytes": 1230
|
||||
}, {
|
||||
"kind": 22551,
|
||||
"count": 182,
|
||||
"total_bytes": 78260,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 20001,
|
||||
"count": 143,
|
||||
"total_bytes": 70427,
|
||||
"max_bytes": 1206
|
||||
}, {
|
||||
"kind": 30078,
|
||||
"count": 141,
|
||||
"total_bytes": 1361122,
|
||||
"max_bytes": 44169
|
||||
}, {
|
||||
"kind": 0,
|
||||
"count": 135,
|
||||
"total_bytes": 119793,
|
||||
"max_bytes": 3483
|
||||
}, {
|
||||
"kind": 22734,
|
||||
"count": 122,
|
||||
"total_bytes": 52094,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 24747,
|
||||
"count": 101,
|
||||
"total_bytes": 59352,
|
||||
"max_bytes": 594
|
||||
}, {
|
||||
"kind": 1,
|
||||
"count": 90,
|
||||
"total_bytes": 92140,
|
||||
"max_bytes": 4709
|
||||
}, {
|
||||
"kind": 22668,
|
||||
"count": 88,
|
||||
"total_bytes": 37752,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22850,
|
||||
"count": 83,
|
||||
"total_bytes": 35690,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22870,
|
||||
"count": 76,
|
||||
"total_bytes": 77061,
|
||||
"max_bytes": 2202
|
||||
}, {
|
||||
"kind": 22951,
|
||||
"count": 75,
|
||||
"total_bytes": 77282,
|
||||
"max_bytes": 2204
|
||||
}, {
|
||||
"kind": 10002,
|
||||
"count": 75,
|
||||
"total_bytes": 202196,
|
||||
"max_bytes": 42385
|
||||
}, {
|
||||
"kind": 22912,
|
||||
"count": 74,
|
||||
"total_bytes": 31672,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 38501,
|
||||
"count": 65,
|
||||
"total_bytes": 48152,
|
||||
"max_bytes": 744
|
||||
}, {
|
||||
"kind": 24133,
|
||||
"count": 63,
|
||||
"total_bytes": 72262,
|
||||
"max_bytes": 2898
|
||||
}, {
|
||||
"kind": 6,
|
||||
"count": 50,
|
||||
"total_bytes": 40985,
|
||||
"max_bytes": 3346
|
||||
}, {
|
||||
"kind": 37195,
|
||||
"count": 48,
|
||||
"total_bytes": 36225,
|
||||
"max_bytes": 771
|
||||
}, {
|
||||
"kind": 21050,
|
||||
"count": 48,
|
||||
"total_bytes": 46800,
|
||||
"max_bytes": 2558
|
||||
}, {
|
||||
"kind": 4515,
|
||||
"count": 46,
|
||||
"total_bytes": 81638,
|
||||
"max_bytes": 6028
|
||||
}, {
|
||||
"kind": 25555,
|
||||
"count": 45,
|
||||
"total_bytes": 209551,
|
||||
"max_bytes": 16603
|
||||
}, {
|
||||
"kind": 7,
|
||||
"count": 40,
|
||||
"total_bytes": 22486,
|
||||
"max_bytes": 805
|
||||
}, {
|
||||
"kind": 22917,
|
||||
"count": 39,
|
||||
"total_bytes": 35435,
|
||||
"max_bytes": 1166
|
||||
}, {
|
||||
"kind": 22699,
|
||||
"count": 39,
|
||||
"total_bytes": 26723,
|
||||
"max_bytes": 1166
|
||||
}, {
|
||||
"kind": 22690,
|
||||
"count": 39,
|
||||
"total_bytes": 16770,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22918,
|
||||
"count": 38,
|
||||
"total_bytes": 36470,
|
||||
"max_bytes": 1507
|
||||
}, {
|
||||
"kind": 22832,
|
||||
"count": 37,
|
||||
"total_bytes": 16128,
|
||||
"max_bytes": 446
|
||||
}, {
|
||||
"kind": 25050,
|
||||
"count": 35,
|
||||
"total_bytes": 15507,
|
||||
"max_bytes": 465
|
||||
}, {
|
||||
"kind": 30383,
|
||||
"count": 35,
|
||||
"total_bytes": 18766,
|
||||
"max_bytes": 541
|
||||
}, {
|
||||
"kind": 22713,
|
||||
"count": 34,
|
||||
"total_bytes": 14570,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22698,
|
||||
"count": 34,
|
||||
"total_bytes": 31371,
|
||||
"max_bytes": 1674
|
||||
}, {
|
||||
"kind": 22601,
|
||||
"count": 28,
|
||||
"total_bytes": 11984,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22655,
|
||||
"count": 28,
|
||||
"total_bytes": 11984,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 1059,
|
||||
"count": 23,
|
||||
"total_bytes": 46912,
|
||||
"max_bytes": 5285
|
||||
}, {
|
||||
"kind": 22751,
|
||||
"count": 21,
|
||||
"total_bytes": 8946,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22676,
|
||||
"count": 21,
|
||||
"total_bytes": 8967,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 29333,
|
||||
"count": 20,
|
||||
"total_bytes": 9840,
|
||||
"max_bytes": 492
|
||||
}, {
|
||||
"kind": 5300,
|
||||
"count": 20,
|
||||
"total_bytes": 11959,
|
||||
"max_bytes": 630
|
||||
}, {
|
||||
"kind": 22743,
|
||||
"count": 19,
|
||||
"total_bytes": 8132,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22603,
|
||||
"count": 19,
|
||||
"total_bytes": 8094,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22693,
|
||||
"count": 19,
|
||||
"total_bytes": 8113,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22774,
|
||||
"count": 19,
|
||||
"total_bytes": 8132,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22808,
|
||||
"count": 19,
|
||||
"total_bytes": 8151,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22575,
|
||||
"count": 19,
|
||||
"total_bytes": 8075,
|
||||
"max_bytes": 425
|
||||
}, {
|
||||
"kind": 23003,
|
||||
"count": 19,
|
||||
"total_bytes": 8132,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22949,
|
||||
"count": 19,
|
||||
"total_bytes": 8151,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 23334,
|
||||
"count": 19,
|
||||
"total_bytes": 8189,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 24242,
|
||||
"count": 17,
|
||||
"total_bytes": 9843,
|
||||
"max_bytes": 579
|
||||
}, {
|
||||
"kind": 22816,
|
||||
"count": 16,
|
||||
"total_bytes": 6864,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 20787,
|
||||
"count": 16,
|
||||
"total_bytes": 25100,
|
||||
"max_bytes": 2478
|
||||
}, {
|
||||
"kind": 13194,
|
||||
"count": 15,
|
||||
"total_bytes": 7574,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 38502,
|
||||
"count": 14,
|
||||
"total_bytes": 5390,
|
||||
"max_bytes": 385
|
||||
}, {
|
||||
"kind": 22236,
|
||||
"count": 14,
|
||||
"total_bytes": 11214,
|
||||
"max_bytes": 814
|
||||
}, {
|
||||
"kind": 22613,
|
||||
"count": 13,
|
||||
"total_bytes": 8977,
|
||||
"max_bytes": 694
|
||||
}, {
|
||||
"kind": 30088,
|
||||
"count": 12,
|
||||
"total_bytes": 22340,
|
||||
"max_bytes": 1871
|
||||
}, {
|
||||
"kind": 22484,
|
||||
"count": 12,
|
||||
"total_bytes": 10948,
|
||||
"max_bytes": 1165
|
||||
}, {
|
||||
"kind": 30091,
|
||||
"count": 12,
|
||||
"total_bytes": 7385,
|
||||
"max_bytes": 629
|
||||
}, {
|
||||
"kind": 20004,
|
||||
"count": 11,
|
||||
"total_bytes": 5643,
|
||||
"max_bytes": 549
|
||||
}, {
|
||||
"kind": 31990,
|
||||
"count": 11,
|
||||
"total_bytes": 8711,
|
||||
"max_bytes": 1465
|
||||
}, {
|
||||
"kind": 445,
|
||||
"count": 10,
|
||||
"total_bytes": 17972,
|
||||
"max_bytes": 4126
|
||||
}, {
|
||||
"kind": 22795,
|
||||
"count": 9,
|
||||
"total_bytes": 3861,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22507,
|
||||
"count": 9,
|
||||
"total_bytes": 8480,
|
||||
"max_bytes": 1165
|
||||
}, {
|
||||
"kind": 22922,
|
||||
"count": 9,
|
||||
"total_bytes": 3870,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 24421,
|
||||
"count": 9,
|
||||
"total_bytes": 4644,
|
||||
"max_bytes": 516
|
||||
}, {
|
||||
"kind": 22830,
|
||||
"count": 9,
|
||||
"total_bytes": 7317,
|
||||
"max_bytes": 1168
|
||||
}, {
|
||||
"kind": 20000,
|
||||
"count": 9,
|
||||
"total_bytes": 3854,
|
||||
"max_bytes": 484
|
||||
}, {
|
||||
"kind": 22955,
|
||||
"count": 9,
|
||||
"total_bytes": 3852,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22793,
|
||||
"count": 9,
|
||||
"total_bytes": 3843,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 30315,
|
||||
"count": 8,
|
||||
"total_bytes": 4604,
|
||||
"max_bytes": 926
|
||||
}, {
|
||||
"kind": 20387,
|
||||
"count": 8,
|
||||
"total_bytes": 4112,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 7368,
|
||||
"count": 8,
|
||||
"total_bytes": 8309,
|
||||
"max_bytes": 1041
|
||||
}, {
|
||||
"kind": 4004,
|
||||
"count": 8,
|
||||
"total_bytes": 9352,
|
||||
"max_bytes": 1169
|
||||
}, {
|
||||
"kind": 443,
|
||||
"count": 8,
|
||||
"total_bytes": 8928,
|
||||
"max_bytes": 1116
|
||||
}, {
|
||||
"kind": 11998,
|
||||
"count": 7,
|
||||
"total_bytes": 3255,
|
||||
"max_bytes": 465
|
||||
}, {
|
||||
"kind": 10100,
|
||||
"count": 7,
|
||||
"total_bytes": 11851,
|
||||
"max_bytes": 3825
|
||||
}, {
|
||||
"kind": 22456,
|
||||
"count": 7,
|
||||
"total_bytes": 3290,
|
||||
"max_bytes": 470
|
||||
}, {
|
||||
"kind": 30089,
|
||||
"count": 7,
|
||||
"total_bytes": 157322,
|
||||
"max_bytes": 44372
|
||||
}, {
|
||||
"kind": 22737,
|
||||
"count": 7,
|
||||
"total_bytes": 4669,
|
||||
"max_bytes": 707
|
||||
}, {
|
||||
"kind": 23337,
|
||||
"count": 7,
|
||||
"total_bytes": 3557,
|
||||
"max_bytes": 509
|
||||
}, {
|
||||
"kind": 30515,
|
||||
"count": 7,
|
||||
"total_bytes": 18032,
|
||||
"max_bytes": 2576
|
||||
}, {
|
||||
"kind": 30311,
|
||||
"count": 6,
|
||||
"total_bytes": 5818,
|
||||
"max_bytes": 1197
|
||||
}, {
|
||||
"kind": 1985,
|
||||
"count": 6,
|
||||
"total_bytes": 2860,
|
||||
"max_bytes": 482
|
||||
}, {
|
||||
"kind": 22859,
|
||||
"count": 5,
|
||||
"total_bytes": 8606,
|
||||
"max_bytes": 2195
|
||||
}, {
|
||||
"kind": 4,
|
||||
"count": 5,
|
||||
"total_bytes": 3222,
|
||||
"max_bytes": 722
|
||||
}, {
|
||||
"kind": 10011,
|
||||
"count": 5,
|
||||
"total_bytes": 2027,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22764,
|
||||
"count": 4,
|
||||
"total_bytes": 1712,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22777,
|
||||
"count": 4,
|
||||
"total_bytes": 2790,
|
||||
"max_bytes": 698
|
||||
}, {
|
||||
"kind": 4244,
|
||||
"count": 4,
|
||||
"total_bytes": 2256,
|
||||
"max_bytes": 564
|
||||
}, {
|
||||
"kind": 30023,
|
||||
"count": 4,
|
||||
"total_bytes": 22789,
|
||||
"max_bytes": 6817
|
||||
}, {
|
||||
"kind": 9735,
|
||||
"count": 4,
|
||||
"total_bytes": 7033,
|
||||
"max_bytes": 1805
|
||||
}, {
|
||||
"kind": 20333,
|
||||
"count": 4,
|
||||
"total_bytes": 3188,
|
||||
"max_bytes": 798
|
||||
}, {
|
||||
"kind": 3,
|
||||
"count": 3,
|
||||
"total_bytes": 26232,
|
||||
"max_bytes": 14166
|
||||
}, {
|
||||
"kind": 38503,
|
||||
"count": 3,
|
||||
"total_bytes": 1655,
|
||||
"max_bytes": 552
|
||||
}, {
|
||||
"kind": 10050,
|
||||
"count": 3,
|
||||
"total_bytes": 1411,
|
||||
"max_bytes": 511
|
||||
}, {
|
||||
"kind": 21617,
|
||||
"count": 3,
|
||||
"total_bytes": 1485,
|
||||
"max_bytes": 495
|
||||
}, {
|
||||
"kind": 1984,
|
||||
"count": 3,
|
||||
"total_bytes": 1986,
|
||||
"max_bytes": 662
|
||||
}, {
|
||||
"kind": 3927,
|
||||
"count": 3,
|
||||
"total_bytes": 1599,
|
||||
"max_bytes": 533
|
||||
}, {
|
||||
"kind": 3434,
|
||||
"count": 3,
|
||||
"total_bytes": 1907,
|
||||
"max_bytes": 665
|
||||
}, {
|
||||
"kind": 22514,
|
||||
"count": 2,
|
||||
"total_bytes": 856,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 33334,
|
||||
"count": 2,
|
||||
"total_bytes": 1662,
|
||||
"max_bytes": 831
|
||||
}, {
|
||||
"kind": 38500,
|
||||
"count": 2,
|
||||
"total_bytes": 1424,
|
||||
"max_bytes": 713
|
||||
}, {
|
||||
"kind": 22526,
|
||||
"count": 2,
|
||||
"total_bytes": 860,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 30380,
|
||||
"count": 2,
|
||||
"total_bytes": 908,
|
||||
"max_bytes": 454
|
||||
}, {
|
||||
"kind": 23194,
|
||||
"count": 2,
|
||||
"total_bytes": 1020,
|
||||
"max_bytes": 510
|
||||
}, {
|
||||
"kind": 23042,
|
||||
"count": 2,
|
||||
"total_bytes": 858,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 38385,
|
||||
"count": 2,
|
||||
"total_bytes": 2692,
|
||||
"max_bytes": 1478
|
||||
}, {
|
||||
"kind": 30443,
|
||||
"count": 2,
|
||||
"total_bytes": 2369,
|
||||
"max_bytes": 1219
|
||||
}, {
|
||||
"kind": 22747,
|
||||
"count": 2,
|
||||
"total_bytes": 2064,
|
||||
"max_bytes": 1288
|
||||
}, {
|
||||
"kind": 4245,
|
||||
"count": 2,
|
||||
"total_bytes": 888,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 1111,
|
||||
"count": 2,
|
||||
"total_bytes": 1936,
|
||||
"max_bytes": 981
|
||||
}, {
|
||||
"kind": 38383,
|
||||
"count": 2,
|
||||
"total_bytes": 1439,
|
||||
"max_bytes": 720
|
||||
}, {
|
||||
"kind": 4243,
|
||||
"count": 2,
|
||||
"total_bytes": 1128,
|
||||
"max_bytes": 564
|
||||
}, {
|
||||
"kind": 38225,
|
||||
"count": 1,
|
||||
"total_bytes": 978,
|
||||
"max_bytes": 978
|
||||
}, {
|
||||
"kind": 30618,
|
||||
"count": 1,
|
||||
"total_bytes": 733,
|
||||
"max_bytes": 733
|
||||
}, {
|
||||
"kind": 31510,
|
||||
"count": 1,
|
||||
"total_bytes": 981,
|
||||
"max_bytes": 981
|
||||
}, {
|
||||
"kind": 30617,
|
||||
"count": 1,
|
||||
"total_bytes": 1089,
|
||||
"max_bytes": 1089
|
||||
}, {
|
||||
"kind": 1077,
|
||||
"count": 1,
|
||||
"total_bytes": 607,
|
||||
"max_bytes": 607
|
||||
}, {
|
||||
"kind": 20201,
|
||||
"count": 1,
|
||||
"total_bytes": 491,
|
||||
"max_bytes": 491
|
||||
}, {
|
||||
"kind": 20200,
|
||||
"count": 1,
|
||||
"total_bytes": 491,
|
||||
"max_bytes": 491
|
||||
}, {
|
||||
"kind": 1078,
|
||||
"count": 1,
|
||||
"total_bytes": 14173,
|
||||
"max_bytes": 14173
|
||||
}, {
|
||||
"kind": 6300,
|
||||
"count": 1,
|
||||
"total_bytes": 3698,
|
||||
"max_bytes": 3698
|
||||
}, {
|
||||
"kind": 11316,
|
||||
"count": 1,
|
||||
"total_bytes": 791,
|
||||
"max_bytes": 791
|
||||
}, {
|
||||
"kind": 11317,
|
||||
"count": 1,
|
||||
"total_bytes": 2873,
|
||||
"max_bytes": 2873
|
||||
}, {
|
||||
"kind": 17,
|
||||
"count": 1,
|
||||
"total_bytes": 610,
|
||||
"max_bytes": 610
|
||||
}, {
|
||||
"kind": 23059,
|
||||
"count": 1,
|
||||
"total_bytes": 429,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22806,
|
||||
"count": 1,
|
||||
"total_bytes": 1520,
|
||||
"max_bytes": 1520
|
||||
}, {
|
||||
"kind": 22120,
|
||||
"count": 1,
|
||||
"total_bytes": 1127,
|
||||
"max_bytes": 1127
|
||||
}, {
|
||||
"kind": 13196,
|
||||
"count": 1,
|
||||
"total_bytes": 656,
|
||||
"max_bytes": 656
|
||||
}, {
|
||||
"kind": 24913,
|
||||
"count": 1,
|
||||
"total_bytes": 431,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 12222,
|
||||
"count": 1,
|
||||
"total_bytes": 579,
|
||||
"max_bytes": 579
|
||||
}, {
|
||||
"kind": 1040,
|
||||
"count": 1,
|
||||
"total_bytes": 1048,
|
||||
"max_bytes": 1048
|
||||
}, {
|
||||
"kind": 22119,
|
||||
"count": 1,
|
||||
"total_bytes": 845,
|
||||
"max_bytes": 845
|
||||
}, {
|
||||
"kind": 10312,
|
||||
"count": 1,
|
||||
"total_bytes": 472,
|
||||
"max_bytes": 472
|
||||
}, {
|
||||
"kind": 3079,
|
||||
"count": 1,
|
||||
"total_bytes": 909,
|
||||
"max_bytes": 909
|
||||
}, {
|
||||
"kind": 30000,
|
||||
"count": 1,
|
||||
"total_bytes": 594,
|
||||
"max_bytes": 594
|
||||
}]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,704 @@
|
||||
{
|
||||
"duration_seconds": 32,
|
||||
"total_events": 1485,
|
||||
"total_bytes": 1812166,
|
||||
"unique_pubkeys": 511,
|
||||
"relay_count": 15,
|
||||
"relays": [{
|
||||
"url": "wss://laantungir.net",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": false
|
||||
}, {
|
||||
"url": "wss://nos.lol",
|
||||
"events": 247,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://nostr-pub.wellorder.net",
|
||||
"events": 37,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://nostr.mom",
|
||||
"events": 38,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://nostr.oxtr.dev",
|
||||
"events": 36,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://offchain.pub",
|
||||
"events": 113,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://premium.primal.net",
|
||||
"events": 1,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.damus.io",
|
||||
"events": 194,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.ditto.pub",
|
||||
"events": 277,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 1,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.divine.video",
|
||||
"events": 2,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.momostr.pink",
|
||||
"events": 27,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.mostr.pub",
|
||||
"events": 148,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.nostrplebs.com",
|
||||
"events": 0,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://relay.primal.net",
|
||||
"events": 360,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}, {
|
||||
"url": "wss://theforest.nostr1.com",
|
||||
"events": 5,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 0,
|
||||
"connected": true
|
||||
}],
|
||||
"kinds": [{
|
||||
"kind": 21059,
|
||||
"count": 184,
|
||||
"total_bytes": 623532,
|
||||
"max_bytes": 5314
|
||||
}, {
|
||||
"kind": 22591,
|
||||
"count": 139,
|
||||
"total_bytes": 107560,
|
||||
"max_bytes": 1223
|
||||
}, {
|
||||
"kind": 30382,
|
||||
"count": 119,
|
||||
"total_bytes": 53663,
|
||||
"max_bytes": 458
|
||||
}, {
|
||||
"kind": 30383,
|
||||
"count": 119,
|
||||
"total_bytes": 53605,
|
||||
"max_bytes": 536
|
||||
}, {
|
||||
"kind": 5,
|
||||
"count": 91,
|
||||
"total_bytes": 39950,
|
||||
"max_bytes": 624
|
||||
}, {
|
||||
"kind": 30078,
|
||||
"count": 54,
|
||||
"total_bytes": 179695,
|
||||
"max_bytes": 14343
|
||||
}, {
|
||||
"kind": 20001,
|
||||
"count": 49,
|
||||
"total_bytes": 35635,
|
||||
"max_bytes": 1871
|
||||
}, {
|
||||
"kind": 0,
|
||||
"count": 48,
|
||||
"total_bytes": 39906,
|
||||
"max_bytes": 1468
|
||||
}, {
|
||||
"kind": 22668,
|
||||
"count": 48,
|
||||
"total_bytes": 20592,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 1,
|
||||
"count": 45,
|
||||
"total_bytes": 38547,
|
||||
"max_bytes": 2413
|
||||
}, {
|
||||
"kind": 22734,
|
||||
"count": 26,
|
||||
"total_bytes": 11102,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 4515,
|
||||
"count": 26,
|
||||
"total_bytes": 38218,
|
||||
"max_bytes": 2956
|
||||
}, {
|
||||
"kind": 10002,
|
||||
"count": 25,
|
||||
"total_bytes": 11707,
|
||||
"max_bytes": 565
|
||||
}, {
|
||||
"kind": 22850,
|
||||
"count": 24,
|
||||
"total_bytes": 10320,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 7,
|
||||
"count": 24,
|
||||
"total_bytes": 13528,
|
||||
"max_bytes": 780
|
||||
}, {
|
||||
"kind": 22551,
|
||||
"count": 24,
|
||||
"total_bytes": 10320,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 31991,
|
||||
"count": 20,
|
||||
"total_bytes": 9220,
|
||||
"max_bytes": 461
|
||||
}, {
|
||||
"kind": 38501,
|
||||
"count": 18,
|
||||
"total_bytes": 13341,
|
||||
"max_bytes": 744
|
||||
}, {
|
||||
"kind": 22663,
|
||||
"count": 17,
|
||||
"total_bytes": 7276,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 25555,
|
||||
"count": 15,
|
||||
"total_bytes": 90493,
|
||||
"max_bytes": 16887
|
||||
}, {
|
||||
"kind": 22912,
|
||||
"count": 13,
|
||||
"total_bytes": 5564,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 1059,
|
||||
"count": 13,
|
||||
"total_bytes": 23775,
|
||||
"max_bytes": 1883
|
||||
}, {
|
||||
"kind": 22832,
|
||||
"count": 12,
|
||||
"total_bytes": 5233,
|
||||
"max_bytes": 446
|
||||
}, {
|
||||
"kind": 22690,
|
||||
"count": 11,
|
||||
"total_bytes": 4730,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22545,
|
||||
"count": 11,
|
||||
"total_bytes": 4697,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 25050,
|
||||
"count": 10,
|
||||
"total_bytes": 4394,
|
||||
"max_bytes": 465
|
||||
}, {
|
||||
"kind": 37195,
|
||||
"count": 10,
|
||||
"total_bytes": 7494,
|
||||
"max_bytes": 771
|
||||
}, {
|
||||
"kind": 22601,
|
||||
"count": 10,
|
||||
"total_bytes": 4280,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22795,
|
||||
"count": 10,
|
||||
"total_bytes": 11639,
|
||||
"max_bytes": 1487
|
||||
}, {
|
||||
"kind": 22891,
|
||||
"count": 9,
|
||||
"total_bytes": 13331,
|
||||
"max_bytes": 1490
|
||||
}, {
|
||||
"kind": 22655,
|
||||
"count": 9,
|
||||
"total_bytes": 3852,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22911,
|
||||
"count": 9,
|
||||
"total_bytes": 13328,
|
||||
"max_bytes": 1487
|
||||
}, {
|
||||
"kind": 24133,
|
||||
"count": 9,
|
||||
"total_bytes": 8250,
|
||||
"max_bytes": 1534
|
||||
}, {
|
||||
"kind": 13194,
|
||||
"count": 8,
|
||||
"total_bytes": 4112,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 22647,
|
||||
"count": 8,
|
||||
"total_bytes": 3416,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22695,
|
||||
"count": 7,
|
||||
"total_bytes": 10339,
|
||||
"max_bytes": 1481
|
||||
}, {
|
||||
"kind": 22653,
|
||||
"count": 7,
|
||||
"total_bytes": 10368,
|
||||
"max_bytes": 1487
|
||||
}, {
|
||||
"kind": 22455,
|
||||
"count": 7,
|
||||
"total_bytes": 10339,
|
||||
"max_bytes": 1485
|
||||
}, {
|
||||
"kind": 22543,
|
||||
"count": 7,
|
||||
"total_bytes": 10354,
|
||||
"max_bytes": 1487
|
||||
}, {
|
||||
"kind": 30315,
|
||||
"count": 7,
|
||||
"total_bytes": 2714,
|
||||
"max_bytes": 398
|
||||
}, {
|
||||
"kind": 22676,
|
||||
"count": 6,
|
||||
"total_bytes": 2562,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22575,
|
||||
"count": 6,
|
||||
"total_bytes": 2550,
|
||||
"max_bytes": 425
|
||||
}, {
|
||||
"kind": 22689,
|
||||
"count": 6,
|
||||
"total_bytes": 8851,
|
||||
"max_bytes": 1484
|
||||
}, {
|
||||
"kind": 22913,
|
||||
"count": 6,
|
||||
"total_bytes": 2586,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22774,
|
||||
"count": 6,
|
||||
"total_bytes": 2568,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 24242,
|
||||
"count": 6,
|
||||
"total_bytes": 3474,
|
||||
"max_bytes": 579
|
||||
}, {
|
||||
"kind": 22808,
|
||||
"count": 6,
|
||||
"total_bytes": 2574,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22842,
|
||||
"count": 6,
|
||||
"total_bytes": 8891,
|
||||
"max_bytes": 1488
|
||||
}, {
|
||||
"kind": 22603,
|
||||
"count": 5,
|
||||
"total_bytes": 2130,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 6,
|
||||
"count": 5,
|
||||
"total_bytes": 10814,
|
||||
"max_bytes": 7298
|
||||
}, {
|
||||
"kind": 31990,
|
||||
"count": 5,
|
||||
"total_bytes": 4305,
|
||||
"max_bytes": 1321
|
||||
}, {
|
||||
"kind": 22384,
|
||||
"count": 5,
|
||||
"total_bytes": 2130,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22699,
|
||||
"count": 5,
|
||||
"total_bytes": 2140,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22613,
|
||||
"count": 5,
|
||||
"total_bytes": 3443,
|
||||
"max_bytes": 691
|
||||
}, {
|
||||
"kind": 38502,
|
||||
"count": 5,
|
||||
"total_bytes": 1925,
|
||||
"max_bytes": 385
|
||||
}, {
|
||||
"kind": 23003,
|
||||
"count": 5,
|
||||
"total_bytes": 2140,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22743,
|
||||
"count": 5,
|
||||
"total_bytes": 2140,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 29333,
|
||||
"count": 5,
|
||||
"total_bytes": 2460,
|
||||
"max_bytes": 492
|
||||
}, {
|
||||
"kind": 20004,
|
||||
"count": 4,
|
||||
"total_bytes": 1800,
|
||||
"max_bytes": 549
|
||||
}, {
|
||||
"kind": 4,
|
||||
"count": 4,
|
||||
"total_bytes": 3072,
|
||||
"max_bytes": 826
|
||||
}, {
|
||||
"kind": 20387,
|
||||
"count": 4,
|
||||
"total_bytes": 2056,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 22816,
|
||||
"count": 4,
|
||||
"total_bytes": 1716,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 20000,
|
||||
"count": 4,
|
||||
"total_bytes": 1872,
|
||||
"max_bytes": 628
|
||||
}, {
|
||||
"kind": 22934,
|
||||
"count": 3,
|
||||
"total_bytes": 5535,
|
||||
"max_bytes": 1846
|
||||
}, {
|
||||
"kind": 1985,
|
||||
"count": 2,
|
||||
"total_bytes": 948,
|
||||
"max_bytes": 474
|
||||
}, {
|
||||
"kind": 31234,
|
||||
"count": 2,
|
||||
"total_bytes": 89092,
|
||||
"max_bytes": 44546
|
||||
}, {
|
||||
"kind": 10777,
|
||||
"count": 2,
|
||||
"total_bytes": 976,
|
||||
"max_bytes": 488
|
||||
}, {
|
||||
"kind": 4004,
|
||||
"count": 2,
|
||||
"total_bytes": 2338,
|
||||
"max_bytes": 1169
|
||||
}, {
|
||||
"kind": 9735,
|
||||
"count": 2,
|
||||
"total_bytes": 3926,
|
||||
"max_bytes": 2135
|
||||
}, {
|
||||
"kind": 1000,
|
||||
"count": 2,
|
||||
"total_bytes": 3415,
|
||||
"max_bytes": 1712
|
||||
}, {
|
||||
"kind": 25195,
|
||||
"count": 2,
|
||||
"total_bytes": 1356,
|
||||
"max_bytes": 678
|
||||
}, {
|
||||
"kind": 30311,
|
||||
"count": 2,
|
||||
"total_bytes": 2210,
|
||||
"max_bytes": 1198
|
||||
}, {
|
||||
"kind": 25196,
|
||||
"count": 2,
|
||||
"total_bytes": 3576,
|
||||
"max_bytes": 2214
|
||||
}, {
|
||||
"kind": 1040,
|
||||
"count": 2,
|
||||
"total_bytes": 1920,
|
||||
"max_bytes": 960
|
||||
}, {
|
||||
"kind": 38383,
|
||||
"count": 2,
|
||||
"total_bytes": 1532,
|
||||
"max_bytes": 815
|
||||
}, {
|
||||
"kind": 30515,
|
||||
"count": 2,
|
||||
"total_bytes": 5152,
|
||||
"max_bytes": 2576
|
||||
}, {
|
||||
"kind": 30091,
|
||||
"count": 2,
|
||||
"total_bytes": 1221,
|
||||
"max_bytes": 611
|
||||
}, {
|
||||
"kind": 30088,
|
||||
"count": 2,
|
||||
"total_bytes": 3717,
|
||||
"max_bytes": 1859
|
||||
}, {
|
||||
"kind": 21617,
|
||||
"count": 1,
|
||||
"total_bytes": 494,
|
||||
"max_bytes": 494
|
||||
}, {
|
||||
"kind": 30380,
|
||||
"count": 1,
|
||||
"total_bytes": 454,
|
||||
"max_bytes": 454
|
||||
}, {
|
||||
"kind": 22611,
|
||||
"count": 1,
|
||||
"total_bytes": 426,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 30079,
|
||||
"count": 1,
|
||||
"total_bytes": 875,
|
||||
"max_bytes": 875
|
||||
}, {
|
||||
"kind": 22767,
|
||||
"count": 1,
|
||||
"total_bytes": 429,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 38500,
|
||||
"count": 1,
|
||||
"total_bytes": 711,
|
||||
"max_bytes": 711
|
||||
}, {
|
||||
"kind": 30312,
|
||||
"count": 1,
|
||||
"total_bytes": 461,
|
||||
"max_bytes": 461
|
||||
}, {
|
||||
"kind": 7368,
|
||||
"count": 1,
|
||||
"total_bytes": 1039,
|
||||
"max_bytes": 1039
|
||||
}, {
|
||||
"kind": 22967,
|
||||
"count": 1,
|
||||
"total_bytes": 431,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 39101,
|
||||
"count": 1,
|
||||
"total_bytes": 533,
|
||||
"max_bytes": 533
|
||||
}, {
|
||||
"kind": 445,
|
||||
"count": 1,
|
||||
"total_bytes": 4130,
|
||||
"max_bytes": 4130
|
||||
}, {
|
||||
"kind": 10000,
|
||||
"count": 1,
|
||||
"total_bytes": 1722,
|
||||
"max_bytes": 1722
|
||||
}, {
|
||||
"kind": 30617,
|
||||
"count": 1,
|
||||
"total_bytes": 1089,
|
||||
"max_bytes": 1089
|
||||
}, {
|
||||
"kind": 22526,
|
||||
"count": 1,
|
||||
"total_bytes": 430,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 20787,
|
||||
"count": 1,
|
||||
"total_bytes": 926,
|
||||
"max_bytes": 926
|
||||
}, {
|
||||
"kind": 443,
|
||||
"count": 1,
|
||||
"total_bytes": 800,
|
||||
"max_bytes": 800
|
||||
}, {
|
||||
"kind": 16,
|
||||
"count": 1,
|
||||
"total_bytes": 780,
|
||||
"max_bytes": 780
|
||||
}, {
|
||||
"kind": 10011,
|
||||
"count": 1,
|
||||
"total_bytes": 397,
|
||||
"max_bytes": 397
|
||||
}, {
|
||||
"kind": 22679,
|
||||
"count": 1,
|
||||
"total_bytes": 693,
|
||||
"max_bytes": 693
|
||||
}, {
|
||||
"kind": 23042,
|
||||
"count": 1,
|
||||
"total_bytes": 429,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22514,
|
||||
"count": 1,
|
||||
"total_bytes": 428,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 30023,
|
||||
"count": 1,
|
||||
"total_bytes": 8164,
|
||||
"max_bytes": 8164
|
||||
}, {
|
||||
"kind": 5300,
|
||||
"count": 1,
|
||||
"total_bytes": 630,
|
||||
"max_bytes": 630
|
||||
}, {
|
||||
"kind": 22605,
|
||||
"count": 1,
|
||||
"total_bytes": 692,
|
||||
"max_bytes": 692
|
||||
}, {
|
||||
"kind": 34237,
|
||||
"count": 1,
|
||||
"total_bytes": 418,
|
||||
"max_bytes": 418
|
||||
}, {
|
||||
"kind": 30618,
|
||||
"count": 1,
|
||||
"total_bytes": 733,
|
||||
"max_bytes": 733
|
||||
}, {
|
||||
"kind": 38421,
|
||||
"count": 1,
|
||||
"total_bytes": 1069,
|
||||
"max_bytes": 1069
|
||||
}, {
|
||||
"kind": 10100,
|
||||
"count": 1,
|
||||
"total_bytes": 1036,
|
||||
"max_bytes": 1036
|
||||
}, {
|
||||
"kind": 30080,
|
||||
"count": 1,
|
||||
"total_bytes": 925,
|
||||
"max_bytes": 925
|
||||
}, {
|
||||
"kind": 38385,
|
||||
"count": 1,
|
||||
"total_bytes": 1214,
|
||||
"max_bytes": 1214
|
||||
}, {
|
||||
"kind": 38225,
|
||||
"count": 1,
|
||||
"total_bytes": 1012,
|
||||
"max_bytes": 1012
|
||||
}, {
|
||||
"kind": 11998,
|
||||
"count": 1,
|
||||
"total_bytes": 465,
|
||||
"max_bytes": 465
|
||||
}, {
|
||||
"kind": 22236,
|
||||
"count": 1,
|
||||
"total_bytes": 747,
|
||||
"max_bytes": 747
|
||||
}, {
|
||||
"kind": 22823,
|
||||
"count": 1,
|
||||
"total_bytes": 1852,
|
||||
"max_bytes": 1852
|
||||
}]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,998 @@
|
||||
{
|
||||
"duration_seconds": 503,
|
||||
"total_events": 7884,
|
||||
"total_bytes": 12205231,
|
||||
"unique_pubkeys": 2301,
|
||||
"relay_count": 1,
|
||||
"relays": [{
|
||||
"url": "wss://relay.primal.net",
|
||||
"events": 7884,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 10,
|
||||
"connected": true
|
||||
}],
|
||||
"kinds": [{
|
||||
"kind": 1059,
|
||||
"count": 871,
|
||||
"total_bytes": 1657832,
|
||||
"max_bytes": 55121
|
||||
}, {
|
||||
"kind": 21059,
|
||||
"count": 740,
|
||||
"total_bytes": 2308644,
|
||||
"max_bytes": 22354
|
||||
}, {
|
||||
"kind": 30078,
|
||||
"count": 622,
|
||||
"total_bytes": 2651879,
|
||||
"max_bytes": 55090
|
||||
}, {
|
||||
"kind": 30383,
|
||||
"count": 520,
|
||||
"total_bytes": 278610,
|
||||
"max_bytes": 548
|
||||
}, {
|
||||
"kind": 20001,
|
||||
"count": 386,
|
||||
"total_bytes": 403111,
|
||||
"max_bytes": 2026
|
||||
}, {
|
||||
"kind": 22734,
|
||||
"count": 357,
|
||||
"total_bytes": 152451,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 1,
|
||||
"count": 303,
|
||||
"total_bytes": 303990,
|
||||
"max_bytes": 4648
|
||||
}, {
|
||||
"kind": 30382,
|
||||
"count": 288,
|
||||
"total_bytes": 137207,
|
||||
"max_bytes": 484
|
||||
}, {
|
||||
"kind": 0,
|
||||
"count": 189,
|
||||
"total_bytes": 140594,
|
||||
"max_bytes": 2012
|
||||
}, {
|
||||
"kind": 29333,
|
||||
"count": 165,
|
||||
"total_bytes": 81180,
|
||||
"max_bytes": 492
|
||||
}, {
|
||||
"kind": 10002,
|
||||
"count": 158,
|
||||
"total_bytes": 571188,
|
||||
"max_bytes": 42385
|
||||
}, {
|
||||
"kind": 22236,
|
||||
"count": 158,
|
||||
"total_bytes": 120802,
|
||||
"max_bytes": 801
|
||||
}, {
|
||||
"kind": 5,
|
||||
"count": 154,
|
||||
"total_bytes": 73847,
|
||||
"max_bytes": 664
|
||||
}, {
|
||||
"kind": 4515,
|
||||
"count": 154,
|
||||
"total_bytes": 463562,
|
||||
"max_bytes": 38797
|
||||
}, {
|
||||
"kind": 22743,
|
||||
"count": 134,
|
||||
"total_bytes": 57352,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 7,
|
||||
"count": 113,
|
||||
"total_bytes": 62452,
|
||||
"max_bytes": 727
|
||||
}, {
|
||||
"kind": 24133,
|
||||
"count": 102,
|
||||
"total_bytes": 132440,
|
||||
"max_bytes": 7334
|
||||
}, {
|
||||
"kind": 22684,
|
||||
"count": 99,
|
||||
"total_bytes": 42669,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22850,
|
||||
"count": 94,
|
||||
"total_bytes": 40420,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22838,
|
||||
"count": 88,
|
||||
"total_bytes": 37752,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22774,
|
||||
"count": 84,
|
||||
"total_bytes": 35952,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 23003,
|
||||
"count": 84,
|
||||
"total_bytes": 35952,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22876,
|
||||
"count": 83,
|
||||
"total_bytes": 35358,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22611,
|
||||
"count": 75,
|
||||
"total_bytes": 32175,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 25555,
|
||||
"count": 69,
|
||||
"total_bytes": 281319,
|
||||
"max_bytes": 16987
|
||||
}, {
|
||||
"kind": 4,
|
||||
"count": 66,
|
||||
"total_bytes": 72028,
|
||||
"max_bytes": 17018
|
||||
}, {
|
||||
"kind": 22613,
|
||||
"count": 63,
|
||||
"total_bytes": 43489,
|
||||
"max_bytes": 692
|
||||
}, {
|
||||
"kind": 25050,
|
||||
"count": 61,
|
||||
"total_bytes": 24461,
|
||||
"max_bytes": 401
|
||||
}, {
|
||||
"kind": 11998,
|
||||
"count": 61,
|
||||
"total_bytes": 28269,
|
||||
"max_bytes": 465
|
||||
}, {
|
||||
"kind": 443,
|
||||
"count": 49,
|
||||
"total_bytes": 68056,
|
||||
"max_bytes": 22480
|
||||
}, {
|
||||
"kind": 30301,
|
||||
"count": 47,
|
||||
"total_bytes": 53284,
|
||||
"max_bytes": 1912
|
||||
}, {
|
||||
"kind": 3927,
|
||||
"count": 47,
|
||||
"total_bytes": 25051,
|
||||
"max_bytes": 533
|
||||
}, {
|
||||
"kind": 20387,
|
||||
"count": 44,
|
||||
"total_bytes": 22616,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 22761,
|
||||
"count": 44,
|
||||
"total_bytes": 18832,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 13194,
|
||||
"count": 43,
|
||||
"total_bytes": 22043,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 20004,
|
||||
"count": 42,
|
||||
"total_bytes": 22266,
|
||||
"max_bytes": 549
|
||||
}, {
|
||||
"kind": 5300,
|
||||
"count": 42,
|
||||
"total_bytes": 25437,
|
||||
"max_bytes": 637
|
||||
}, {
|
||||
"kind": 22546,
|
||||
"count": 39,
|
||||
"total_bytes": 16614,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22714,
|
||||
"count": 37,
|
||||
"total_bytes": 15836,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 30166,
|
||||
"count": 35,
|
||||
"total_bytes": 17904,
|
||||
"max_bytes": 589
|
||||
}, {
|
||||
"kind": 9735,
|
||||
"count": 35,
|
||||
"total_bytes": 70344,
|
||||
"max_bytes": 3538
|
||||
}, {
|
||||
"kind": 23334,
|
||||
"count": 35,
|
||||
"total_bytes": 15084,
|
||||
"max_bytes": 432
|
||||
}, {
|
||||
"kind": 1985,
|
||||
"count": 34,
|
||||
"total_bytes": 16232,
|
||||
"max_bytes": 483
|
||||
}, {
|
||||
"kind": 22816,
|
||||
"count": 33,
|
||||
"total_bytes": 14157,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 21050,
|
||||
"count": 33,
|
||||
"total_bytes": 30862,
|
||||
"max_bytes": 1874
|
||||
}, {
|
||||
"kind": 30315,
|
||||
"count": 32,
|
||||
"total_bytes": 21166,
|
||||
"max_bytes": 925
|
||||
}, {
|
||||
"kind": 445,
|
||||
"count": 32,
|
||||
"total_bytes": 120956,
|
||||
"max_bytes": 9346
|
||||
}, {
|
||||
"kind": 22698,
|
||||
"count": 32,
|
||||
"total_bytes": 13664,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 4004,
|
||||
"count": 32,
|
||||
"total_bytes": 37408,
|
||||
"max_bytes": 1169
|
||||
}, {
|
||||
"kind": 38501,
|
||||
"count": 31,
|
||||
"total_bytes": 23034,
|
||||
"max_bytes": 744
|
||||
}, {
|
||||
"kind": 31990,
|
||||
"count": 25,
|
||||
"total_bytes": 9675,
|
||||
"max_bytes": 387
|
||||
}, {
|
||||
"kind": 10100,
|
||||
"count": 24,
|
||||
"total_bytes": 27687,
|
||||
"max_bytes": 1589
|
||||
}, {
|
||||
"kind": 20333,
|
||||
"count": 24,
|
||||
"total_bytes": 19120,
|
||||
"max_bytes": 798
|
||||
}, {
|
||||
"kind": 3,
|
||||
"count": 23,
|
||||
"total_bytes": 328284,
|
||||
"max_bytes": 56750
|
||||
}, {
|
||||
"kind": 24913,
|
||||
"count": 22,
|
||||
"total_bytes": 9700,
|
||||
"max_bytes": 493
|
||||
}, {
|
||||
"kind": 30311,
|
||||
"count": 21,
|
||||
"total_bytes": 22061,
|
||||
"max_bytes": 1197
|
||||
}, {
|
||||
"kind": 6,
|
||||
"count": 21,
|
||||
"total_bytes": 49793,
|
||||
"max_bytes": 12925
|
||||
}, {
|
||||
"kind": 10050,
|
||||
"count": 19,
|
||||
"total_bytes": 8172,
|
||||
"max_bytes": 450
|
||||
}, {
|
||||
"kind": 22712,
|
||||
"count": 18,
|
||||
"total_bytes": 7704,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22808,
|
||||
"count": 17,
|
||||
"total_bytes": 7293,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 10000,
|
||||
"count": 16,
|
||||
"total_bytes": 26659,
|
||||
"max_bytes": 12630
|
||||
}, {
|
||||
"kind": 4244,
|
||||
"count": 15,
|
||||
"total_bytes": 8460,
|
||||
"max_bytes": 564
|
||||
}, {
|
||||
"kind": 23025,
|
||||
"count": 15,
|
||||
"total_bytes": 6465,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 31234,
|
||||
"count": 14,
|
||||
"total_bytes": 24051,
|
||||
"max_bytes": 2268
|
||||
}, {
|
||||
"kind": 38503,
|
||||
"count": 13,
|
||||
"total_bytes": 7174,
|
||||
"max_bytes": 552
|
||||
}, {
|
||||
"kind": 22630,
|
||||
"count": 12,
|
||||
"total_bytes": 11762,
|
||||
"max_bytes": 1654
|
||||
}, {
|
||||
"kind": 37195,
|
||||
"count": 12,
|
||||
"total_bytes": 8752,
|
||||
"max_bytes": 934
|
||||
}, {
|
||||
"kind": 6300,
|
||||
"count": 12,
|
||||
"total_bytes": 77247,
|
||||
"max_bytes": 17248
|
||||
}, {
|
||||
"kind": 10777,
|
||||
"count": 12,
|
||||
"total_bytes": 5861,
|
||||
"max_bytes": 489
|
||||
}, {
|
||||
"kind": 30091,
|
||||
"count": 11,
|
||||
"total_bytes": 6763,
|
||||
"max_bytes": 629
|
||||
}, {
|
||||
"kind": 20000,
|
||||
"count": 11,
|
||||
"total_bytes": 3806,
|
||||
"max_bytes": 346
|
||||
}, {
|
||||
"kind": 30515,
|
||||
"count": 11,
|
||||
"total_bytes": 58344,
|
||||
"max_bytes": 5304
|
||||
}, {
|
||||
"kind": 30088,
|
||||
"count": 11,
|
||||
"total_bytes": 20483,
|
||||
"max_bytes": 1871
|
||||
}, {
|
||||
"kind": 22361,
|
||||
"count": 10,
|
||||
"total_bytes": 4439,
|
||||
"max_bytes": 445
|
||||
}, {
|
||||
"kind": 30280,
|
||||
"count": 9,
|
||||
"total_bytes": 4617,
|
||||
"max_bytes": 513
|
||||
}, {
|
||||
"kind": 22902,
|
||||
"count": 9,
|
||||
"total_bytes": 3861,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22506,
|
||||
"count": 8,
|
||||
"total_bytes": 3416,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 7368,
|
||||
"count": 8,
|
||||
"total_bytes": 8304,
|
||||
"max_bytes": 1040
|
||||
}, {
|
||||
"kind": 22645,
|
||||
"count": 8,
|
||||
"total_bytes": 3432,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 38500,
|
||||
"count": 8,
|
||||
"total_bytes": 5696,
|
||||
"max_bytes": 713
|
||||
}, {
|
||||
"kind": 33334,
|
||||
"count": 8,
|
||||
"total_bytes": 6648,
|
||||
"max_bytes": 831
|
||||
}, {
|
||||
"kind": 30380,
|
||||
"count": 8,
|
||||
"total_bytes": 3632,
|
||||
"max_bytes": 454
|
||||
}, {
|
||||
"kind": 22688,
|
||||
"count": 7,
|
||||
"total_bytes": 2989,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22656,
|
||||
"count": 7,
|
||||
"total_bytes": 3017,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22316,
|
||||
"count": 7,
|
||||
"total_bytes": 3106,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30089,
|
||||
"count": 6,
|
||||
"total_bytes": 123676,
|
||||
"max_bytes": 44372
|
||||
}, {
|
||||
"kind": 22456,
|
||||
"count": 6,
|
||||
"total_bytes": 3140,
|
||||
"max_bytes": 790
|
||||
}, {
|
||||
"kind": 22739,
|
||||
"count": 6,
|
||||
"total_bytes": 2580,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22882,
|
||||
"count": 6,
|
||||
"total_bytes": 5292,
|
||||
"max_bytes": 1449
|
||||
}, {
|
||||
"kind": 22862,
|
||||
"count": 6,
|
||||
"total_bytes": 2574,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 1111,
|
||||
"count": 6,
|
||||
"total_bytes": 7227,
|
||||
"max_bytes": 1698
|
||||
}, {
|
||||
"kind": 4245,
|
||||
"count": 5,
|
||||
"total_bytes": 2220,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30512,
|
||||
"count": 5,
|
||||
"total_bytes": 7504,
|
||||
"max_bytes": 1506
|
||||
}, {
|
||||
"kind": 22641,
|
||||
"count": 5,
|
||||
"total_bytes": 2145,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22586,
|
||||
"count": 5,
|
||||
"total_bytes": 2135,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 4243,
|
||||
"count": 5,
|
||||
"total_bytes": 2820,
|
||||
"max_bytes": 564
|
||||
}, {
|
||||
"kind": 22835,
|
||||
"count": 5,
|
||||
"total_bytes": 2145,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22620,
|
||||
"count": 5,
|
||||
"total_bytes": 2145,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22298,
|
||||
"count": 5,
|
||||
"total_bytes": 2218,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22852,
|
||||
"count": 5,
|
||||
"total_bytes": 2140,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22726,
|
||||
"count": 5,
|
||||
"total_bytes": 2150,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22362,
|
||||
"count": 5,
|
||||
"total_bytes": 2218,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22772,
|
||||
"count": 5,
|
||||
"total_bytes": 4051,
|
||||
"max_bytes": 1132
|
||||
}, {
|
||||
"kind": 22805,
|
||||
"count": 4,
|
||||
"total_bytes": 1712,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 9734,
|
||||
"count": 4,
|
||||
"total_bytes": 3756,
|
||||
"max_bytes": 1033
|
||||
}, {
|
||||
"kind": 22200,
|
||||
"count": 4,
|
||||
"total_bytes": 1774,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 31510,
|
||||
"count": 4,
|
||||
"total_bytes": 3922,
|
||||
"max_bytes": 982
|
||||
}, {
|
||||
"kind": 22570,
|
||||
"count": 4,
|
||||
"total_bytes": 1716,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 25195,
|
||||
"count": 4,
|
||||
"total_bytes": 2712,
|
||||
"max_bytes": 678
|
||||
}, {
|
||||
"kind": 22752,
|
||||
"count": 3,
|
||||
"total_bytes": 4047,
|
||||
"max_bytes": 3191
|
||||
}, {
|
||||
"kind": 31339,
|
||||
"count": 3,
|
||||
"total_bytes": 4410,
|
||||
"max_bytes": 1470
|
||||
}, {
|
||||
"kind": 22949,
|
||||
"count": 3,
|
||||
"total_bytes": 1287,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22358,
|
||||
"count": 3,
|
||||
"total_bytes": 1331,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22474,
|
||||
"count": 3,
|
||||
"total_bytes": 1330,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22185,
|
||||
"count": 3,
|
||||
"total_bytes": 1330,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22936,
|
||||
"count": 3,
|
||||
"total_bytes": 1290,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 25196,
|
||||
"count": 3,
|
||||
"total_bytes": 4938,
|
||||
"max_bytes": 2214
|
||||
}, {
|
||||
"kind": 22439,
|
||||
"count": 3,
|
||||
"total_bytes": 1330,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22824,
|
||||
"count": 3,
|
||||
"total_bytes": 1281,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22270,
|
||||
"count": 3,
|
||||
"total_bytes": 1330,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22263,
|
||||
"count": 3,
|
||||
"total_bytes": 1330,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22755,
|
||||
"count": 3,
|
||||
"total_bytes": 1284,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 10051,
|
||||
"count": 3,
|
||||
"total_bytes": 1317,
|
||||
"max_bytes": 439
|
||||
}, {
|
||||
"kind": 34775,
|
||||
"count": 3,
|
||||
"total_bytes": 7599,
|
||||
"max_bytes": 2561
|
||||
}, {
|
||||
"kind": 30300,
|
||||
"count": 3,
|
||||
"total_bytes": 5502,
|
||||
"max_bytes": 1834
|
||||
}, {
|
||||
"kind": 22234,
|
||||
"count": 3,
|
||||
"total_bytes": 1330,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 7403,
|
||||
"count": 2,
|
||||
"total_bytes": 978,
|
||||
"max_bytes": 489
|
||||
}, {
|
||||
"kind": 22626,
|
||||
"count": 2,
|
||||
"total_bytes": 1916,
|
||||
"max_bytes": 1486
|
||||
}, {
|
||||
"kind": 30079,
|
||||
"count": 2,
|
||||
"total_bytes": 1750,
|
||||
"max_bytes": 875
|
||||
}, {
|
||||
"kind": 15750,
|
||||
"count": 2,
|
||||
"total_bytes": 1242,
|
||||
"max_bytes": 626
|
||||
}, {
|
||||
"kind": 23337,
|
||||
"count": 2,
|
||||
"total_bytes": 1027,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 30815,
|
||||
"count": 2,
|
||||
"total_bytes": 75068,
|
||||
"max_bytes": 37534
|
||||
}, {
|
||||
"kind": 30213,
|
||||
"count": 2,
|
||||
"total_bytes": 1264,
|
||||
"max_bytes": 632
|
||||
}, {
|
||||
"kind": 22716,
|
||||
"count": 2,
|
||||
"total_bytes": 854,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22492,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30000,
|
||||
"count": 2,
|
||||
"total_bytes": 1646,
|
||||
"max_bytes": 823
|
||||
}, {
|
||||
"kind": 22463,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22304,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 10003,
|
||||
"count": 2,
|
||||
"total_bytes": 20016,
|
||||
"max_bytes": 15003
|
||||
}, {
|
||||
"kind": 30443,
|
||||
"count": 2,
|
||||
"total_bytes": 2572,
|
||||
"max_bytes": 1312
|
||||
}, {
|
||||
"kind": 22233,
|
||||
"count": 2,
|
||||
"total_bytes": 886,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22275,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30087,
|
||||
"count": 2,
|
||||
"total_bytes": 11238,
|
||||
"max_bytes": 7325
|
||||
}, {
|
||||
"kind": 20078,
|
||||
"count": 2,
|
||||
"total_bytes": 1458,
|
||||
"max_bytes": 729
|
||||
}, {
|
||||
"kind": 22057,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22251,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22181,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22678,
|
||||
"count": 2,
|
||||
"total_bytes": 1388,
|
||||
"max_bytes": 694
|
||||
}, {
|
||||
"kind": 22747,
|
||||
"count": 2,
|
||||
"total_bytes": 858,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22410,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22334,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22249,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22258,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30090,
|
||||
"count": 2,
|
||||
"total_bytes": 2588,
|
||||
"max_bytes": 1515
|
||||
}, {
|
||||
"kind": 10312,
|
||||
"count": 1,
|
||||
"total_bytes": 472,
|
||||
"max_bytes": 472
|
||||
}, {
|
||||
"kind": 22853,
|
||||
"count": 1,
|
||||
"total_bytes": 1673,
|
||||
"max_bytes": 1673
|
||||
}, {
|
||||
"kind": 22303,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22306,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 20200,
|
||||
"count": 1,
|
||||
"total_bytes": 491,
|
||||
"max_bytes": 491
|
||||
}, {
|
||||
"kind": 22132,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 20201,
|
||||
"count": 1,
|
||||
"total_bytes": 491,
|
||||
"max_bytes": 491
|
||||
}, {
|
||||
"kind": 22245,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22352,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22240,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 34236,
|
||||
"count": 1,
|
||||
"total_bytes": 931,
|
||||
"max_bytes": 931
|
||||
}, {
|
||||
"kind": 17,
|
||||
"count": 1,
|
||||
"total_bytes": 610,
|
||||
"max_bytes": 610
|
||||
}, {
|
||||
"kind": 22286,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 13196,
|
||||
"count": 1,
|
||||
"total_bytes": 656,
|
||||
"max_bytes": 656
|
||||
}, {
|
||||
"kind": 20242,
|
||||
"count": 1,
|
||||
"total_bytes": 346,
|
||||
"max_bytes": 346
|
||||
}, {
|
||||
"kind": 7376,
|
||||
"count": 1,
|
||||
"total_bytes": 670,
|
||||
"max_bytes": 670
|
||||
}, {
|
||||
"kind": 38385,
|
||||
"count": 1,
|
||||
"total_bytes": 1350,
|
||||
"max_bytes": 1350
|
||||
}, {
|
||||
"kind": 22355,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 23333,
|
||||
"count": 1,
|
||||
"total_bytes": 571,
|
||||
"max_bytes": 571
|
||||
}, {
|
||||
"kind": 22737,
|
||||
"count": 1,
|
||||
"total_bytes": 556,
|
||||
"max_bytes": 556
|
||||
}, {
|
||||
"kind": 22291,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 30421,
|
||||
"count": 1,
|
||||
"total_bytes": 995,
|
||||
"max_bytes": 995
|
||||
}, {
|
||||
"kind": 22860,
|
||||
"count": 1,
|
||||
"total_bytes": 553,
|
||||
"max_bytes": 553
|
||||
}, {
|
||||
"kind": 2333,
|
||||
"count": 1,
|
||||
"total_bytes": 659,
|
||||
"max_bytes": 659
|
||||
}, {
|
||||
"kind": 22219,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22382,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 23032,
|
||||
"count": 1,
|
||||
"total_bytes": 430,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 7375,
|
||||
"count": 1,
|
||||
"total_bytes": 1822,
|
||||
"max_bytes": 1822
|
||||
}, {
|
||||
"kind": 22579,
|
||||
"count": 1,
|
||||
"total_bytes": 1670,
|
||||
"max_bytes": 1670
|
||||
}, {
|
||||
"kind": 10007,
|
||||
"count": 1,
|
||||
"total_bytes": 715,
|
||||
"max_bytes": 715
|
||||
}, {
|
||||
"kind": 10086,
|
||||
"count": 1,
|
||||
"total_bytes": 715,
|
||||
"max_bytes": 715
|
||||
}, {
|
||||
"kind": 22729,
|
||||
"count": 1,
|
||||
"total_bytes": 3030,
|
||||
"max_bytes": 3030
|
||||
}, {
|
||||
"kind": 22540,
|
||||
"count": 1,
|
||||
"total_bytes": 426,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22671,
|
||||
"count": 1,
|
||||
"total_bytes": 3194,
|
||||
"max_bytes": 3194
|
||||
}, {
|
||||
"kind": 30618,
|
||||
"count": 1,
|
||||
"total_bytes": 460,
|
||||
"max_bytes": 460
|
||||
}, {
|
||||
"kind": 23118,
|
||||
"count": 1,
|
||||
"total_bytes": 430,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 38421,
|
||||
"count": 1,
|
||||
"total_bytes": 1069,
|
||||
"max_bytes": 1069
|
||||
}, {
|
||||
"kind": 10377,
|
||||
"count": 1,
|
||||
"total_bytes": 664,
|
||||
"max_bytes": 664
|
||||
}, {
|
||||
"kind": 11111,
|
||||
"count": 1,
|
||||
"total_bytes": 382,
|
||||
"max_bytes": 382
|
||||
}, {
|
||||
"kind": 34550,
|
||||
"count": 1,
|
||||
"total_bytes": 867,
|
||||
"max_bytes": 867
|
||||
}, {
|
||||
"kind": 22307,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 1078,
|
||||
"count": 1,
|
||||
"total_bytes": 13969,
|
||||
"max_bytes": 13969
|
||||
}]
|
||||
}
|
||||
@@ -0,0 +1,938 @@
|
||||
{
|
||||
"duration_seconds": 376,
|
||||
"total_events": 5992,
|
||||
"total_bytes": 8743262,
|
||||
"unique_pubkeys": 1142,
|
||||
"relay_count": 1,
|
||||
"relays": [{
|
||||
"url": "wss://relay.primal.net",
|
||||
"events": 5992,
|
||||
"eose": 0,
|
||||
"closed": 0,
|
||||
"notice": 0,
|
||||
"errors": 0,
|
||||
"disconnects": 3,
|
||||
"connected": true
|
||||
}],
|
||||
"kinds": [{
|
||||
"kind": 30078,
|
||||
"count": 495,
|
||||
"total_bytes": 2024957,
|
||||
"max_bytes": 54029
|
||||
}, {
|
||||
"kind": 21059,
|
||||
"count": 386,
|
||||
"total_bytes": 1099128,
|
||||
"max_bytes": 5314
|
||||
}, {
|
||||
"kind": 4515,
|
||||
"count": 374,
|
||||
"total_bytes": 781718,
|
||||
"max_bytes": 14221
|
||||
}, {
|
||||
"kind": 22591,
|
||||
"count": 371,
|
||||
"total_bytes": 286839,
|
||||
"max_bytes": 1228
|
||||
}, {
|
||||
"kind": 20001,
|
||||
"count": 271,
|
||||
"total_bytes": 315643,
|
||||
"max_bytes": 2029
|
||||
}, {
|
||||
"kind": 22734,
|
||||
"count": 264,
|
||||
"total_bytes": 112728,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 30382,
|
||||
"count": 255,
|
||||
"total_bytes": 121375,
|
||||
"max_bytes": 483
|
||||
}, {
|
||||
"kind": 30383,
|
||||
"count": 237,
|
||||
"total_bytes": 126938,
|
||||
"max_bytes": 547
|
||||
}, {
|
||||
"kind": 1,
|
||||
"count": 212,
|
||||
"total_bytes": 211399,
|
||||
"max_bytes": 2011
|
||||
}, {
|
||||
"kind": 5,
|
||||
"count": 183,
|
||||
"total_bytes": 91915,
|
||||
"max_bytes": 664
|
||||
}, {
|
||||
"kind": 22236,
|
||||
"count": 146,
|
||||
"total_bytes": 104252,
|
||||
"max_bytes": 810
|
||||
}, {
|
||||
"kind": 0,
|
||||
"count": 145,
|
||||
"total_bytes": 103418,
|
||||
"max_bytes": 2012
|
||||
}, {
|
||||
"kind": 7,
|
||||
"count": 138,
|
||||
"total_bytes": 79421,
|
||||
"max_bytes": 1036
|
||||
}, {
|
||||
"kind": 22743,
|
||||
"count": 134,
|
||||
"total_bytes": 57352,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 1059,
|
||||
"count": 132,
|
||||
"total_bytes": 430222,
|
||||
"max_bytes": 5285
|
||||
}, {
|
||||
"kind": 29333,
|
||||
"count": 130,
|
||||
"total_bytes": 63960,
|
||||
"max_bytes": 492
|
||||
}, {
|
||||
"kind": 22611,
|
||||
"count": 117,
|
||||
"total_bytes": 50147,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 10002,
|
||||
"count": 114,
|
||||
"total_bytes": 510211,
|
||||
"max_bytes": 42449
|
||||
}, {
|
||||
"kind": 23456,
|
||||
"count": 72,
|
||||
"total_bytes": 121616,
|
||||
"max_bytes": 1874
|
||||
}, {
|
||||
"kind": 22850,
|
||||
"count": 71,
|
||||
"total_bytes": 30530,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 22684,
|
||||
"count": 70,
|
||||
"total_bytes": 30170,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22838,
|
||||
"count": 63,
|
||||
"total_bytes": 27027,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 23003,
|
||||
"count": 63,
|
||||
"total_bytes": 26964,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22774,
|
||||
"count": 62,
|
||||
"total_bytes": 26536,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22876,
|
||||
"count": 61,
|
||||
"total_bytes": 28880,
|
||||
"max_bytes": 3193
|
||||
}, {
|
||||
"kind": 22583,
|
||||
"count": 61,
|
||||
"total_bytes": 26047,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22613,
|
||||
"count": 60,
|
||||
"total_bytes": 43172,
|
||||
"max_bytes": 1133
|
||||
}, {
|
||||
"kind": 4,
|
||||
"count": 58,
|
||||
"total_bytes": 61778,
|
||||
"max_bytes": 17018
|
||||
}, {
|
||||
"kind": 25555,
|
||||
"count": 56,
|
||||
"total_bytes": 249772,
|
||||
"max_bytes": 16895
|
||||
}, {
|
||||
"kind": 25050,
|
||||
"count": 51,
|
||||
"total_bytes": 20451,
|
||||
"max_bytes": 401
|
||||
}, {
|
||||
"kind": 11998,
|
||||
"count": 48,
|
||||
"total_bytes": 22272,
|
||||
"max_bytes": 465
|
||||
}, {
|
||||
"kind": 22728,
|
||||
"count": 48,
|
||||
"total_bytes": 20592,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 31234,
|
||||
"count": 33,
|
||||
"total_bytes": 77859,
|
||||
"max_bytes": 2612
|
||||
}, {
|
||||
"kind": 13194,
|
||||
"count": 32,
|
||||
"total_bytes": 16448,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 20387,
|
||||
"count": 32,
|
||||
"total_bytes": 16448,
|
||||
"max_bytes": 514
|
||||
}, {
|
||||
"kind": 24133,
|
||||
"count": 32,
|
||||
"total_bytes": 23680,
|
||||
"max_bytes": 2214
|
||||
}, {
|
||||
"kind": 3,
|
||||
"count": 31,
|
||||
"total_bytes": 167289,
|
||||
"max_bytes": 61894
|
||||
}, {
|
||||
"kind": 4004,
|
||||
"count": 26,
|
||||
"total_bytes": 30394,
|
||||
"max_bytes": 1169
|
||||
}, {
|
||||
"kind": 22816,
|
||||
"count": 26,
|
||||
"total_bytes": 11154,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 20004,
|
||||
"count": 26,
|
||||
"total_bytes": 13878,
|
||||
"max_bytes": 549
|
||||
}, {
|
||||
"kind": 30315,
|
||||
"count": 26,
|
||||
"total_bytes": 17657,
|
||||
"max_bytes": 872
|
||||
}, {
|
||||
"kind": 443,
|
||||
"count": 25,
|
||||
"total_bytes": 43504,
|
||||
"max_bytes": 22480
|
||||
}, {
|
||||
"kind": 38501,
|
||||
"count": 24,
|
||||
"total_bytes": 17819,
|
||||
"max_bytes": 744
|
||||
}, {
|
||||
"kind": 1985,
|
||||
"count": 24,
|
||||
"total_bytes": 11435,
|
||||
"max_bytes": 483
|
||||
}, {
|
||||
"kind": 22882,
|
||||
"count": 23,
|
||||
"total_bytes": 20949,
|
||||
"max_bytes": 1455
|
||||
}, {
|
||||
"kind": 5300,
|
||||
"count": 22,
|
||||
"total_bytes": 13434,
|
||||
"max_bytes": 701
|
||||
}, {
|
||||
"kind": 31990,
|
||||
"count": 22,
|
||||
"total_bytes": 21777,
|
||||
"max_bytes": 6861
|
||||
}, {
|
||||
"kind": 22790,
|
||||
"count": 21,
|
||||
"total_bytes": 8988,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 21050,
|
||||
"count": 19,
|
||||
"total_bytes": 17510,
|
||||
"max_bytes": 1874
|
||||
}, {
|
||||
"kind": 10100,
|
||||
"count": 19,
|
||||
"total_bytes": 22108,
|
||||
"max_bytes": 1589
|
||||
}, {
|
||||
"kind": 20333,
|
||||
"count": 18,
|
||||
"total_bytes": 14340,
|
||||
"max_bytes": 798
|
||||
}, {
|
||||
"kind": 30088,
|
||||
"count": 16,
|
||||
"total_bytes": 29798,
|
||||
"max_bytes": 1871
|
||||
}, {
|
||||
"kind": 6,
|
||||
"count": 16,
|
||||
"total_bytes": 28131,
|
||||
"max_bytes": 3369
|
||||
}, {
|
||||
"kind": 30091,
|
||||
"count": 16,
|
||||
"total_bytes": 9842,
|
||||
"max_bytes": 629
|
||||
}, {
|
||||
"kind": 6300,
|
||||
"count": 15,
|
||||
"total_bytes": 45643,
|
||||
"max_bytes": 8157
|
||||
}, {
|
||||
"kind": 22658,
|
||||
"count": 15,
|
||||
"total_bytes": 11909,
|
||||
"max_bytes": 1161
|
||||
}, {
|
||||
"kind": 30311,
|
||||
"count": 15,
|
||||
"total_bytes": 16556,
|
||||
"max_bytes": 1197
|
||||
}, {
|
||||
"kind": 445,
|
||||
"count": 15,
|
||||
"total_bytes": 45070,
|
||||
"max_bytes": 4130
|
||||
}, {
|
||||
"kind": 10777,
|
||||
"count": 14,
|
||||
"total_bytes": 6840,
|
||||
"max_bytes": 489
|
||||
}, {
|
||||
"kind": 9735,
|
||||
"count": 14,
|
||||
"total_bytes": 27231,
|
||||
"max_bytes": 2777
|
||||
}, {
|
||||
"kind": 4244,
|
||||
"count": 12,
|
||||
"total_bytes": 6768,
|
||||
"max_bytes": 564
|
||||
}, {
|
||||
"kind": 22456,
|
||||
"count": 12,
|
||||
"total_bytes": 6808,
|
||||
"max_bytes": 790
|
||||
}, {
|
||||
"kind": 38503,
|
||||
"count": 11,
|
||||
"total_bytes": 6070,
|
||||
"max_bytes": 552
|
||||
}, {
|
||||
"kind": 10050,
|
||||
"count": 11,
|
||||
"total_bytes": 4882,
|
||||
"max_bytes": 592
|
||||
}, {
|
||||
"kind": 30515,
|
||||
"count": 10,
|
||||
"total_bytes": 53040,
|
||||
"max_bytes": 5304
|
||||
}, {
|
||||
"kind": 30512,
|
||||
"count": 10,
|
||||
"total_bytes": 15210,
|
||||
"max_bytes": 1596
|
||||
}, {
|
||||
"kind": 30089,
|
||||
"count": 10,
|
||||
"total_bytes": 164434,
|
||||
"max_bytes": 44372
|
||||
}, {
|
||||
"kind": 10000,
|
||||
"count": 10,
|
||||
"total_bytes": 16448,
|
||||
"max_bytes": 4287
|
||||
}, {
|
||||
"kind": 22809,
|
||||
"count": 9,
|
||||
"total_bytes": 3852,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22486,
|
||||
"count": 9,
|
||||
"total_bytes": 3834,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22376,
|
||||
"count": 8,
|
||||
"total_bytes": 3550,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 7368,
|
||||
"count": 8,
|
||||
"total_bytes": 8294,
|
||||
"max_bytes": 1040
|
||||
}, {
|
||||
"kind": 38500,
|
||||
"count": 8,
|
||||
"total_bytes": 5696,
|
||||
"max_bytes": 713
|
||||
}, {
|
||||
"kind": 30380,
|
||||
"count": 7,
|
||||
"total_bytes": 3178,
|
||||
"max_bytes": 454
|
||||
}, {
|
||||
"kind": 20000,
|
||||
"count": 7,
|
||||
"total_bytes": 2422,
|
||||
"max_bytes": 346
|
||||
}, {
|
||||
"kind": 22104,
|
||||
"count": 7,
|
||||
"total_bytes": 3105,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 23025,
|
||||
"count": 7,
|
||||
"total_bytes": 3017,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22896,
|
||||
"count": 7,
|
||||
"total_bytes": 3003,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 33334,
|
||||
"count": 7,
|
||||
"total_bytes": 5817,
|
||||
"max_bytes": 831
|
||||
}, {
|
||||
"kind": 22835,
|
||||
"count": 6,
|
||||
"total_bytes": 2574,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 30443,
|
||||
"count": 6,
|
||||
"total_bytes": 7297,
|
||||
"max_bytes": 1260
|
||||
}, {
|
||||
"kind": 22633,
|
||||
"count": 6,
|
||||
"total_bytes": 6097,
|
||||
"max_bytes": 1668
|
||||
}, {
|
||||
"kind": 22392,
|
||||
"count": 6,
|
||||
"total_bytes": 2662,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 1984,
|
||||
"count": 6,
|
||||
"total_bytes": 3180,
|
||||
"max_bytes": 530
|
||||
}, {
|
||||
"kind": 30064,
|
||||
"count": 6,
|
||||
"total_bytes": 4438,
|
||||
"max_bytes": 991
|
||||
}, {
|
||||
"kind": 22715,
|
||||
"count": 6,
|
||||
"total_bytes": 2562,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 30280,
|
||||
"count": 6,
|
||||
"total_bytes": 3078,
|
||||
"max_bytes": 513
|
||||
}, {
|
||||
"kind": 22559,
|
||||
"count": 6,
|
||||
"total_bytes": 2574,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22813,
|
||||
"count": 6,
|
||||
"total_bytes": 2562,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22635,
|
||||
"count": 6,
|
||||
"total_bytes": 2556,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22746,
|
||||
"count": 5,
|
||||
"total_bytes": 2155,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22364,
|
||||
"count": 5,
|
||||
"total_bytes": 2135,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 37195,
|
||||
"count": 5,
|
||||
"total_bytes": 3664,
|
||||
"max_bytes": 786
|
||||
}, {
|
||||
"kind": 22571,
|
||||
"count": 5,
|
||||
"total_bytes": 4055,
|
||||
"max_bytes": 1127
|
||||
}, {
|
||||
"kind": 23004,
|
||||
"count": 5,
|
||||
"total_bytes": 2145,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22834,
|
||||
"count": 5,
|
||||
"total_bytes": 4050,
|
||||
"max_bytes": 1126
|
||||
}, {
|
||||
"kind": 22636,
|
||||
"count": 5,
|
||||
"total_bytes": 3280,
|
||||
"max_bytes": 1164
|
||||
}, {
|
||||
"kind": 22786,
|
||||
"count": 4,
|
||||
"total_bytes": 1720,
|
||||
"max_bytes": 430
|
||||
}, {
|
||||
"kind": 25195,
|
||||
"count": 4,
|
||||
"total_bytes": 2712,
|
||||
"max_bytes": 678
|
||||
}, {
|
||||
"kind": 4243,
|
||||
"count": 4,
|
||||
"total_bytes": 2256,
|
||||
"max_bytes": 564
|
||||
}, {
|
||||
"kind": 22168,
|
||||
"count": 4,
|
||||
"total_bytes": 1774,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22760,
|
||||
"count": 4,
|
||||
"total_bytes": 2239,
|
||||
"max_bytes": 695
|
||||
}, {
|
||||
"kind": 22733,
|
||||
"count": 4,
|
||||
"total_bytes": 1696,
|
||||
"max_bytes": 424
|
||||
}, {
|
||||
"kind": 22878,
|
||||
"count": 3,
|
||||
"total_bytes": 4059,
|
||||
"max_bytes": 3203
|
||||
}, {
|
||||
"kind": 22902,
|
||||
"count": 3,
|
||||
"total_bytes": 5023,
|
||||
"max_bytes": 1675
|
||||
}, {
|
||||
"kind": 22428,
|
||||
"count": 3,
|
||||
"total_bytes": 1331,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 25196,
|
||||
"count": 3,
|
||||
"total_bytes": 4938,
|
||||
"max_bytes": 2214
|
||||
}, {
|
||||
"kind": 22325,
|
||||
"count": 3,
|
||||
"total_bytes": 1331,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 4245,
|
||||
"count": 3,
|
||||
"total_bytes": 1332,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22258,
|
||||
"count": 3,
|
||||
"total_bytes": 1331,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22625,
|
||||
"count": 3,
|
||||
"total_bytes": 1284,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22631,
|
||||
"count": 3,
|
||||
"total_bytes": 1281,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22551,
|
||||
"count": 3,
|
||||
"total_bytes": 1816,
|
||||
"max_bytes": 695
|
||||
}, {
|
||||
"kind": 22763,
|
||||
"count": 3,
|
||||
"total_bytes": 2988,
|
||||
"max_bytes": 1331
|
||||
}, {
|
||||
"kind": 3927,
|
||||
"count": 2,
|
||||
"total_bytes": 1066,
|
||||
"max_bytes": 533
|
||||
}, {
|
||||
"kind": 22186,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30213,
|
||||
"count": 2,
|
||||
"total_bytes": 1264,
|
||||
"max_bytes": 632
|
||||
}, {
|
||||
"kind": 22367,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22783,
|
||||
"count": 2,
|
||||
"total_bytes": 1391,
|
||||
"max_bytes": 697
|
||||
}, {
|
||||
"kind": 22616,
|
||||
"count": 2,
|
||||
"total_bytes": 858,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22268,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22279,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22474,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22407,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22729,
|
||||
"count": 2,
|
||||
"total_bytes": 854,
|
||||
"max_bytes": 427
|
||||
}, {
|
||||
"kind": 22234,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 10003,
|
||||
"count": 2,
|
||||
"total_bytes": 18782,
|
||||
"max_bytes": 15076
|
||||
}, {
|
||||
"kind": 30815,
|
||||
"count": 2,
|
||||
"total_bytes": 75068,
|
||||
"max_bytes": 37534
|
||||
}, {
|
||||
"kind": 1111,
|
||||
"count": 2,
|
||||
"total_bytes": 1775,
|
||||
"max_bytes": 922
|
||||
}, {
|
||||
"kind": 30087,
|
||||
"count": 2,
|
||||
"total_bytes": 13286,
|
||||
"max_bytes": 7325
|
||||
}, {
|
||||
"kind": 22256,
|
||||
"count": 2,
|
||||
"total_bytes": 886,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22299,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30090,
|
||||
"count": 2,
|
||||
"total_bytes": 2911,
|
||||
"max_bytes": 1515
|
||||
}, {
|
||||
"kind": 22260,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 7376,
|
||||
"count": 2,
|
||||
"total_bytes": 1340,
|
||||
"max_bytes": 670
|
||||
}, {
|
||||
"kind": 22012,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 30618,
|
||||
"count": 2,
|
||||
"total_bytes": 920,
|
||||
"max_bytes": 460
|
||||
}, {
|
||||
"kind": 1078,
|
||||
"count": 2,
|
||||
"total_bytes": 28397,
|
||||
"max_bytes": 14219
|
||||
}, {
|
||||
"kind": 22313,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 31339,
|
||||
"count": 2,
|
||||
"total_bytes": 2940,
|
||||
"max_bytes": 1470
|
||||
}, {
|
||||
"kind": 15750,
|
||||
"count": 2,
|
||||
"total_bytes": 1184,
|
||||
"max_bytes": 620
|
||||
}, {
|
||||
"kind": 20,
|
||||
"count": 2,
|
||||
"total_bytes": 1664,
|
||||
"max_bytes": 834
|
||||
}, {
|
||||
"kind": 22326,
|
||||
"count": 2,
|
||||
"total_bytes": 887,
|
||||
"max_bytes": 444
|
||||
}, {
|
||||
"kind": 22841,
|
||||
"count": 1,
|
||||
"total_bytes": 428,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22738,
|
||||
"count": 1,
|
||||
"total_bytes": 1668,
|
||||
"max_bytes": 1668
|
||||
}, {
|
||||
"kind": 22295,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22296,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 31510,
|
||||
"count": 1,
|
||||
"total_bytes": 979,
|
||||
"max_bytes": 979
|
||||
}, {
|
||||
"kind": 22691,
|
||||
"count": 1,
|
||||
"total_bytes": 431,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22340,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 30003,
|
||||
"count": 1,
|
||||
"total_bytes": 387,
|
||||
"max_bytes": 387
|
||||
}, {
|
||||
"kind": 22197,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22257,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 30079,
|
||||
"count": 1,
|
||||
"total_bytes": 875,
|
||||
"max_bytes": 875
|
||||
}, {
|
||||
"kind": 22811,
|
||||
"count": 1,
|
||||
"total_bytes": 3211,
|
||||
"max_bytes": 3211
|
||||
}, {
|
||||
"kind": 38385,
|
||||
"count": 1,
|
||||
"total_bytes": 1350,
|
||||
"max_bytes": 1350
|
||||
}, {
|
||||
"kind": 22339,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 13196,
|
||||
"count": 1,
|
||||
"total_bytes": 656,
|
||||
"max_bytes": 656
|
||||
}, {
|
||||
"kind": 20200,
|
||||
"count": 1,
|
||||
"total_bytes": 491,
|
||||
"max_bytes": 491
|
||||
}, {
|
||||
"kind": 20201,
|
||||
"count": 1,
|
||||
"total_bytes": 491,
|
||||
"max_bytes": 491
|
||||
}, {
|
||||
"kind": 22395,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 30023,
|
||||
"count": 1,
|
||||
"total_bytes": 27062,
|
||||
"max_bytes": 27062
|
||||
}, {
|
||||
"kind": 7403,
|
||||
"count": 1,
|
||||
"total_bytes": 490,
|
||||
"max_bytes": 490
|
||||
}, {
|
||||
"kind": 22618,
|
||||
"count": 1,
|
||||
"total_bytes": 1668,
|
||||
"max_bytes": 1668
|
||||
}, {
|
||||
"kind": 17,
|
||||
"count": 1,
|
||||
"total_bytes": 593,
|
||||
"max_bytes": 593
|
||||
}, {
|
||||
"kind": 30000,
|
||||
"count": 1,
|
||||
"total_bytes": 823,
|
||||
"max_bytes": 823
|
||||
}, {
|
||||
"kind": 22558,
|
||||
"count": 1,
|
||||
"total_bytes": 428,
|
||||
"max_bytes": 428
|
||||
}, {
|
||||
"kind": 22143,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22198,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 7375,
|
||||
"count": 1,
|
||||
"total_bytes": 2846,
|
||||
"max_bytes": 2846
|
||||
}, {
|
||||
"kind": 22506,
|
||||
"count": 1,
|
||||
"total_bytes": 426,
|
||||
"max_bytes": 426
|
||||
}, {
|
||||
"kind": 22243,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 23086,
|
||||
"count": 1,
|
||||
"total_bytes": 431,
|
||||
"max_bytes": 431
|
||||
}, {
|
||||
"kind": 22688,
|
||||
"count": 1,
|
||||
"total_bytes": 3201,
|
||||
"max_bytes": 3201
|
||||
}, {
|
||||
"kind": 22975,
|
||||
"count": 1,
|
||||
"total_bytes": 429,
|
||||
"max_bytes": 429
|
||||
}, {
|
||||
"kind": 22270,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22584,
|
||||
"count": 1,
|
||||
"total_bytes": 1675,
|
||||
"max_bytes": 1675
|
||||
}, {
|
||||
"kind": 22764,
|
||||
"count": 1,
|
||||
"total_bytes": 551,
|
||||
"max_bytes": 551
|
||||
}, {
|
||||
"kind": 23071,
|
||||
"count": 1,
|
||||
"total_bytes": 1675,
|
||||
"max_bytes": 1675
|
||||
}, {
|
||||
"kind": 22817,
|
||||
"count": 1,
|
||||
"total_bytes": 559,
|
||||
"max_bytes": 559
|
||||
}, {
|
||||
"kind": 22614,
|
||||
"count": 1,
|
||||
"total_bytes": 3200,
|
||||
"max_bytes": 3200
|
||||
}, {
|
||||
"kind": 22330,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 22229,
|
||||
"count": 1,
|
||||
"total_bytes": 443,
|
||||
"max_bytes": 443
|
||||
}, {
|
||||
"kind": 24421,
|
||||
"count": 1,
|
||||
"total_bytes": 525,
|
||||
"max_bytes": 525
|
||||
}]
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import json, sys, os
|
||||
from collections import Counter
|
||||
|
||||
def analyze(filepath):
|
||||
kinds = Counter()
|
||||
sizes = Counter()
|
||||
pubkeys = Counter()
|
||||
total = 0
|
||||
total_bytes = 0
|
||||
max_size = 0
|
||||
max_size_kind = None
|
||||
relay_msgs = []
|
||||
|
||||
with open(filepath) as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
ev = json.loads(line)
|
||||
except:
|
||||
relay_msgs.append(line)
|
||||
continue
|
||||
|
||||
kind = ev.get('kind', -1)
|
||||
kinds[kind] += 1
|
||||
total += 1
|
||||
|
||||
pk = ev.get('pubkey', '')
|
||||
pubkeys[pk] += 1
|
||||
|
||||
sz = len(line)
|
||||
sizes[kind] += sz
|
||||
total_bytes += sz
|
||||
if sz > max_size:
|
||||
max_size = sz
|
||||
max_size_kind = kind
|
||||
|
||||
print(f"{'='*60}")
|
||||
print(f"File: {os.path.basename(filepath)}")
|
||||
print(f"{'='*60}")
|
||||
print(f"Total events: {total}")
|
||||
print(f"Total bytes: {total_bytes:,}")
|
||||
print(f"Avg size: {total_bytes/max(total,1):,.0f} bytes")
|
||||
print(f"Max event: {max_size:,} bytes (kind {max_size_kind})")
|
||||
print(f"Unique pubkeys: {len(pubkeys)}")
|
||||
print(f"Relay messages: {len(relay_msgs)}")
|
||||
if relay_msgs:
|
||||
print(f" First few: {relay_msgs[:3]}")
|
||||
print()
|
||||
|
||||
print(f"{'Kind':>8} {'Count':>8} {'%':>6} {'Total Bytes':>14} {'Avg Bytes':>10}")
|
||||
print(f"{'-'*8} {'-'*8} {'-'*6} {'-'*14} {'-'*10}")
|
||||
for kind, count in kinds.most_common():
|
||||
pct = count / total * 100
|
||||
tb = sizes[kind]
|
||||
avg = tb / count
|
||||
print(f"{kind:>8} {count:>8} {pct:>5.1f}% {tb:>12,} {avg:>8,.0f}")
|
||||
print()
|
||||
|
||||
if __name__ == '__main__':
|
||||
for f in sys.argv[1:]:
|
||||
analyze(f)
|
||||
@@ -0,0 +1,2 @@
|
||||
connecting to relay.damus.io... status 503
|
||||
failed to connect to any of the given relays.
|
||||
@@ -0,0 +1 @@
|
||||
connecting to nos.lol... ok.
|
||||
@@ -0,0 +1,100 @@
|
||||
{"kind":1059,"id":"3b112c9920bc79584669face207b9491a2a2da388110b84aa085a543d99ac841","pubkey":"c91a8fba68b9d08b9917e3a7443083a9b1364c984685bc56e2310024507612e9","created_at":1785677036,"tags":[["p","0ac458d69b9340c2e8a20a4d5f3afac1211b59e372a646beec37ac32b05ea4cb"]],"content":"v2:v4hmDySAiOH_Iv0uoZ0c5ctYsNwIFjWYQaAr5RPg5s-jqC95LxG56m_gZyio5uKm_7bImZ7hKuyoKXPx8_lfvJsg042FpZnUE8kCU8gAbl0lPTlHbwi-uPL43u0p1SACh1HHf8zyQMLaSBEIV-FTIghxtz9nIjo962bVbCqbh1sk_iMJ6qeEkmmYOCukb8ryRBYnW_7RsruPUsXnbGq5-JS4LXaKwmFmk78GYnaVaRzr_9IlQfUNKe2KD89hcsg5-SbOfLX-YEXeIeB7fKGT741tCtHs9JOBvwA7pgGwdfvUHUmz7WbSv4E6au2JENZ944rkxkv-8LinUAt0vlkXvzmHh-vwhnF9d09BZSj_tHvX2d7PEVg70EgifE6p6X5NnOjILq7VaSYTf2BLfkGl_dwV0R3pGL5_EtHr4abVGCeWTn30YJdUYHu7WV_7YuaX8tAxi0QtZ_5wstZEi8EkIS7R-ocJHNLVX8V3qp8hbFJ9jw_ZZv2Yjfjs_1CZLY7z-1u1WVjcBeXzEGQj5jnQTsf05D9Lv0fE9dmz5UL172LIJhDRQarhtowUJihycoQvRgcY8QH9wZzND-xCclxoncgku2x86TPyMmOPE9vhZX-UeimbJVSFO_PUt71quXF3l6kSLJqGK9Kpjf_yTKlcOiWqRlZ89QYuPfX5jNWEvWfv-g2rLmq2HM59Yq_J7iZZmXB_j0MH0Wz95Vdy6BdFkKA2boYWh7EKTslQHNw7uFZAsbH4keW64urcx1f21y6ccssz3snUGesmxlflSgbQCaY0C4J91OSOU8HsjGwbF1JIAK-UmLwNXsr645Z8iVingbQnSiUyR_RCWgufGaT03bJVp0uZNhrEAHckvYQ15mhHLDSIJoNCiTr0nBfpc1_iupYVQYXjWLgDcFIXhYbrr_cGPL_7sCVrfxKzrCbcm4Nz2LQo2ICrKWFUvWsDOw7Rp8e-gjLaLQxf349rgPPH0bz3VpA_vyiina8G8MGjZ1DnmRRyWn7IqN1Zc2x81_eYu4d25QAeqtctF86keK-nwQcQJt-frFmn9_Ei4uaj56g7YPTIFJF7VLV1af5xf8QfnsDnstmXejfIfq59k6H8-jJKrYbQ3Yue58qTin0wgUOKkPUmq0hml7BeQCykConuV33wV8Y0pJcPkTo69ufeaB8q8t-6xx78-mYNJWLM1KjXLLwqoG6Qqs0-CaASLVYJL7oVFZBpzD1FM8M4h_1d4YC9-_g22ilzm2wu2Z_EHaTOn184oiIpjg80umDtGoNgDejcAb9R8gdnI5SbLo-ianC52UO4piD1DheYurE0sDIuTbbnGgT03q4xtu3xxi-olmPScr3CHvH3mt8wWgjwRGIUgH71yoT0dvPUq6APmqOz_FAMLhFws8rMFaYLzoyzO3knSdwVkNyBqrzapRtP4DiD2pzx8w7mHI6bEpc7zMJZquJ6ksM8g9k","sig":"909df887f9f6ff688a919d16cf49a9cfc542c70e57676a663baa020aa10a28ae01d39aadf79b9ead4ef0f9a95e6af8205ca371b928f2dc498ff5f3b184d75e97"}
|
||||
{"kind":38501,"id":"73b2e63fc89ae708f89d2d355cffebcdd5bbfcea39da46e6410b408f8b9fe2b9","pubkey":"45ac97d8c6b2896d43dbc903105ad722548ff1b986269654ebdc0228ffed4bb3","created_at":1785676888,"tags":[["d","btf-descriptor-2"]],"content":"{\"created\":1785676888,\"enc\":\"3d7e99d510750b3af7b20e45c2116c88f2fca84c5147f3c839a83b4be80a982f\",\"meeting_node\":\"92.246.128.180:8434\",\"pubkey\":\"45ac97d8c6b2896d43dbc903105ad722548ff1b986269654ebdc0228ffed4bb3\",\"sig\":\"a32af8b0a024dc7a67fa881041ccd4f1c50bcd600d7e8bdac5aadc143a3c2fbeca6ba616ded91df6e92d3669cc8f8114a15778786293e1822f8b6f99867efb55\",\"v\":2}","sig":"b00356fe4f3371d47d3348ca1d5d8d66b92da75ee8f3fe7799fb5744127fa4a76758a97db7bee777b30d4da3e710d6497009e6f9775275ac516f3dbe3cd52830"}
|
||||
{"kind":30078,"id":"769fffcd14f4044105b49e1233169861c48eee0f156e70a0d3c5bbe4dce4caee","pubkey":"45ac97d8c6b2896d43dbc903105ad722548ff1b986269654ebdc0228ffed4bb3","created_at":1785676888,"tags":[["d","bitflash-mainnet-2"],["t","bitflash-mainnet-2"]],"content":"82.67.0.226:8433","sig":"60557df1a6c814e0f815d5cd4d5e8285e7e5a724080af10b5ab0ae382e70a42e1e6af0a9ecf62cbba4e0ba8ff60ef16f485be5ffdc2ee809b7769799a0465a11"}
|
||||
{"kind":445,"id":"1cb1e652eee8d63d61792139730edae9141329d91c37afb61b6cd5cc3c2cfa27","pubkey":"6bf7822615d8091f8d5b76879cf8e8bef5f20b2a73d81e36bc06bb5b4d5e3034","created_at":1785676878,"tags":[["h","8c3f1c25eefc49fb83a272a826d5a36235381ffdd1ba0c7fa4d774f0c7f1b55b"],["encoding","base64"]],"content":"Ygn9YOUc48RIHWWOgepFIxy0yRbxXB1LWu3Md/RE8sbwnnF50ijaMTQTiVCxlb5s6dITCwpFaz4oPOHIwre/vn4Se9+WXFA2sgl9iNAanzh4ltnzP1c9mG6zQtZRRSYyvCBtBrsAx333eiOKMzSPFov9QqCK0F9Pwz+5Ee3CQpVC/hJfmo0vz4RHOe6WvxW4tjPbGFVd5PrMqeGv8xtMKlAYDdKZIXmRPySxllV7+zH17sN56eRITT/6zRq0enPORGqIAsgQqIZOSe652mRyOqkvkaJ9sxv3IyEb/u8gnZ9sdOuSQs1iRAGQgvLoCKBoTqoIAqMZT6YL/NjhuQ0NzZVZLXJwggfM7rBlv3F0Ad0MgRO6HMpSXxyxKSW1T0/+rgxcvNV7Q3DNOEMOPugCyfmrKboLIHfBSTyFgKdrQ6gZZtwUA72TgGLQctXjCzXwudG+n/q2s1KAItcmG6BpxiqQYAi7iw+fOivUwz41ra8x0hpZEVbU6K9wHwpjhN9tcqq+j6ALdjkFdnffRCMUMXB5GjLubaTdA4MCWZvEGdM5YACnmcCNhTMJMvLzurm3d1+8V/wwQvsIiYIYoa6Ph/ZoXvvE6P/Pvmrg+mARugiS3rSPyE7wZDcTXrhC/gGzBJdLrTW1hDgse5QFh+/m21O0eWJFweOnZSBWYkgDotuyAhzInsHZ4Lh3KtCMnAV/O12j5R78VtwwZHrT4nnejtenNxzIcwmSNpn10kTalHPYWOw=","sig":"a7d756444139f09ebb1c69c38cbd76787d6a2d9d30a2262853f017c78420177fc40307d803b7fe4f472332cfa312f0e0549da0d258648ea58c3792905a2ea05c"}
|
||||
{"kind":7,"id":"7db435801117613a1eeffa3eaf68a9fc51fbade2951f16b7ddfa0b44ea367113","pubkey":"21c1a52506a343d12c34c0a434f7c6cda276a609ee51a0a02533febf0c84fb3a","created_at":1785676832,"tags":[["e","0000352da8dcd26bb6cbbada87e4ad466090ee86caa2e1a039eb7ee7d9b5a415"],["p","40b9c85fffeafc1cadf8c30a4e5c88660ff6e4971a0dc723d5ab674b5e61b451"],["k","1"]],"content":"😂","sig":"865e4ddde04a31a03dd07c7f3db1f87a87dee1057d60497b9f234b1f5d4d2919fe2db33b8810b8a0f557e5fb7bcde1fd2cb3a87336857f7e24333250b3a674a6"}
|
||||
{"kind":22749,"id":"e1abe91e8827ce0b42b55440d14182531ec10413503e0f0df44bf6ffb1d2ce77","pubkey":"38879d5f7d6ca197f5a43f4043cde208002391eda3d7a66529cc29f95754fb5f","created_at":1785676832,"tags":[["x","14305u172l2k3a2wn1e103y5j6k5v4q69c214a"]],"content":"{\"peerId\":\"hMQ2j8o62EZB1aaiWa0D\"}","sig":"d2a05f9d679f36d1ad95b172ec7343e42f26225621e2a05e8ae79cdd779bec6b0800a74165c66bfc6b3af283a1e1f833890ac87301b15188cd7d6775f86e5805"}
|
||||
{"kind":21059,"id":"ffc75a95b53a380a2de1114ecfa1426c080d5908df48fc66ce209c429ec8d4d3","pubkey":"a249d052bdf16251537b47555586389c8090db4a08687811edfb8a5dbe574044","created_at":1785676831,"tags":[["p","32a6df90883d1d026ce75ca91bfed54353fd2feb9e9f7329f7a94cb467037b05"],["expiration","1785676951"]],"content":"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","sig":"8a6d018e1563b415ed70a13ebd5adf1fe2ee36f92006c570bcfffa198646314280f07fa6788801ce809fcf8e8b5470f629f836076ba19d30600eb273ffbfc542"}
|
||||
{"kind":21059,"id":"518b7655489f9339f73a7d4cc9013b817e731288dea4b45d2e5eb6485f438489","pubkey":"7b353d5d4669607809fdc4e22690fe19e068912e0aa67c5d83c65ed12803e7e7","created_at":1785676831,"tags":[["p","32a6df90883d1d026ce75ca91bfed54353fd2feb9e9f7329f7a94cb467037b05"],["expiration","1785676935"]],"content":"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","sig":"c7c4162fc010944e98390ba22f03d2027dc635c2ec5bc52501d43cec6bc2bd78bd515de180b5586d961d9dc8b374e29597b548c28376b018b8264e28c3860f6a"}
|
||||
{"kind":21059,"id":"5e8ffd1a6c5f869a3a04aef3bc0cb701930c4348110ba8d52ff0549c0f463d58","pubkey":"79e0b421158103026cfd58b00ed88d52fea107e5974f419879d80a5b7ce3d40a","created_at":1785676831,"tags":[["p","32a6df90883d1d026ce75ca91bfed54353fd2feb9e9f7329f7a94cb467037b05"],["expiration","1785676951"]],"content":"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","sig":"bc53226df7c6b32d70168c939b2f810791493f408f365d779e652ab9cf9a88203b25b8d2f40d12ffa29e90101528de9078be4a146317b1ea1ccd80b56af6022a"}
|
||||
{"kind":38501,"id":"1a8b39de152c04c4cf7d46e9ecd4b05d718cc83f8c283e89c920b5ef91a72a81","pubkey":"bb4f1716ebb55c0cc2759c6ec70be71884486568237be5b0a24fb94b87ab0d5a","created_at":1785676831,"tags":[["d","btf-descriptor-2"]],"content":"{\"created\":1785676831,\"enc\":\"d395724b1f1d6cec4f76cb341404015ace916a410ce93993358b6ee568051329\",\"meeting_node\":\"92.246.128.180:8434\",\"pubkey\":\"bb4f1716ebb55c0cc2759c6ec70be71884486568237be5b0a24fb94b87ab0d5a\",\"sig\":\"56006b2ad9357724b0848a25f049343e59177e414550d609a1970900b80fe679335e7fbf09503d5581513676daed140d68313c6d6f0efd075e9b2cd4ca52d8cb\",\"v\":2}","sig":"111a08e451e1733ecbf6fa8e89ad9bff22f9e49bb5059688cdb741db58851656143013b8ee33fe0668e13ff5bc2348764631bad217da59d26ab82775002ab9e5"}
|
||||
{"kind":21059,"id":"1fa1cc7fb9b195dfb7bb587649e1f57a13c22a716d5b6b7ad1eaa35f3682ba36","pubkey":"df37a8e8a754e2aa7c61085a67f70c11c548381b45f6bfa45c1fe4fc6a05d60f","created_at":1785676831,"tags":[["p","9131564f29a6caa4884f5dc2bc7f2f37cf9f9f3ea79eac6cbee56f23faacfdc4"],["expiration","1785676951"]],"content":"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","sig":"b4f89cad58ddb2840fce5d18b59703412e7781d721482486e53c10a540ca6bb91266bd747ee03301cc4bc638838c2f8e1d19aeb7959597ad3a9c667c808e52a1"}
|
||||
{"kind":21059,"id":"c6a07a7a6c5efe9492211f5c7ac91af555b672564450a29a13d6c4d480da58e5","pubkey":"33f9b8d989cc0db6caa5503b2e59a174550054c8eb93688641d71371ae305338","created_at":1785676831,"tags":[["p","605e6516fc17fab93c5e1c66534b5d4a8a2b3de64942c3ed742b51626d267cf5"],["expiration","1785676945"]],"content":"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","sig":"291c834d1ba72b4cc0830e8f69bc4a07cee371fdfdad2466d1cfc6cc69b4866cf5e3895ebdfdc43255320a9473423f83f1a2c92d37d7e9acf51e46e344a6e814"}
|
||||
{"kind":21059,"id":"0f9efae4bd3dc697c547733b74c1c0b2f36c17a14031ad3f9257e35ce8c11d18","pubkey":"a6b8b3720e7a311904a9d6d5ddfcacedd7e0a70654bd41c043072de6f53f8107","created_at":1785676831,"tags":[["p","4f8e06e55adc2dff717adbde066c79a192468858816257c8c717dcaa8d51a28e"],["expiration","1785676951"]],"content":"AubJQsxm8SkAeQNftU9AwJuZRBh0U6MePhL4eF7UV8Z19uaO7MKvQFf+2jf8KQxaPtP79fVm6O7hREoUv9UbGD+LS5uCOr1Tj5Takng50m+N0saOsR/Y3antsQhtk5OoAVSmmXwA5xDIKqkcvQaYleWj2rxiCjvtCNB3XVddLFS1BTdNUr1T2/11ICLOi9eEGd2AZKGceY+hDtsNQXWfvPi4yq3vx7XdudIvKrZCqnJLhWU9YXCeTiF4FtYeNMApUG2xDU8qrNNam5J0dThfXqc7L6SWINqLLDy71uq183rxGamNSbs0GvhyGwk/PKKI/mmsb/OMyixrnAPlK9vXX4TFYkeMseNToaw3J6ZRKgItpBaOJdTliRZW9992dBhWjP/V1Aqt4LV9bztxxMJvkUZl47Uhw9BRRPfo6g1k0qHW0ymq9lXH60ZmEuIOiZXSbZTFo0BZr8aKuy7mdo3LsDNeQXCgIngbsW57QnMCjehJCgP18yP4lzTYobOjzCEECZf4v4oCY9IjwfCIGq0ODcrxi6NLOThjnWcg7DzVKpHelf6wboxV8dTDsYFHeF+BKi++Vc3cF79g4AX+VY5MILm7EHT9ktZz8WbKhSKGX21tZqgjWktCMNziCZpfVW1GLKwWtoN7yAodwP1Kgt2v2zRfd+KhpnWAsrI7YUpzXgt2OpIpIMxyjsB40bJLXfnU5HwgiuyT0n356TX2FCPMtAH5mGp0vPHLxYqI9VehtzsaQXfNJAlgCxc31K95reMPQUdjhA3PsizeRveFHG28/Tl2xZKHHuuUlcVfpPZNhFw/H0mT/JyG3lK4b5NcXpw+AiZiTK2QApoYM4cYJzeQIntXpj0eHAGi2HiKoBAYMxEd/nSkpduyInjJIX39eFk0zO5wNAX0j3ALsewY7OEPcsmlVFcXQhZHesjaUAha/iV+xxdCd6xvP8vsmp4GUB1VjvcsJYxeMquywRWn1B6EU+C4xqMHTBaGzdX3iqVX+0QS5YzXcDkyzAeU7SBic8UhAratSn4NR/plC6vRAS7PhK6YlLDoFPQplvvTHPQe5hKQgq1f7Ujx77C5QOkqHNx9p5COjqbEXNOU3XHcaajcxs/VowGmvtgvB8HoOWpZf9vnElZdg0C62Cd8GSyqVWTVcPOvu+7x+dPmPuyEd05JJ+sdaXwYhlMewpycR0kUsdxRB6YfRJFoBGBtUihW/nKL/cbd7Q6yJORL2D23T7nRf7Xt7Rw4jzovD8Bz6xovLMIZxzeBc72g+ibiVJLU9mSORcCe1EYTdymTXRBwQAWxJuG6RpzLwX4yEmnMrzFzYGdRWNNc7k149ZU97eGOxwDJl5N+x8f2fhfsxPBEgS9wPpCa+WDlMpTFA590BYv+HsNA52YzAews4Honr7QXiuIwGGoNJ80+LM5Fl/UZQFXJnJCZDjqGsECkLsWnMfIrKZOj3eNnt1fMvKlbbDzF0QwyJq0KwYDSpV6FBxWo57pxm21arN/2TCcZ5sNnHNHRQGLXotkCNcCIuZQofrwyOmlpU2EuKmbiZu7/MJrW1csQCFbM8rcVCPhyr908l7kN0dHn1AqoZ7MPUTOq+otYXTaPR9FZqVQERba87afoTJ519+zaT3HnNy+G2dXDkjLvrGqsNfIB7FDX7Ad4xcZnnGCWgZR0ZUBaIpq/P2XCYwC7A6MWqCSlsl6C/5QW22kYyN41xhEmzf+2yE5T5bT+q5Fo9Y6Tazo22G7hCUHtYpUDrAJQw/clt3tClMXxNNeD01dspXsE0gDbTlfi1KzdikiPEjoTdGFTfy+JLnp6l/DdOxRm+KmNrZDqACjruxeU8N+OoHSiEdiDVK/CNpQIiTqAk+SN5BxAV1eBDhn3LGbOVU/3u1citPxkRnhbqAW8QI3ZgD3HC3y/beFShzFN8jfyLvR6tymku4gsnH100AtE0vIgKxB5aZqjDqVJmZXoShLPnd74i0ZaHgtNB+ixn7ItreV35/U7j55AWe0UYM+r3yHmIT0Ledxuva/8qCssudcQTpBzOXIArm3dMygjlNMJFxh+9+stp4fZyTY/gDY8ub7xXoxzbyEzeTVQyiyJLFK2RfMQ4RQyntInCrW4oc43bKm7RCDKER7mHFkMSd4jwY0XLHl9fGW3DqJ+3xvlDa+VceEAKn+dTUawT8Y+2z35VxUX5N+CWbFYtUNGq375Tx4gpmXzKnZgv3BsqoMD23sFFIrVi0oomLI2lBAxjCHOyXvbvT4X02auqHy4jic+E+9D2AnCoCmCIte1lpmvvlicuCYrcDwXj/qdgtB/avQSw8W4slGB4pCK3LuA5BFPd6D1LlnwdaJknvYyA0axUYK3pklECzOKfo1OM0fSJ6bGhmOj82Y/FBxeE0qYUPXISLHBvQ1VI1ylYfQX+O5ae2cuiGWVBy1xEYQ+C/fZo1bsgan8U7PL8RAuba0njNgHe2eP4MHK4XGZocQ7sn0VFb4F0TYXR3tT3DslW++l7mNmghJ1RbOnslI27LiBLRhjtmJiQ4+1vlDa9EBZqM5C4wSzz8mNeug0MI2ZXt0mzQajB//EfMCbyY8Z7zGfosic8a8/Ow4xUsH+hxfAE7WM8B/oCnx0A1Wq7TM0vQcIl+78j/b2p/pVTeVkS9WT1xwceRlwWmBo244QQweUgHRyhN8QSW+wfGVUTpzJ9k/5YrugVtUkKiOfgZGZlq4UNo5r973v5E9UMvX9px16FSx/cKJxv0u8sAl1uY6L19CXY6sWilZySxt7RRy5ZpMN3L+XIDH+QTCqR+njO5lIOZQzmzpFx4Kcl8Pij0EiV26itm6TnrLy+OeYj6iKQZvJnHK28hyZNk2CXQ6bvlgaCU9YuMJTgfrRSD0FbRWOHvrbjlTR1iGGm5SeIMJtzOHv5t93YTgTcHQqB/3vsUbCxrviSilV/uFv5zWvZnjZGnaMyXV7tiOZ1B2KYn5CTdwdiFgw9oiRcyb8Zvd8MrfYiBVTGimzKRCpL/CwiF3dyRUT44t/pV9Xp3kYi9CLf243HmFIPm4njmS9pGGUv9p95xdSWdbN0Vwsyqrwbw6xEGHByDkj7QzUQcmUGyqPHXI06xT8cR97x8cWPzObBOQu+Omy3174MSNPGTaQPOdyQvawVLuiKbj6yt6CFozxXsyFHTp5c28OCqRRvs33oQiu4znINtv3XAo7yXfNjzx7t3LjYJUeJUXU5BmBrbEnrTaaFVBWCoGU4+ojGPWvaIkEaH64faYlgSeOgotu8ElpQ4FvHRQP0riD4yD9Dnfh7OZnBDU+k/JisncJB8Y5DrpAPMRaYt6TWtqMA6zXzx/5w+2Dmt+Aec5ubQueyk4VTT7VwqRbYk8kRxtxxgnA7G66vVWpx+NWKpfRLOL+1l+QZuFzlra8UzXs6Tgx/V0yEp/I1PMi+C8AZKHIZWZx/PZJSwFIZs6Dmmrv63Ff0bgLKES0uBdHEFBU8uqTXJIgTlSD30/AfL921mJD43wgHqrUQnoU5lj9Vvs=","sig":"70c6036ef7b66b2954d3ac4a944f8c5234bad1b37b43a50cfd947fe8e984e0cbf91b3ac51b17aa8babcfadfbd27affe5dee578c36103a9660290e7aabcc814b8"}
|
||||
{"kind":21059,"id":"233787bfae7c7d89e6d09ee4d1348e59be138204edec57ab399abed267e9ad43","pubkey":"38cd9712528928a6b85f526abf6613917c52c636608e1f7411b33ee457d5bc4b","created_at":1785676831,"tags":[["p","7b938b906ad984ea438f8af5e464ae3c2fcca4acefcfadbe7a3d66a7a69212c0"],["expiration","1785676951"]],"content":"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","sig":"e7894c60e30fdbcb92032f6e2a80090b2474996796771becec02a2e1af748f3c893b113cc6ab197b6fadeceb10805fcdba74ec43617cb665199ebad82209a2d4"}
|
||||
{"kind":21059,"id":"f22714bcb70a4b41ffd4712f8e5764a0d6bd3af78f6107134932bf8531f52621","pubkey":"fbae19b87545bf7615aeb74ac04cf926a50bf332f3b8c2a0aa5f4c877d36e351","created_at":1785676831,"tags":[["p","fc62a3263abf4a39c09a7b7064aa40480788f868b653c66dc6e3a32c6880a506"],["expiration","1785676951"]],"content":"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","sig":"69949c1cb10548c9a991212c50390aff75777fa2eaf5f979c23f7e031d48fbd0202b7882248552330464dccd8fdd089b613e46e343e540ea49c111005da39d01"}
|
||||
{"kind":21059,"id":"83cd0f7e4b2e434807599c79a7f0549266bd37f0b91847b0c1cc9681417c9041","pubkey":"b6b05517cc607db1425e192c3ced2df864b46000526d5f50e47b74d25c99436a","created_at":1785676831,"tags":[["p","08e99116ad58c5aa5e6e7dc40668d5d7f2c080fc9fd697ec0aeb76880cf54bd9"],["expiration","1785676951"]],"content":"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","sig":"466fcb9413f41abf5337adc2032829603aed33963cdaa304cdf5522bd45b59905298465515310b00588aea216c0aa3249618d60e907a19363bf84bddac67cd25"}
|
||||
{"kind":21059,"id":"0afb26e3a41a100c304aedc5b80548e679da585e4af81391b7e0196f5eb694ee","pubkey":"d66b7344ecf950b1261dd49de99deea8b325f038dcc1ed9e436b57f9fccefbe3","created_at":1785676831,"tags":[["p","fde8ca9b4a9d1f5d2ed8b82ea13766c37bdbf6cb50bd272d642eaeacc713563d"],["expiration","1785676951"]],"content":"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","sig":"6e8c0633ec51e9d5663a865754116c27582180150f5eb7581570cef47b58449b79315c1623c2684eb4075f46120cdcdecf7fcdd59e57181132e754be7fd8d4de"}
|
||||
{"kind":21059,"id":"eea2139089ca939ab3e858c7c626609fe629f4dec943497e0aa8bc5c49d13b78","pubkey":"71654ee31d04384b529f095a9cca21b58530ab86c35e239257ae5a6b86b1f70c","created_at":1785676831,"tags":[["p","5376ff74b7bb5a5c9e97cb60a1d068dbdbc5ec39c4346156335747b776ec6d84"],["expiration","1785676951"]],"content":"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","sig":"e03f0a94db48468a6a07bd0ae0a9792c4752f3d498497bbbb3b6fb1873bcea3ba8f2d08efd7e2ca67928a5183f3bf9361699785adbad273a1da60c58cbbd31d7"}
|
||||
{"kind":10002,"id":"0ff496f20a3bc170afc15a4141498259c26fb487702ba35b9260a96b7b5ba0bb","pubkey":"0000521bbc284afcbc646771c0fda5b1a839a0d3cd7b6f4fe2eda9be15ecbc6b","created_at":1785676831,"tags":[["r","wss://relay.damus.io"],["r","wss://relay.mostro.network"],["r","wss://nos.lol"]],"content":"","sig":"111925db0e99748aedfae54d2442ea8053130095695c5cecf798f3d34cd4039afc4b41662ee128fde49e3c3d517523fe8a828b21d31033c7f4d264e43c2ed35a"}
|
||||
{"kind":21059,"id":"7f897e9c805c499c963dd8999caf3645b5c6aa968568d5f37462ab8659e41853","pubkey":"6e7e9c51e2739dafb6348212fbf48fb6d768002b018125c8cfbbadfe70b37dd6","created_at":1785676831,"tags":[["p","aaf802c63614f6028fca31eedc3d0021bc3320fc95d0e3af5ddf8e7cae871472"],["expiration","1785676951"]],"content":"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","sig":"24b691e5868fdfa5546625783063d68c5d6bd412e389851e5555bb15b4c6aff3251474fa3580501b8cce93e9711a982dc2f1e7da6ae167ddf459ffec1af0d94f"}
|
||||
{"kind":21059,"id":"ee1cdd05723f5a6ef4ad3caf9db988f33f9a2921a82cce6f7a24158218ab38ec","pubkey":"755a026b88668c9ce69857b49983a95039dd7689739acabc169a21315ee04783","created_at":1785676831,"tags":[["p","e15d56d1b0ca49d50a4f71cbf04774ae606c4632ad7752195ff9b80c5574e0b3"],["expiration","1785676951"]],"content":"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","sig":"0f74f06f1c14373856bac66f45fbef85bb774aa1e6a7ef82ee821c5dd81b3d32a6666b815d2b53613fb28d7eb63b7a6859c15dcc9ee6b67930ecfa086b10ded8"}
|
||||
{"kind":22653,"id":"35b97981fe7f50b3f20cae1277b4861b9fa3d49ee7dc7acb8da9d45c1287399e","pubkey":"146c70d40e1f4f96528309629258f8dc97e9a61aa53e54e13b999ba5d2276968","created_at":1785676831,"tags":[["x","1w3v3i5c503a1e531y6b136q2s5466t39322o4"]],"content":"{\"peerId\":\"9IVDCiG4hlib9t5iG017\",\"offer\":{\"type\":\"offer\",\"sdp\":\"180,27,136,119,41,56,194,227,43,3,188,67,19,22,123,115$ZeuNQlPcrzNPMpEycw20kbmWmAQ9LQA2e4EBLwCM4jl3ajWwnnK7utcxXmapzWDz2xsFhpNRr1jg81viwHLkwzGfOHC4/0o7KKF5Jl4TnLLwSj8g6oToW1FNupDZeu9NkaY0j8JEJCU/G9iTJ/mnnTFSyMZUY9Y3AB5v9+uk+uBij+wmOk1Q4CBDPScFZll2oBNoq/GhlUP9BqhSavsUerOnATJMjqzcMT1m8pZYe8RV5KnCDn6YnSaIlje9LmePx1qMBQBWugymQGuaX5OufdXkvabgjXBMkoj2X1/I9KbAsNGWU2ePqgfGhYXO2IrpEuqwsyiYn9UaZN+RI5v6c847DIpLpVo12xlDg+gog8L1ueTawBSBLazJmCytxqvLROFKCv0EctnbbMKpGu79nsa8NPYcp6c5BVaYFZgWbDxHaEJx2vz85n4STQ8OhjyvA003IwSrE60SUu78URUKA9SXTQoQMbu7H9Uc3+JukT4W3wCMOiMgnJNqQYvYgr2+HJ5EFWLEyD8dlnmI838FJGwnHl05fkAv5vHmdT1Eyrbbstlrn9wrSEmla5mq3cf4lLSkb+06a4D47/j3QBrtfREhnc31O/+XCzhGYZKs5HajWQF3YVW3Md9nHCGFe+yYplq5pCe6HlVSbooXQsYuYyHH8BmfdZCA+Jkrhfbasr+MKTXvvR1ARfXuddxvOjuxk9uQbIN+k1eJmnlyzxODDhMi7gJmQeOpudYWlcquuPhSYHBzKlPs15ibSr/+/Ki/upX0+AZCywGZEyPQE5MYYD6jGoX1SyoZ4jIfl8Xw6oTOTJ+esJc9Ub5LQNBNLUhU8Lh5lxw4LPkZpnepAfyGno1BbrN6V5gg3LA+aoD8pQY8DajozXQX3OWTCu8CGZTu/RXK/VCEnUykrfYaXBU+88+F+3xAxS38G1jdek7VmAMqlfxGY/21roM4zVKahtTJTSZBDK6RtK60tZffGkxOugNHGTY6+DbOAa+NfLg2GWsSkcXSStUmCzFQbql5p4g8FiiO/3udMNlqIx1nxX0DWclYGgHi4DGJw7E/wyuXn7324Tvw/UjVQvm5fHVLc7LnClr//dsQArzagNjdIolCSC+pnI/EUkWAFVwcnwu5RpcPam6c6ZtLkXPhB0bK15vdRY4QUKLNSm0kGDDs3HC6/xi6oZQgF6j49ziOGeV5YYS42XVk41mZG4cGqX9R1EWGd4ZQFiWyRXNLttaMol2CJTQ+yJC1DYjD2N793qoMRuzLVXStld6436buBHJrqL4Wzywzi6eS6ANXyX4jqKxQlXOl9nTxCQ==\"}}","sig":"849aeadaa749a4d431cb91f8a282ac09b9fb322872ff0895430f978ee69108deb02f0cbd323a4b0a92148d4014d8bc8c503e22f9b05569d7d751824737661f9a"}
|
||||
{"kind":22842,"id":"a497bc4e9330b78979645581cb7422c54b64d990b295d18fb965c15c8b28e0e4","pubkey":"146c70d40e1f4f96528309629258f8dc97e9a61aa53e54e13b999ba5d2276968","created_at":1785676831,"tags":[["x","3b47662o2j5h6w4431116d4l6k6z6z2o3s2tk51"]],"content":"{\"peerId\":\"9IVDCiG4hlib9t5iG017\",\"offer\":{\"type\":\"offer\",\"sdp\":\"167,11,114,204,116,88,224,166,141,164,164,64,134,197,97,18$zMoeDUlzCvWcmm9Mn8HB1tuqvdDd4BvM3uJBCzwaUKQ0gnUWY+HmKkpaABQex/UCuKjf0fdsRr7SHE3MQ2j4vbSabKo+LD9mdyeQt1vDGpiu1uWbq/Em0HVEEWxTTTAuySuo/cV34xa4On1Ju8LjUaaF2+Bf5udktCf+/EzzVZmGWlyWqbMmw1mg1D3UcSsye2IBiD0FpjDzRiqsweHRoqfESL6XuL5XZ1ka2oipiN4t3DtkIf+QncvSElMm4lxyOnqDR2HDcuQuJKsi9NtuXbZoyJ+rgdfbHAmKsT1hrywjk08aBI56JBUQvVv1ClKq5gRplDRscxlj4CYeksMayW8cHjxqchUEtPdqzOvvjbS/fS1hzEwplaQbYqkEINUSxCx0llT5023uwSMcZXFuPPzEpuu9L91zI1EwBYIjpIeUti2bDG+RtseCcdp8TQh6Ygwqc8Ne5HDzYQHrWqEQRSuurZp/w7+tES8NlAAmPSCPoPLyyKG57uvaWKysmRr3bL1jPdVS+Wqo0WbUMvrS6xEwYle1qvnK/6bP3JeaMhnriq6xTJiMDBplL21vOC7qwvA+sQgu/R/w7q3qcYFre9HbXipFTWY4x8QOGv/JMAf9YSSHmDYUsIKt0Rh3Ow6AJhJjC4bjem6QKpuznLwwRlWcv0sJaF0LtibH/z2bwKs6Q4OozajwS3aJ9YupJT1NcNBOdf0+9R3zZEENOghm8mbLIN0YIkSZXepR/gzn8D7fAt3Bh7gihZvZHReMytPWL3Hjoev30HO8ehBLGbJrpe+gkoxsnbU/zQT40ucy3Vp1KlbOCd7aGGSKqWvlFxbz+EraunwiLtp6gqML257CdGa03iZFKu9joOS98uSzUf3CRn9A28cbgHPvLTQ4UYj00TBb8v04uW6Kv1s0VCm0kZDt1V6moMlFGXu592B6I0aDBkWEr6/uKX1UymIsRBm3Wj5oWXVf8VEvDOYExMFJtHmUJg/z3/KUJASjoX+LAENQO8k28vlWh8b41YTVkA3sB06SZIRGoCVXcEs6+IJgqvuLv58OvZrfK20gSdGEeYdEWwy+w+4zJeaL3OZNbDJZIHCBRRvruSqiXG0OdKT2QnknrJ9otReAc/mN8E4wPwciDUsKV4278gWSZrFWuIPERcf7xxwmbxc/gXCE2bf84V+khN2YH15WtGBDErRNAbVfEwQdrAYzyGKiy3CaoxIIbOn/wR6WPFnImdzMlT2zcIlhLgTHCGo+5186vOk1M/AWsUyah36Pf0eQW3aCtb/nweENd/aGWqSaFzX+L4BHYuKSsT7stFc=\"}}","sig":"5358909a435dd89d34a1e61e94e5294945eb1eb021242dac22067aac7f0652228d9b4a7793a2b9956f879d41cbe70793eb2ff79088470ee3b6af3b01e99d136b"}
|
||||
{"kind":5,"id":"6e783cf2000cb5793a94ae2b09162e1d3f1304be6eb7c774b852e66b59fd521d","pubkey":"1ec71c39a30373cbb10e91d6efa6ef1e9dad0756d610c1a4e337df016eeaaff8","created_at":1785676831,"tags":[["e","1f4d0d3d55c0fd387950ea4e0de7e973457039bfb03b824cc71b13bbcd39f293"],["e","3aed713425ab4a0459176d4ba589876e6a313d879fad18152a11347c22c1114a"]],"content":"","sig":"8bbc6c7ee40ccec7f402c48a5230f71bad3240599ab841e46a3e155841953edc52de47f96fd5b4dd35f8f784e1cc4fc9062303395d6d049d2c78744bb5c176ef"}
|
||||
{"kind":5,"id":"df31df8ea137659a43641ec7aa14f85f6935907ae71e0ac42d5196f1c7f3022a","pubkey":"a6cd35843a1471debb1b174b5bab472d9f5a2e2391e92207c2279468c3e9ac9d","created_at":1785676831,"tags":[["e","3aed713425ab4a0459176d4ba589876e6a313d879fad18152a11347c22c1114a"]],"content":"","sig":"fcbe7b0f5cf5fe044cd295ce6ae5970ca9bcea40e0584b212c027426a1721c3f15c60e387b6f390c7568e7c68e6153512302fc3898a27b0094c2062409788dbb"}
|
||||
{"kind":21059,"id":"bb18168cfcd10c7cfec63ae32e39d5c01ff248531c05ed8d42851751c56a8c85","pubkey":"99f289641b017b67d71e948bad494b63bcd016724e95e425bba176bc8cc03cd3","created_at":1785676831,"tags":[["p","29d1d9e11edbdbf04538d90d053b7b2d32c1c253fc3df1893c11b68826630609"],["expiration","1785676951"]],"content":"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","sig":"3504f1566dc03ab9fc19e597da5baf4a3734fdcb2f7a24316d0a5f43c37bfcd54e6f9bd1d4a0d8960d1ab5d38d77d7078ee990a2c874db0960300731266e1937"}
|
||||
{"kind":31991,"id":"f8a2a8a05db114a7096435a285c45498846a0306d9538e7362b9c9665032b6db","pubkey":"537f2bbfdce17c83ee7338dc26229edd9b26226a2f258b578f91f4213611afc3","created_at":1785676831,"tags":[["d","537f2bbf-v1"],["s","available"],["L","agent-reach"],["l","heartbeat","agent-reach"]],"content":"{\"status\":\"available\"}","sig":"09a021823e02d5c2ae3ddda7d05c22e05033012645617cdd6313b5b425b491cc32c61d849d704c7cd9ff294c757d8e0ff26d553f457cd3d7e26c158a2651552c"}
|
||||
{"kind":22543,"id":"75e596503238aa0f8c242cdb2011667c813515e0f02b006c34026105f67dc2c6","pubkey":"146c70d40e1f4f96528309629258f8dc97e9a61aa53e54e13b999ba5d2276968","created_at":1785676831,"tags":[["x","456a1r2o456h222f3g036k594s5x2333l2v45"]],"content":"{\"peerId\":\"9IVDCiG4hlib9t5iG017\",\"offer\":{\"type\":\"offer\",\"sdp\":\"36,99,139,51,68,73,226,255,159,72,228,209,82,242,77,19$m/DD2pfpEe+VV4XvRyouNbCVzG2hxkrSt+3zBRI1H8ihRyklrKo5mkvQvvG97YeFy79GxjZhneAlrf1ZzwSoxO/KsE7AtZiuYI/onBlne1ueaqNZca0ZLs/eVvLA3nksV0gf4IMc8g7zJ/IXHGK+9Ha2cSW81dPPlnIsL/7DPyzvtOTpTqENqXYwkpOe5yYa/lOhEF7XNWHDcJCiDonINlMc9JFvXqd+rXlBmrXMsI2De1l4EPGHAk0hnY04uLbpE9j2AFHNMU7JaLLfYyAB2hL4GEjxCqGXuCETm+oJ6hGfsmMeF1dHFfVj+JqsVZAy+pWYr81I5F8xzzhIuLI1DN0mmC0hVV+dDTQw9AzNSoSR/ANICZxkDD6OLeepNkhLZ/h7p5sd/ue5BWONH7mBtKFZ84e1c/OTwJyteTPTokoifMWS3AS1CLAau6Uy6QFXtFz/WhmtVj5MQ1axmzM9asKaJghl4dOi7ScPYLXTluWuAJH9azpjrw9qL4PR9nJG6chRoJAbkRYAodXhT5LmVe64CyWS8GDrAjGOgqY5rmWMJQJgjPJEFVh7xX5yP6tok8z/7K53Rj2XtsCXE5yM+7WI1/l/GSv0Pv7A5LRt/8mndt7tUtg2ez8UyfFsnuZDzPlWwkWCO3jLHLSPvLxYK+X6CiPHKqcZDuvGqNQUTYC0kT0Dhv7ZBPZvVDYgvooA9KgPYT2J1um0MPctIgIzk9TmXCT845IL4aKWOwwMPFkiHc49btdDzCPmEJ9IAI++yUb1QYcnXRhe02jcMcj2t8x9Bmdu4cW7c9syePqWYpytfgsAhCnbT9gfqOoLkrPxmvNP86lbTYLq1KcFFIYIqOrG5dmV6kQQlvbzQbaP+zIk1I3ACOh2KYd1CZpE2FiSPZ9yq7dZ5LZdKd38tM75/LPDQwrLNKvg/yvm5CAMXWNpEeCSfLYUvhSKmFgYVlBLd1aUODOma7pWuRH9A+3V2Sg3rqn3ux6yHASkqvVZN5zQZ38lwvHgfc2SsoB5OkAXwAKPKC7YajsoU9p3VNHvdf6vfL12udGeFODqGqcKbTHTMJC4Q/U4/Ch40HMFbnWdTIK7+Cr4bdQVsML5kUNEqxFSoIO1mcADBxXFP4rIG/tB9GzyQZjmSHJ3bnKvBtvVih+vZZMju8cxrFtW5qedAcDw2qJhhN0dkDRQPOdbq7KkgPktbqe/j1D7NbetdGH7qJ4eeCVb4W7MZkWoNJdXCII16vh8Wv6nzZBK2ItYyY+sKGv0LHR/g76c33zyNzkGOV6AeKb8/wMHfrq1/cqut2T9E8vAPLU=\"}}","sig":"e8418147619db01eacb6f22e5d363226a5b650b2df0b2facb3c33b8c93951c08d63f76a2441beac1facb213e569ce0ba3675907d8d2348d9f1631b568aaa6584"}
|
||||
{"kind":22668,"id":"d05164ec247e35c2dccc14ae8700bcbcf5355d1f9fb589b97939d37f97f7b4ad","pubkey":"c938fb345106fb08fe6680f7bbc7b2e635967c636e763f6579accb3d0627ca73","created_at":1785676830,"tags":[["x","3h4b5840o6s3o6aq23294k3l3u32544u3s7266"]],"content":"{\"peerId\":\"LE1qO6qizx5jMA2erFhj\"}","sig":"708e7d3c91e43ab8f65630208c294307d2a0472ce5c8e57cc6ba0d548dec4a0ad6ca5858b5de1f98bf52ad7f9c5ff86b61b2c80775edad0a8e251d24d1f0c9ee"}
|
||||
{"kind":22668,"id":"f10a1eaab979692852318eade7c2fcf8ba3cec9f659867011647580bea0bcd99","pubkey":"129614faaeaf11f6606d45e39a591fd02f1a3d297cf5911c39a007c7c7f3cedd","created_at":1785676830,"tags":[["x","3h4b5840o6s3o6aq23294k3l3u32544u3s7266"]],"content":"{\"peerId\":\"ZZEfCmLfVXsZXTgS8Wil\"}","sig":"fc92eda249f298ad247000192e68a7260e25ee237429cfec40245d4c674568b6938bd9a3ee9795a432fe81e5565425802a037f2bbaeb66d83d46977c968021ea"}
|
||||
{"kind":9735,"id":"80ef4548d68d36095f62d0c6081b02a021fff27d628262cf4bfce334f8dee039","pubkey":"be1d89794bf92de5dd64c1e60f6a2c70c140abac9932418fee30c5c637fe9479","created_at":1785676830,"tags":[["p","e4146d1d7fb2f7f6e6b3c799eaeaba6f7446fd28ccea2592671cb239a13f4d81"],["bolt11","lnbc100n1p4x73qupp563fjv7p2j9qlh4cmkqhty5808avtjhxvr90mc4rhqxtpfyly8ysqhp5qq5hwkrnpgm97lt4sfh7gt82ccspge9mvwjrr45y9ej6a80tsnmscqzzsxqyz5vqsp59kuq05evhglk4j8efpcklc78pudrs3tux6slfjjnk2pzdgam343s9qxpqysgq25yxnew6a0humrzhg4fym7xtrxy8f4s23vfjert7wq4rkp88pf8qhe9kpagpt9qaf37w0z3ugfnjeqg2pqew0y2keythw36l6f36t5cqvu99dn"],["description","{\"kind\":9734,\"content\":\"⚡ AQSTR Reward: Btcnews earned 10 sats for like\",\"pubkey\":\"6c27a5aa02b769c6b51fd7edd80c5b21b9ba32c16d913b2bc8e1617fb4573680\",\"created_at\":1785676828,\"tags\":[[\"relays\",\"wss://relay.bullishbounty.com\",\"wss://relay.damus.io\",\"wss://relay.nostr.band\",\"wss://relay.primal.net\",\"wss://buzzbot-relay.bullishbounty.com\",\"wss://at.nostrworks.com\",\"wss://nos.lol\",\"wss://libretechsystems.nostr1.com\",\"wss://btc.klendazu.com\",\"wss://nostr-pub.wellorder.net\",\"wss://nostr.bitcoiner.social\",\"wss://knostr.neutrine.com\",\"wss://nostr-verif.slothy.win\",\"wss://nostr.cercatrova.me\",\"wss://nostr.einundzwanzig.space\",\"wss://nostr.wine\",\"wss://relay.westernbtc.com\",\"wss://nostr.roundrockbitcoiners.com\",\"wss://nostr.land\",\"wss://nostr.mom\",\"wss://purplepag.es\",\"wss://relay.lexingtonbitcoin.org\",\"wss://relay.snort.social\",\"wss://nostr.semisol.dev\"],[\"amount\",\"10000\"],[\"lnurl\",\"spritebeet37@walletofsatoshi.com\"],[\"p\",\"e4146d1d7fb2f7f6e6b3c799eaeaba6f7446fd28ccea2592671cb239a13f4d81\"]],\"id\":\"6e64b14ed5da47c6d4ee3caf4649dba7e9259ff2173fe9a092d46f838dcb4984\",\"sig\":\"08396838f0645989cba3c7ac753aa5a39cd7ea113ce588f4ca39b1061f1c17cfed46206b91545912de5470ee556d08fb2218f34593cc8abc2f7e317961407dde\"}"],["preimage","833bb4c5c573dfe24cea6306294aec8ee1bcf903c4b1af0af174aab14bbe91ae"]],"content":"","sig":"64460054919c2703eac063ff7dd4807610f123dfa6a3a5c838e87ca7686e9d8c697f5f135dbd4088d1688caf0f79869603b80ccca2b6c7a8f32d6622554d8651"}
|
||||
{"kind":22668,"id":"e93ca07e3919f3f216dcf0a2e0a96a016840eebf41e5fd706773903af39c84e8","pubkey":"dcb7a55095f3761726ad6d5a53209c3ac46cf9be9c8e5013313fce6de948ee33","created_at":1785676830,"tags":[["x","3h4b5840o6s3o6aq23294k3l3u32544u3s7266"]],"content":"{\"peerId\":\"qLShkXb42nycV1mZOj3N\"}","sig":"de497859d5a80968957b9cf61624e6ac7451d71249cca0a3f2945e888453946aaaf1d42844ab01e620f27c0c1f612d8eea41395449b4354def8eb6f1db91997a"}
|
||||
{"kind":21059,"id":"6275550f617b1e838bb333227f5567e49c5039508ca2fbe67392df600352fc4a","pubkey":"b6e091b72c36a10e1b33f22e798bc2c497fddaf4334c8b90d9064cd40c969da5","created_at":1785676830,"tags":[["p","2e26907e7e535fadfdadbb3c5c2ca41f39c3f86a78143642fd0e435a4a6da6e4"],["expiration","1785676950"]],"content":"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","sig":"c80ff23a16b2aaa5607fd4930c15fc2b5dc99f5e56d4cb38e4f17d1322fd9f337eb2e82573fd6cf79f7dd1effb1facbed1b429cca561500052474979e5b87050"}
|
||||
{"kind":20004,"id":"a44cef5e7a3d808548ac3300b5b214d2307c957b1b02c106bce6988fe2a760e4","pubkey":"4e8ec641f5340254c1228c02d69995ca9246c7b3b0295328cd6ac418efbbd9fc","created_at":1785676830,"tags":[["p","04504ed6eed7a46e07b708e8805dcfc2189a49108e3f42ff1137d879f21b6824"]],"content":"zDcS1eEbhLUg6zfwDZ0vRCaLCfKkltMD0OL-e69jva-BPkKQrHIrpJITgSq36FBl-cTK9wyojnUUzld76_OJDBzin-8fJSU?iv=CZo2CiPoKnVD_9S8dF11mtAOomcyZYQn","sig":"cf941df89b47a2144d2650a8c6313c976845e42d856136be7e932ddb5de816eb84ccc725f9237aa4f0a6d46f7148422bc8e956d133022bbe021ddf4f50a71fb9"}
|
||||
{"kind":21059,"id":"5d90f55f4d87f435f650e0da26e501e7d2376c74b56e259ab807ed3d89f4b313","pubkey":"90e84244c692310d3b93fde994d7a25112a00613f7e6ae8d18f141e66930ca8b","created_at":1785676830,"tags":[["p","08e99116ad58c5aa5e6e7dc40668d5d7f2c080fc9fd697ec0aeb76880cf54bd9"],["expiration","1785676950"]],"content":"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","sig":"c1ddfe11c41e265d28ad6787a6f81d5bcbcb0038367424bdf047c78dbd349bb375c6c4a758a89644faecaf94b56d8851da1006e7259a255a42cfd539268a5abc"}
|
||||
{"kind":1059,"id":"6293744ffa82db6aa84f749cf1a40f069297865f4f47e4b9fa998afdafc91d62","pubkey":"1ecbd9f1a29cf784475500f5bb060692c168beb8a73e7857b90ca4e9e39235ec","created_at":1785676830,"tags":[["p","15df570d3edadf50eefbe7d46ab9896356e52b7464774cfa865262f912cfd577"]],"content":"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","sig":"dc3abfc7a4d9a7689a82a945cd48dc7ea1f315254928111ec8a477f108fd28b59220c76377174082a5311790fbafd13d58018394399e28f6d949af95c4e59f25"}
|
||||
{"kind":21059,"id":"6b85fbd7cd052c7f39df3de5dfa3ab7959f2a7b2131c22c9f1d03b9f3d11cbcd","pubkey":"61612c62844bb7bb89a96d59667be268c8db7f5a6dc4dc1dc915769929704f93","created_at":1785676830,"tags":[["p","48092008b3f8aedbf147268ae9a191bfd003e97d3521f706d738494d55a05079"],["expiration","1785676950"]],"content":"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","sig":"0c74c118a80bca7ee3ba466eea0cd2ba45c1877f8cfce631185524e2a40b7bbea4f01fd2a4728c1ab4d503ec6d2b5d4438c74314ae18a7e506f7dd804f86f59a"}
|
||||
{"kind":5,"id":"e004071b98835065bd79466e9694e922eca9fcaf1a9699756da6ff7af1d50f9a","pubkey":"f32f0405b1976474d2eaa74ecd15c257dc7c5854e405996526023a7aef7f9ff0","created_at":1785676830,"tags":[["e","c3d841341e03f0f22b2e6e7cd0811954f7590ff69c785965c2afe1e91cc6558a"],["e","e7558455c28020c88895334d03cfa2567922e7010873686a5d988b73fdc412e1"]],"content":"","sig":"1931a895da1d66d643a2c3ea0e2d84f7c84b75be0c480f7900db9925ad0ad939efcf188d443ecfdf318649b5c5485cba9630d283a285416fc9b137153c4a52fe"}
|
||||
{"kind":13194,"id":"a3fe853699b7641349db48aaa2f100a6d3c1c4cff0f7d6fff89fc1647d6a2a32","pubkey":"d03ca1662e2bebb12d280299b09a07a9c77450b7c5b6eacb357e3bacde1e14b4","created_at":1785676830,"tags":[["p","d03ca1662e2bebb12d280299b09a07a9c77450b7c5b6eacb357e3bacde1e14b4"]],"content":"pay_invoice multi_pay_invoice make_invoice lookup_invoice list_transactions get_balance get_info","sig":"000f134426656ad3b8b5a4c4b1cd2a208bebf2392dee1763a339d76ebf4585d847ff8fdb0793fb8fd7aed2cca83a78ec21d57635447d353ba5c528a351974123"}
|
||||
{"kind":22668,"id":"c705e88ba63b117f281ef394600d2f33a03c72dd67c22b8517c689e00853d722","pubkey":"651ef346f974c18f3a781247a39ad0c1812f7817f52c3e1e48d09fb277c62751","created_at":1785676830,"tags":[["x","3h4b5840o6s3o6aq23294k3l3u32544u3s7266"]],"content":"{\"peerId\":\"gnZTneCwL6Qb5ZD4UewN\"}","sig":"85550bc17c5328cafd4f1172106e4e7af93122861b8ea3be462271b6747e64b5baaa6c952ad12c2f4d7160b6431aee4dd3df77e850b45212292816f1177c1a27"}
|
||||
{"kind":5,"id":"1e8a289daa492596bbe1d34fc8486cfda8f284883d0007599c21655e1ef7cb01","pubkey":"c3d2d513091f404497181534e7965d2b80da38f82ac76bdc8faa2ee9b20b7fe8","created_at":1785676830,"tags":[["e","b7e189df82207c6e3c837afe4900dbbcdbed7e8a962fb24bf3a9ddd2158729ab"]],"content":"","sig":"824d9bfa8b1860acb395c869895e1a950b8d067336265f28f164cfa11ba00dbf398913d00e2acde7f9ac4f81c34f13dec78394ad37376e916c28cd9df6574e60"}
|
||||
{"kind":5,"id":"504765ce365092825d7185424246b11b1b510ae68c663424a47117e64ce896f3","pubkey":"92e744f3d9e8ca5888da31ac871ef9eed2a0b198ba08f417937cbff3030b0000","created_at":1785676830,"tags":[["e","84780070c1d4646031d9d096b035b73fbc5f1c8e8cf88708b0ee5260dba22e86"],["e","b7e189df82207c6e3c837afe4900dbbcdbed7e8a962fb24bf3a9ddd2158729ab"]],"content":"","sig":"f15d8a5be186bee060ed55fb432679cfa829a5e28f7f142b4004d5ed3c5e06cebb8cea9813cea8c391b541131aac750e4c9c3d189451de67068dddf6ef946603"}
|
||||
{"kind":31990,"id":"b982613c77be9bd1202a48c630833a7949f07ee83fb76d879d4686af2704d8f3","pubkey":"867a67b1f464d9099e009e73f93ef6e5df8091be0b149bd38c85a88d29af7cf0","created_at":1785676830,"tags":[["l","hello"],["expiration","1785677130"]],"content":"","sig":"88bd7ab0d68817ee099e8d24673091a41f817f1f3c8bf849d2c91d672a35a3b191dfc52ddd485b889b6a6fe8c9654d95ba31591e32029f4490bbdd222526429c"}
|
||||
{"kind":22668,"id":"22af285ccb3f6287cdcf363ebb06b648add8ebdda93d4ad49a40330abf8250b2","pubkey":"f50ddc7a8ab4a5ae2abc2802f7e33afc40f32acc157c749665cd6b78454690a4","created_at":1785676830,"tags":[["x","3h4b5840o6s3o6aq23294k3l3u32544u3s7266"]],"content":"{\"peerId\":\"MUzRfOSvVHCPwAQ1zQlC\"}","sig":"77518b61f5756b7fcaccfd68a9c63164deea9558b0bf9fdab40d79fd9036b946848fc85241dbc797c11762d24b62265da569fcf91244c571cf2b070e53c8dbbf"}
|
||||
{"kind":37195,"id":"784c21c5b8d1ae8569d4b663711c9579bc92e6417daa76b160ce8fb764c7fae7","pubkey":"522bf69c8bcc74bcf6e8ba3dd4e2322fce057892ad9b9f81ce93f05e65ab7564","created_at":1785676830,"tags":[["d","iris-chat-device-sync-v1:fdacc68213faacb25010d10c2c6bf9770a3a6006696a8282c906c6bc538315e7"],["protocol","iris-chat-device-sync-v1:fdacc68213faacb25010d10c2c6bf9770a3a6006696a8282c906c6bc538315e7"],["version","1"],["expiration","1785676838"]],"content":"{\"identifier\":\"fips-overlay-v1\",\"version\":1,\"endpoints\":[{\"transport\":\"webrtc\",\"addr\":\"02522bf69c8bcc74bcf6e8ba3dd4e2322fce057892ad9b9f81ce93f05e65ab7564\"}]}","sig":"591246b446dadbe3a2067fd458b72edcd7db27fa9889b22a5b032137bcd14c814c8039041d7ebc1678bb73fc0b8baf5285e54ea09276db25ad1c713ac48c4ae4"}
|
||||
{"kind":22891,"id":"c4f37c58db11bd3c2d90196f859b88254d8953e85ea2e319b7367755c825ebe6","pubkey":"146c70d40e1f4f96528309629258f8dc97e9a61aa53e54e13b999ba5d2276968","created_at":1785676830,"tags":[["x","6y2v464t15574k2a276u1z5o2kw4m6i6d222e1a"]],"content":"{\"peerId\":\"9IVDCiG4hlib9t5iG017\",\"offer\":{\"type\":\"offer\",\"sdp\":\"202,14,200,159,96,222,82,153,64,34,246,116,22,182,211,172$FIiGiFA+45swhd9X7BA8TJjG/LGiO079N5BFevU3Otgzgz8iB+/cHqfFuKfuzApWtHPEqlVp06wXUEaLjvnbAkR6EBEaZP9ImobFwwLkw70gvM0zegLQCxJNxFDUOCvZtONUTjyFneKIqKkM06DTRhxOMKiuYKPR0C1RpvTIwfCnZv89I4+bQPyc56SdHLrAVX20SZO0YHJqe9c6cf7BGLlLHythEawKUNuqs9KK+8KLzQ1THHOBWjYBkvho8bBAzChGkx/tuqt58JsBjkCDbrV1QbhV2sfA6e0ypFMR29KLBU26mQLbMllAgdv8YCY3ceD6a3pLQ5njmMZrQyIno5GC0OWO/14efdYHF88iDknVdgprL2zhL00emLviW14b+lV1UnuedFROYBbqzidDIadnNIPoJO3bxuUIf/Kb+P3oKV+etfnz0/86cY3vuno28op6ixoNjt93v+3bsdZtNTVto6v41qRWj9H2D8Ap2TYpqnAyvZNCl7F67K53ONVxqw5lC2DooGfsUP7nbPBztZrkWHqH7pZ8y390FqEBM+QoqlYT3p562xAM64LYUe3ynEd+cUVOdJn9WjD5qIbk0dvl3N6ykV/IPb6lhWBN6zDrldR+gbZ6muhmJf/LOogRZtEVmYqvy/ObJIJukPBqTCL2TEVgPlmhNgH1FXzl7tIRlp1mI+aIHJwXdaAL4w7pbxP/QxNKru1WUAB9HJI2gasx0NEuFLwD16noWeZeSZfbZSgmKE7qQgHLIRRkp5qWk5AIUaUG0YTiHAaTaH4HakK/pEx5+/i2Ybz4BqdlADCDCHH7ys9/D7l7Kt1UoEKL2dbwrSFjAM2kCyVy8EHz6A0ikXv6Db8yEVLKgfc5dYGAgoe9wtHxxFmAuOq8yq0yVMKDvXoJCN5FlVNh0V62GXE+2My/BY9j/VxgOGYnXbRPEEaMTGqTX4RH1+a5hM8aDivK13BIXMC8j0/F3WMZOW8yP9WDGugWAlMb9Q8yTwVy9upG1XMXFJtCUSGHEhx00GDr3nJZ4QHrjpu/zAIvrBwXWxA2HNMumhbx0lYXUa6Ldpm7CoZMDQIXcSEzypxi/DD603pObMSPJE0pAyLIDdlTJntl9DW9Qmsff3ywVTAlc5dZEBaDmurZeretP7VGP4Q4dx2kpfHrUH0Bm/sNJLRZJIFuLseaOOxDn3s82f0eHNBrrNPorNEUOo0BHixswtEcOO7sYfYUvLVeD239zw47wVvYD3l3oPx22sbNG4i8d4v2B5QvGZYzdS0RTJUKgfJwIoYauUCYIzvhkwZskQvyKIlXcg==\"}}","sig":"292aee436ed0aa9625cc416ad5aa90e2b01729a096d66a13b31d7883fb8cc40167b6f12b90d6c206559d03812b347f85c64cdc00bd91692279b8ff0189930ce5"}
|
||||
{"kind":1059,"id":"92d46f9c73844d0e73a4da9678fba013135470043952ee249b0a1b36189768bd","pubkey":"af36a76eabe37abb29d257916b8004817163931e8d7acb6e14ee83150b6b4b7b","created_at":1785676830,"tags":[["p","f6ddda433221cd4512a1dd7ed37eea610422964044cb96a739ef15f568670367"]],"content":"v2:5D8IFWcX1XB94nMgs75pjKMWV-qH7kJKJ7cp922s7b6dnXZNRUjTXSY07Zf5cDRkU-NUGfrixmrKSeCH_9m6Oboo65haHfHck4IMZFVikRtsb20ZmDKWmFz_IchtRETAbjUBrVFCA0Pz1M_VkVtH59RjK4E1J7ij4gw0lUacIKVaBau-0ujZEouYRLXtEPKVLuxXI780Gya2OONw_m352_AU638i_KGasfa9SMQZZdlR5E1YcYJi6-sSuonmpYdqrq62EXOue5ovHujxiTxC3Ra8P2xvcMH_VwI4-_e8dt_EQ0EG8WkdqQTEwETT3h_eed-KkuCDXda68mqpbywpJSzJD_R7ys79x5vEwkvjUiEFKHiixaXDAm-s6ssYxTVc7J7vPkEFkYIaPqi3ClS5Tbnf8Iv4eLngmFrABUtjGip1XHZ_2QVVv56-2qIjra3-4BBKMSq7qm2eQslTJBgbnuh9zxdjfhqAw7yefff4-hVCn2VBTr3EQdd2bsILheXzWOEj0vePQ-OAG1WPqWD3ruiXBsJPyJs7VWsPP2_PyBfrGWCvamVadPdekc-vPjPrX1qkJustPn1m5AOTW_pFmC8p-zVe-HTPTyNvtkXZe4oOIDBTK2sctviWcrrLF_3gQewIlOD7_KRFPUA6LSMXcK3Ns7saa-jhVfxNIz0nYeW7VgxLbhgveozh7B9b9kHTgTHOcQe6_XEAa3wSHXosYYRJUe0NVMwUN5OC-mmzwCYniyDnWbinTqOdx_EqVQBOoX1VPh8eMqEv499HWnbALCn4iNcY0FA1Qe9KanHpfC-VF8Hz7hz0KB_ZaqNCUSTl0SC_vHmoeEnx_h7Shyn7vdloBXvdaaZjgDfp0otcrC_oa6ERCZg2YEkwqnmytmHOVf6zoY7OsOoRFTTQtpvd4cintjIqVg-V_WvN9M6Bth6g7iTL8Uh1aTDq2efEOeto5GHVGIQftL_uMwSjAAlphCv17a_EreXQM7V55f056Z5OIQAbOS-tXkoZ0O9SRgQurDFsc5mC39H1GoVrpPofIGUFFAgnCTB4mbuw-V3Y8xm0_MJG-xEE4fr7ymp2syDpgCedy_QkFgU9-0fv5FaDH11uWs7ulJlZ1o_WHuzC02ydpOUK_2FseAWTYw1KhN_9ddes8d7xBRF8Ta8pLPbVBNYwOitHb17cspuv1LSind9bjT0bH6dBx0vD22tHRIvkieIuHjtypcz8U5NRVmbchmw4WhpvptvWUoVqySxibpLBNTbUVqlBxXJole6_qkpnDOn1qkGuJTN-tWqQfzZyhXCNULWZSlZ1NYpBrSgTQTO6QBh_tr9oe8Fc-oip7_c7o9gxcvYtmTgghqW7meYhi_tb6dO9b4JM8VAj9VoiFPd6gBXNSWTJ2ej36aqqzF_d_KEgpVr8a01-4owIZMPTsefZCMLzoMux-q_aYfvtvhs3wM7YYHWfyIw","sig":"52aa16a82ed4922de3a8c78fcf5be1066a328cd99ef0b2268e3133e9cf575605c3c23b42d6c5921c00e19718ad446eea051d4fa601527694f01257fc53f830c4"}
|
||||
{"kind":20001,"id":"0008627e93710f902251efbebea4f25418fb8263eda4cf113ce40d49100593e6","pubkey":"d4dd33c3e92280a7cc8a4bd65e5b3876a572218902921df450db07badb1bb00b","created_at":1785676829,"tags":[["g","td"],["t","teleport"],["n","Boob"],["client","glub.chat"],["nonce","1534","12"]],"content":"","sig":"5175c979a4127301f00119c041ddb30a0b2836485a1d05d824aa933c84a4775ef163588118cf8d9a09f805860341df300ee4a8e9471443544946972497e0e80b"}
|
||||
{"kind":37195,"id":"b3848e2644e70a784d948eef64eca608ce57ba1a8a75ae5e26565ddcaa9bb8f3","pubkey":"14b1d34a9d862fa6073e2f9ad689ff11af8411751f71f10e5440cde3876c6710","created_at":1785676829,"tags":[["d","fips-overlay-v1"],["protocol","fips-overlay-v1"],["version","1"],["expiration","1785680424"]],"content":"{\"identifier\":\"fips-overlay-v1\",\"version\":1,\"endpoints\":[{\"transport\":\"udp\",\"addr\":\"nat\"}],\"signalRelays\":[\"wss://nos.lol\",\"wss://offchain.pub\",\"wss://relay.damus.io\",\"wss://temp.iris.to\"],\"stunServers\":[\"stun:stun.iris.to:3478\",\"stun:stun.l.google.com:19302\",\"stun:stun.cloudflare.com:3478\"]}","sig":"be31af4686ebfe3d850c516be763e74f2c5588a19427dcee1577b9a3b6dba59da5ac920fc6c6a524631e9e9bc32161b8de01116f34758055101c7cbf406c6995"}
|
||||
{"kind":21059,"id":"7e8ac972c6a94ef4fd8a07ced607d6229065d421d6c480fc13e7a40979f981a0","pubkey":"7be527855bd9034f673f08570a74b91411141a1c07b20f0d096386f1f2552a91","created_at":1785676829,"tags":[["p","4571e6236c45bb75ca1bf6c142b996d9d451ec6c3fa14ce279dd53a827b6525d"],["expiration","1785676949"]],"content":"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","sig":"8af0bb1316d7577439f261ad76875b1babedb47262565eb2a8276dec88691a80dd64e2a894dbe78562a4b69696141d860ec6c9f890a14c84549a1225a38fe47b"}
|
||||
{"kind":22795,"id":"b0806a8559de7756b708116bca32573e9a11d6bbdf0a51fcff4cff7628d7a6df","pubkey":"984094d4207e9130fbb6c28bb438e2cfce471ae19c71046d6950fd57f20179cd","created_at":1785676829,"tags":[["x","s1c1b5i40406k26b1f1f5y3s3f5o4x4l534s24"]],"content":"{\"peerId\":\"5LAzUDGlviJBcbB5kzJl\"}","sig":"eee99b6279b298bf32d5bd110c24176560e6144d36d134fb2c981eba9c8bc803378ccd154a31620938d1d90a9d9dd248be70321ebb4943d1e96019d40244d190"}
|
||||
{"kind":21059,"id":"27bc4a662ebbc319927530f64000150760e270bdce69cb12b442529ac33ca680","pubkey":"73399d3a149703031fa0d4701ea9e319226c2979343e89c4915230a533572656","created_at":1785676829,"tags":[["p","fe3cf170bd88be377f684d98d098aeffe3438882eb2a81013ddc4e66ea00dc46"],["expiration","1785676947"]],"content":"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","sig":"4813c3412e748c9d99e4ec4ccc6b667a4140714a094914df05d111025e442bd30a594714f03cb0df3537ecc82653c7045b98531bbc0cf49faec2bd67a107c175"}
|
||||
{"kind":21059,"id":"e323e7671e52fa1f93b1c38b74d9045f0e7e0c57c5eb64f0dd9dc0aa4cb7e9f2","pubkey":"42dcdcedf8f9fb5a343aca2f324985960a296f89a40b186ab2663ae544649098","created_at":1785676829,"tags":[["p","db4332cd601e12593fbe239cc5af98f27401d46012c778694c22cb147ae3efdc"],["expiration","1785676949"]],"content":"AmQZm5EvxoizSNBCnSlDS9ro5D9q1cKQeQhHj4UGMBiiipON4kG84nmuneRNTvsN0Fw/SqrWzlwDDitjY/b5fpLgk6yt/wn96PWbJv642Wt3yhNVxrfyUpxxFk9CcYYiAx0yWBA1LNLfK4EDNCq/6NZtYGznkGyNy2uX8dqe54iw2bfYhv6e2l+E3+c/A4uPg7T4dAM7KHn6Bh1gFetLmluly6Rj2PwQFEi024Du59pFVCjnMEP0pcFtflrKFo4krhRvYkSv47VTc7IYXyDx74zkN0zul7eYoMBDRemMc0U9vPfTPPAdpskRNKatFkkyJkXTq9K9KRY14wIeAkkOPoNI5D8QcjraZs2DVFAPEh2O0mnkmMNfQUkF8+EgdGZQtdXZumE33YKW1XFWAECOc/1d8+E6CcRDJWhRoEPC8vauIBls27UYdnXTg3AcxOTTd9LaA46wrwNH9VlLcfRFwPUcjv61dZwDpKD5qznJdOJrSSRTAy0WofwwSP/MbxISgMf8ThllnXA8N538uDUlKtc0g5A6U1hmlLf5YzYvbEPRqpnNw9kqfKUoQXYi3QeehWXw149uqYfeEoVoL76YnPkHvxjqlw3mYsEJc+257cgaIXF8JuwwQ7nskt64XgYWsgVbQvfnaxYM0ooyNNiTHGEXVH95CfQAIVsPNRVzxE+Bf9Z4jF79PNoEgC2Kgy8BVlAnZkSTYYYeYEn12I96NzcR+Qg/Q+ZkR/sr+XzixUS8L78SZHySrkGnO6eqDEHOYdkO5wcd47ugSxYECOWzO3+IWnjF/qRai7UxgJyOXEw400ghmgMD0svtEL2eihjgIhFrmyDnRKlVYDAcYbmcMrofFueiVd2XzjyUnBQlM4mh7rsF03QuA0bTDcY7LVb+5/COnFHmhknCZdd8rFa/kgi9jc84IA9maIhMpsLTBohRQjWZkVYFrCgsyWCGmkZjCttfVrDUkp/G/RJjw+FX+by8Kllpo2mLhbtAAWRgIRTaAdUaKZtwqFUOj5sBQQ5PjTce73hg7ngtAK24aYvHuEmmwXPj0oHNxVuwDg0AX1SNKItzWqOCAefQyBeygPIBEy1/t/3bAlTQTnUExcu+PHeDRUF00aTrtCokbg2GLBj+VVybEGX4qOhvhmm7izKakmDP9p4ww0Q3aDmJM2ITPgEeSUsL9cCmMYihxFswNkunb2xTVu96QdgY07axOWrvDDnCJr5m/uECdF0hLI0zEOACqJVW5iHUc/fw53rnORRAf41zG7j0OVFLweECnOI0DLaxfISUb9s2Hf6idIhRpm8c+gRrPW4Sf7AJqaT+uLY38xwdLiLZ7mmeLvVPhvBVUcJh6zKZwdv/MycbY4D9I+9c3FzsoyWE1IJKGhrhb+DR3x2wsK/cbO9dJn66dUqcNq3BGuHYp5ioBaWMwc/S7EvynFj/bLL5FM1jFQL7ihvS3dqKBq6uhcEK5w7cK86qxnaPpaxjkBrd/JCFdLP18Eqb9nnHpnUHIYqohuecN+/Wog36ycmO/g+SsIdfDLZ/teRNkVQXnv199n1gO38WcbxkE+6PDENklPydYEwu89yMVlTCjWQ4/Bb2NxHN9n8B/XolinSGZk1M7rEljwYvh+P4LX/T8BIcOh5mRGIxKnTxwpxD0O09WPHO3wn/6gUSIBw7WWVxZrQb1EmEJakg+nMZ1bSy3MvCMNDcFtFdkBU/YpU+qTeRZSQpoGfecupZ+lsRCEBNRojRuU+z1fR0FM7VMcEcvA+PXNKK6/mD0Cp7j04cU4vbM1QykEfNb4GNGtm5S7ubK0Jk8Q8k9NXCmZdOGc5XIxjboUKZCOY+KP9DLakqKx1F/zPDiniHZUsCpLoRWeDNdie9YSurmwu/pV5Q6YiTqvReXpjksm7XrNEZY+5eg08yi2N0HeZl8MEa2On9+YyPauoxH7DsAJ/56sdRbOXBe0X3T6uEyyniMUtuCvTkPhUdCflVWJd8H7Z4ppmy+Ua8/vgEd34rWyKTp6uCxzTm1faJT8jYxio02sAONeWpGu9bhuGp1RY7yeQMYR7xhoxr6zFRxJaeKrj9cs30O6HxrVYu/hZY8gUlkLOTvAwu+S3QqDezRGdtCKAfygshb2ESsImG6WDbKUXxaU92cg==","sig":"269bdd6b0a63d8d7842c04b8f6e743848caea5442047c3bf9aef46d389be02b61d6b43a2377b33f6ed6b199c64f2775120447c2281560ed6cdffd14c33192476"}
|
||||
{"kind":21059,"id":"80b6cea3ad0b0abedd667b18d3804879c9b053bd309d388e58aad701d3c4e129","pubkey":"764da1376080b4c50b442e8682283e911a211675ac019a354eb4abcb3e6febf4","created_at":1785676829,"tags":[["p","c90adab9315b97f7bdd9bff861bb026c9c454be1f1fb3a9d64812b75ac5e2bcd"],["expiration","1785676949"]],"content":"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","sig":"30e2bdf73205825bf3a19ff6d5b0fffe49b2d427470d7670e9464628f58791f491b41f78ac8a137ebbe64fb0d603c1b516e857ce8561c8812e53c04e313cb3d5"}
|
||||
{"kind":21059,"id":"7d821dae2407dc0ce17b7be76558fea2a7b42332a80fa26a775bb481e7ab4936","pubkey":"51ab81dee29a9a2cdf3adaa4820d00f4018cd540d6c4b6f5b7cd70a155193e7d","created_at":1785676829,"tags":[["p","4571e6236c45bb75ca1bf6c142b996d9d451ec6c3fa14ce279dd53a827b6525d"],["expiration","1785676949"]],"content":"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","sig":"d2ecfdef11672886570bb8da9f00e89ed488351faa377f7cfd9625455b752d6765a1415ef351bce454bb4c8506e9a7795572fcd0ca3799a5e1c88a96ad164287"}
|
||||
{"kind":22668,"id":"e5bd8d0ba4903407e15dccff8c3847a142403fa8808f08d48927eb1989630530","pubkey":"011290d507f716e7e28b78431c6dacaef737ed0c296eea006b3aeed76162aad2","created_at":1785676829,"tags":[["x","3h4b5840o6s3o6aq23294k3l3u32544u3s7266"]],"content":"{\"peerId\":\"p57BF10Qa2QR5CWwRPwk\"}","sig":"bec46000893446903a21a2cc3c153fd0caeaa2863d420f613d5c86eeeea86252a977c415c08782e52af2dd68e12ede07786e437f4b4e5995d3cc9dab901715e4"}
|
||||
{"kind":20001,"id":"0f03ec93ee1b132d83fe87a2a11488a2457ee29c32d012ef86d6499be2b6aea2","pubkey":"b5c861e028296358eeda540fdc4bf0a55620fcfbc8402c2aa6c0e374ca4caa93","created_at":1785676829,"tags":[["d","781ea0904b118a95"]],"content":"{\"e\":\"🐝\"}","sig":"8c1f43b54758888bab77b247e125d39cbd0f851a9a866e8cea094740fa972dc3545245e97c3b013a10c4ec85ddd162698c377e4335b17f9e3c5e4c834e5d8469"}
|
||||
{"kind":21059,"id":"efa8558e04b1018251c1ca9f75ade84c3665236ac0dd4e7531a5aa4ac50f382e","pubkey":"61e46286db0f8b3a657c97a18b24f941c2bfcfee82e4dee7c43a27dc73d9ea9b","created_at":1785676829,"tags":[["p","62cf088f0fa0f198b341ce6c3c4d16f1bf06c4c94b11b54e5e7ca6290e22e94f"],["expiration","1785676949"]],"content":"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","sig":"6d06c924a3cd1d73deaccc52a86ab472a3a30975ab54311f5e3c83d0896f18abb7c921e5726317532de6382bec35f2237c4c225c03abb8cdd52fd143a1c0e93b"}
|
||||
{"kind":21059,"id":"cac1ddbfca49abfed7106b5e8b35799e803a7323c88f4ab9311c55904dff8038","pubkey":"cc06b791544dbf3924fa4839b43e6db9df75329b67278fd32963cd19e9cee582","created_at":1785676829,"tags":[["p","f3d5c038e4ce5015ff2069c5984c8a47571a427b40e120d5c412e6ae6647744d"],["expiration","1785676949"]],"content":"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","sig":"0648a3e97630d479672873ddc45636b50fda69d79145c6cfed77d518a27808417169dc87ed861eb0e6ca1a8bb274dcd8cf970b37cd3f0d42c09ff7d71be20e4b"}
|
||||
{"kind":22751,"id":"cc1b2bbb1bd8ef560837d280d1510d93d5199aa019673d00a871aaa14bf4c848","pubkey":"3d5ce431f2987ab0f0ea0745e5703bac780ea9384e90c8a198ed5dc8978f1ea8","created_at":1785676829,"tags":[["x","5bb4v4t492d291p6m82o5g2eb2m4w1iho1h"]],"content":"{\"peerId\":\"KInutrde21v4Es53GmBx\"}","sig":"b3875007e6999506f815c52162492680a92f5323dfa51358a5481174692a5f53cee4f8b6bf295f0b69704c777c2d15963bc2fec70d5cb1238569e3189d1097a3"}
|
||||
{"kind":21059,"id":"ce16cb9b2bf391663f91c94f158745bc94760d383dabdc35ffe728462aba63e6","pubkey":"d5bccb32f8efc4810802306118e3a2e2bc39b690f6e1defcc06e007b3da9e591","created_at":1785676829,"tags":[["p","2651be916e121c6baa67236dc6882371562f2dba151ddac18948b8edd88c1321"],["expiration","1785676943"]],"content":"AiVw8AA8OytfUc5yf5g6rVviLP3xY7wgtwmBw0aJWgTdEJWmJCJ97LozoczGBTbIWQgKwhvlArvPgzoMamaZx9M7xRom1ny3rjZlRikjJ2lCcMN8Oktoj/MIy1Y1y+PJrNp3/joySh2qSCExxzyBdMs+2VOGUV0s6DX8c+KNt9HOtdfO1YpfeDdY+AP9KUbn6XYFsKlLR4TmVfNt2poVPi4mPGe0ccNn8PrUwTFJj5/dWB1fV/+VWexUn8rlbVqJ8GFukUj7ofe8j+9Sw0kFk8Ox6XpYUg0ANIZjQv8US6ck/YOIsbbFYL3IIwWAPXXMMrvqJGdS54Q8LIg8z4UtwI4RYsbUJGv3yjDxOkWjV1Ij6oPOPFA3sz/2C7OIUNCWnJ5iCbad5aiyXHVqtjCfz8nrqvrgdFu9fJPsPCfXq3zq3yp3DrZ+HhLB6ky6uP8Y8vxosT3o6LeN8up4fgW9VqgACKlzbQlRzlnd+MkEyUTPY7fFlilbJLw7geEmKTt8mro2POaPUjaXqjev5durZe2p/ZFuNw2pFcX/FW4szvIvk9dDAkbmfaqqRltEtfilI2fDYjp2Q93gbNBkprEsdhtpJkwQLb0KeEFQpBUwXBWJvc28WyF/B6CaNXB2zkdPhJhfzfXdJM1x/fUzn4NA1V4vt8+gMkWY86AFtX/i86S0X41/emDM+e+OkFD2dss2Q0I/CM2LRZ8mF0QGh0DXWLRO2LSB90PENNIfjQnvP3Zsy43GUwTAop1KnaMhcb/0m/g1LLtfIDciB7cTk+VTt4kWcUCveSwTr9SSzGMD/ELZY9laILosRZ3XQzIBT5wkTdXRmzC10al6Bw7705sqcjzPhb9BjaGuCjy9VVCYWh/pq4xELfzgMFJVk+Mdi8kD6EgAAanMb8fUIgeS8TZKgja3lBsB86YRNtW+PH3KrpgEXVUAWm6xITuq8Fe4rvor1fLlFl8lTGzroroBn9fz707xherrF72IhGCqf9MvriptOJplnGRIBFUWxJeHh27iDJspZ2993u6lpE8q7T7akOOdVJdgUO1vr1OPgcT24yidBjwLeUFwU8arqGdxqZeSU6kXD5kQ7lB9iEXbw8scz3/dfAC98KvifxBexYHU4cxR2yVeRnnY/Gve99DLx/RM32m/w5reulnY4y45EffDf7RewDerhQyNdjuaeEfSsBQtDm6IXRo9D1vqfktKrp6IUlv40muTTBI49wAe4gYOde6tcNrYegmqQj1KAvDwXgKUBh3Oj6n8J1x8ivaK5G4VgP2WetdjSa/YL1v0lUWuTP0A+hML4Zu/62mDZH7eXqiIEWTEEUnZc5E0od5zyS73TbrHOQMsDUiHLuVYOaKOGf8TxGsAF+Z7C6CJ/TuC6XJF239IOjJBLwQ1WUlTW1g/k8qIGfprbmXxoe8Cj86GMp29lw1zln4GRmhSna9I/D5LCOyGVG3OIRBL57biZhH/xrRpxo3opJlQMWEUBUHsKSRDnDL91XK/XLP3IvS5Eaily1GJdldqHfgFCSUPuK1/w42rBJEKXbmUKHi3R94yD3EBbylGnTTEvZ16uHmFiXfHkEb12h/MOc/eqX+fQwZUmZcdQB1BrjIzUEPLNmV/ZZJWbQHUy8wim+9dJaRaK0W9jWjItBu7L0jQa8J04WoshfgZZrVdy/kphXh1ZKNRC3BNufhS0ytMZa+wwyuoSKKpquDC5hHplhx0NXrAKxB6Y3a94aJo6DvVuFZvfa1dt/rOL8wo9i+sC7jmbTBHZgMPEHeqKoCDiUhLTCY+zTLK+yaG4eYvrDXP/mM3O9vyp6Ia3AROegLhbOjQ3lR9AAUeEWKi4W2GgKOX497ryyQk/SQEvKVADXRlFpdInCap44sEoMFQJZCS/TUxy2c5GP3a8yfBEc437Vm74Ui7CICXm64tDN9MRapzO29juRlcda9NeATA16WTo7HXBgG8ZKhucBUvD9/r81bHANuFRWWCavzMuav85ujP1+387SgIckmtSUsv4mN0blrQefib7oYYuhkkazLcw5UVw6bcJFJHCTxtilgbE6MGh5SPUmxyh0UuTOhFxYlvgfF8CY8dHSVPRtlxBkCVYM+mewJRGsA9IuckjDEaQQ266pDDNmTyqJizX67wT4paJS15R3i569eptko9BJYd6y7dqb42HmUmucRYOcKiq0VMtq6Nsv7XmbOR/tAGVp6LeQXMV2b3SEslPBBLK4+IcV312uhKuIp6szXV0VYUj177QGhBJ+O9dbv20rTP9SeVBiN6VFK4W1JboC8xRkccevwwBnYceWSuDm/d6nlb1WieHQpxlWFWrzVW8nbaGGllEVn4HTFl+rd7+dfC3a3bDTfS+lGAvizuZWnzGvcNE+us9ZIbLf1tRXWDBVxa8SeaZOyod2dTxeTgd2gs+hcppzuIvH4SS0gjSsmm/S3dbxWnSjTpocAT6KQs1sx/Ku344Oi+Ngk5yiAlAKmnRdHMJA7peJiqq3lDy8O3xAYyqidiqhBR9Yawcf1F8fp0vEVKrCbIT9KhJ+WYSLUyaa7itgGoGeLtYyFTml/t+kPW1s1fwpXmkaM+9LvYCoR7//+jS3v/Pk63ukbFIKd5bwU4HOj0PzRr4LBQHWKQds/k3cH7G+sPdeCjdkUQ84WkwErPWsjeiRSFqnC5wE8byZ8V+kcAEquhsDBNsn/lD3YbyIjUoPfaCX+HxJz0r94lLwcx1tWTLWP29+WppOH0EiSoYaUi9dwoGPjOzo7YHghLl4O2c/858sW/w8HlpfI6k5giBi+o9kYo8ic9O3kgUH8ht5H65DxUMQTqFC31","sig":"67272aed2ffbe1417bdeb2362a9d49e6535253b5792ac600ea3992395b7fed7cae545a5e14ed4a0f037390707f5d0e50c6132b07a480249df008e13e724b8954"}
|
||||
{"kind":13194,"id":"3c0da6d6cfaa5f198bf2dfda454096968434028808a2e29e760a63a824de62d7","pubkey":"18ab43661d7848e6e3843a09c6aaafb007af2ce2ff3481f81469ddae1e8e8fb3","created_at":1785676829,"tags":[["p","18ab43661d7848e6e3843a09c6aaafb007af2ce2ff3481f81469ddae1e8e8fb3"]],"content":"pay_invoice multi_pay_invoice make_invoice lookup_invoice list_transactions get_balance get_info","sig":"29c9cef993fd1012c2a21691671afd32f057f9364eed31b40f0906348ddcc6606aa5b2e4ef8aaf9198e8cc97488cd4133ae650763a3b8da3293e72e07c9801fa"}
|
||||
{"kind":21059,"id":"38274f3cf136f9a19359e866d55b86e661b9c1da65c9e826c08f7669e84a7337","pubkey":"931128665954f1a3f0fa09a5e3f371ab192fe840575daaf43040453d838285af","created_at":1785676829,"tags":[["p","2ec845714f95e64d1de364181734c2e58d33e0534c33402d2bce2c0c10a53b65"],["expiration","1785676949"]],"content":"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","sig":"77927d477d07993c9ccf912e488b3384d69aba61b70f13c85cfbfffc2cb3fab7d384ddc4b377470bef2a93ad4635b1ebb74d05dc0c6f3f21aa15d4b6385ace43"}
|
||||
{"kind":22668,"id":"4d59c8963f927fa9ea3c116a710049275033c52fe5eee1c2d970b1e55a021f34","pubkey":"146c70d40e1f4f96528309629258f8dc97e9a61aa53e54e13b999ba5d2276968","created_at":1785676829,"tags":[["x","3h4b5840o6s3o6aq23294k3l3u32544u3s7266"]],"content":"{\"peerId\":\"9IVDCiG4hlib9t5iG017\"}","sig":"7a569489f112258890c563d4924c4f7344537aef198f64a7cc0b9f32b96ec7306ea98cfe1fff4fa6ac2a162ffa4944ba3699cf2751bea61b765ab32b90122651"}
|
||||
{"kind":21059,"id":"5e5b504bc37e7a30f376cf1ecc6884e31163dae41f5ca3af1c7d5462e972dddb","pubkey":"fd5a12fdce164794145f3a5c4b35d798def92f98242ff4609673de9214f2895e","created_at":1785676829,"tags":[["p","1ec71c39a30373cbb10e91d6efa6ef1e9dad0756d610c1a4e337df016eeaaff8"],["expiration","1785676948"]],"content":"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","sig":"dd1e19594cf2758b966c27f773e20c5f1ce5127e7a6c046f40df32587a6294e23ce91cbcf789f25ce93ca17408ba16d17a82449d734c80d328ec53f096047e74"}
|
||||
{"kind":5,"id":"782cd31915d712063037d3948ee8e7aabfd7560dd332227d502ef641cdca1ce6","pubkey":"b454400c0f61af322680e46825a10c69aaa4226be2f474dc21fab2c7271d4ddd","created_at":1785676829,"tags":[["e","9aa8c8f7a20f62091f9b3ba3ac8262c9c2bc1a40d87ad1c75f0683c0e757a983"]],"content":"","sig":"ca9858bbbd3a7d46a9930122981ad8402cb302dd4a1802df2270c115c12971fff8cbe9b740898d5f618f3f0a9ddcf79ff8f3fbfbefebd21d60670ce15982bcf5"}
|
||||
{"kind":21059,"id":"3aed713425ab4a0459176d4ba589876e6a313d879fad18152a11347c22c1114a","pubkey":"842130f8fe9ce8aac0eb1e1f310de93b32e6968a5553dfd63eb5d8eb7874e0c3","created_at":1785676829,"tags":[["p","1ec71c39a30373cbb10e91d6efa6ef1e9dad0756d610c1a4e337df016eeaaff8"],["expiration","1785676949"]],"content":"AjqHhTAI5+bnCf5r+Fi/fQ80nuj3INZlwNBcn/rRXMh2A5/hdbHkBPlUFaGmYVSPea2wQbBkjQ3VNcb95ffwAZoJ+e+5Zc9L7PBvnC/EymZQFWBmaYbX/RKQjK8A9LmWnpAKBqTts5BQCPBmgoDVS5docr/fYLjSxNQQS1/+2dwrGxancBR7a3T9tcjeRzKPvbmvdRMfR8Z+g1KNu56Ok2fBk3I3bZUN2ZFpmdzPFcumxDTBdhRAHMEQ2DhpUZgXDE/rfG1qxM63mJCxYv0a9DZsgamy9/+PjUXQQ76gMJ/NYaKHGZK5gaz/geP66ly+aq7hfp75pbledOVL5r5Z2LqAU52vrEX/DXDWjda++kB6XUmECbtXstL1vwUi2bvZJPLCTpyXGqh7qOMXuWe7PFwN4vEUzycLZljZw9tYJ3Kgu0kp0khTW20ZSUa3bAQgfGm+GzKCMcAfPnaQMJfDimfVfTlnsLZ0TFNfwLaCdoGixh0CmyuW0Mn9p1rFrPWk1DcU3+20zwNXD793LlHpe3d1yW4xYgAdX7GTWWBCo5tgA6QVg4jeRHv17Mufv8fw7yLc9BkbsDspedYlzLVHYTe+h1jPT8eqw1VSMdGKniHJ0/DmTW4nedLnD29RhZcwgRZxxMqkf3HtIoHaVhVIEDKZg+hO+U2OuSZfAN3DzvHi3enMC62iq27ltJERiR1WeOitUVpidAB5X++jZFHTPjrjdTnfiORKeRoOq/2ClsKNfQH/f8DywLh42/WNubo6lworKvoxRaeQH81DU4LTZBjTNmNnIr97MV4aFizTWTv0kCR5xbr5aZTvTnAmvG9onX9FiudBM0GrMu6LpwWtEjhvOhSpaaCdfH+KPy5Qqs40IhGZBDJSFwvrX+K3lFt9drEB0L/ExbeOkUEVcrgUegwi4IvMwuATU4z+KFLngpqHrHSucyZMzOuead/QSb7pxydvSDdnsW9hhkKo/NPOVFj7SmvNLE3z87kph3HCdWwVUeliz3+QVYTDbg/y/7sOTHTAXt6yoqKaoC5SoCiO4cN23gFjWPOWiYK21wXSaGbvCZJYOACD+qFwdBe9fA+Zq5MO9Ec/O2HNUmd+YFc1MgkTGXENB7nbhCnMNuQxZ3E7ojkxo2EbW0vl8E4cSt2MdMrjWkkZukqXGjozJbupcsUC6AedKnyNxyKuudzn6dmgw1h7S0yNfpvLp/ti076Ll+dLfgpbXvn0Liiut2XrZW7djthVA9f3hEKUHPE/ZTECoewVG1I83TqyTiZ+Y1hrpLKTii2dfJanp2SRcnyCxPrL77dXzljrFV3B05AqZlF38xTjco0uGc+tfdqMZv37rgqwapLmdnmhdp4RCKbM5QNChM9MScXvwEqPXmMHs1iFRXLzILQA3cLZwMXD6aKJ9eHFonxiRG+RTBzI8z5bes6h0p2jGPOg6wae4ZXDdPH1+FFjjUwMWh5TNHZ1s20JV6yFsdB3bOTHuWE5Rjkk0LQ6kzgdvHk/mSnrmvWCFfFXmOH8nG5sWMkYlap9Exk2NIQonsU1e4wKo9Y99vghUIzknn6v7x2d0z1C/sAv5+qpnbDN8Z7hILrUOtEYUebef1SDRa0hboMK4PyBZ9bH8j3X4pyQaL1uRZ1J6msaFB9myWX0yeFla6hri602LEGecifPngzI9hbg0fbyrXZEgzb0xAqJvOcvr2tHNb3TUF8vdLmgoD8MUQFENUYmqXcW8n8iwiFpPJOAW2B+63oDklefqwVwbMvBDCTdeCsxE6F6PtKXi0jAKauEXYoLJtnZ+2EJy3jm5DV/7ZJ54r0gwwInLpHuDQTqBJvGr98VtPxOCzU/XedDnkzBNabqRaUV+bF0t+Ma8V2994gOxGuSufiQISiLqWJcwVNpdauGO/mEfIo/IZ4HgCbOE9H9Gc6T4oazL9/Dw0oA3ImjouvgZVHydv3PAcmqrHlQ774t/TJRATZmlDymqxnBKDC15v6xdyn4/5pFyXC2/ChlFLkg72ojP2Z2YGD7TCNLyQ2liwZQ1P7z2XS8IAlkqk8UiCeWjAiM8J7iDJJ8LuaP48JPchJAlGdX9PnO+8MjcyDPuPH5snn8zlACa86AlDj533vvc3ZtkWoExpXimft6iXd3baeg7Ci9YU5ez1FwByn1dJ5Cam4VP483c+Yq4h2DluUBZgWolNDQsQUPdP1pWnlfzHgyX1An1zsK7De6CX2U4nHkvgO7XfmzQxUbsja0AAEsTcVD1S7xPINBr+Rpts0Lo3V0/0pxVe6C+UfAd4riph0BXcS/JsR754r+pRX6ybfYZ70B44Cmo0/kOpk9GL3+RP8iv2Z0veQG413dZz/3s7QW+7SST7m2V53gFFlTENigxb5o5+qgslxsOCp50mPvGANCuHCZoXregk3DgpxmUptQ5k11W/Qr/MaFdQKFGHTlVfGEw7vl2KwOqHfyuiy7M9biQdb8coullwmh5irtBnHpGna2LKM42qbkEhgpvDhDh/88gZA26TE9j2tsOVltDgbFMyMoms4hIaHCFcnDDHjcwcnLR9hyT7jFUV2zifFO/gNtS3Rptik5kVvmTQ2HN24ac6z50guuIf4oH4Nks7r/nP4PHrcODPf5/4LFdujbupCzd+gYRAUIWIYwnXOC4BWthbz12njTQpezB3Uu1PzGYU+mQzVq/vEXlEtX2doiVX7ql1X0geLhI/nPy4alK8AbzV4/emGsCcKfMIwDt2QCI/fuxsZZdkN71+Vyvon3icVVWNZong9A29pYU6JOhPBSkKIpoMiwWQOOx54/QFuyo1LCkbBAbtxD6cesxRotbujuR+hNRf6pMUrWR8eaxDi4E/RJe1xIyCuiTWu9N9xKq/hJQ78dsung3YR7ynjzS26xWteOc4IH8LT0/DPx9oiP3eZE42om7SvfGKbL9gxnIPvIsk9nSjy4DS7BHdVa8UmX+n/O1GGxGEje99h3viGBAQKXDkHGlU9il+JRS/r6Th8RoM7X74+knZXKJHCRm7GbSCeogJzrXuqoWzEnCNESnzNI4WZfZ8XnLadQLeYJieeKnfXDBt/x/gxXH0MblFt07oo4vabKOJlHmHA89iezM932hJPUpI7FnuPRyPzIzrMri8ErAX/kUZ1c4dLpxXG1OinMYExTtog+IJgqTeXXz2K+lYXyOJclKtJHEIxN99BaYRcSGBUXjE2jUW6YJwjE3V754bIF0bhqkpfc9Jy7dMUjfY8i0Urhbh4B0E46GIi7kmKJxktFgPuXbPKIu3hVUWZJJjz1Pge6en3H+Rnc6ohc1unJcViQGLV0Kwjx/W1V7lDVqhA1y7cMuFP+uVmSDzatKrLaI0fqW1vducNdLmZ9MoSb4xgl9CdVuWzjY8V9HXrc3NuzvO89gwYRY5vLAaTnIpGyhFwHTE0O7fop2T38lQqxcVVdUlOLL61Z0Mxlsd3XF4TJ7B/WQksgbf789xOEORLqM96pKTvMJBrBtYdrdCKpJKDPRgQOSmZldK0=","sig":"aee0be687ade030557e86ba811b5d03c590fe6cd2a62085015cbb4391960b6a24fd0d0caffc5ebc5ba765006c3d98a5c847b15bd81ef38617d491a6a11cb6705"}
|
||||
{"kind":5,"id":"137d08e7ffb7fe1cb7bc8b2be596e6b65d5699f7cd64f13a23bf390f70807c90","pubkey":"29d1d9e11edbdbf04538d90d053b7b2d32c1c253fc3df1893c11b68826630609","created_at":1785676829,"tags":[["e","810bde802c36ad6d9aa0e017ac0f8bbd6e66ad80df5b9419c0313be8054f2d48"],["e","9d28fd6286648d315a0c47db82e20b67e985a54f10eef09745d5cf0241b85e28"]],"content":"","sig":"bc21735717ac3f284a372f2bc72ca9d15badca8f7fd8016ee89015ec19d9a212f528fce8b16a98b62cb5108f86b5ae2698b0049eca59f70b710eecc303765544"}
|
||||
{"kind":21059,"id":"16bdf72f80f5945fb5e08e5f50701615cdf8d9f016c8f48a6f8f22993da33080","pubkey":"7255fdb4025a1afe269132658221bc6e698108cf7b43571e929cfaa712063ebd","created_at":1785676829,"tags":[["p","1ec71c39a30373cbb10e91d6efa6ef1e9dad0756d610c1a4e337df016eeaaff8"],["expiration","1785676949"]],"content":"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","sig":"e113e7856c06159dc5cedb6262892bc5014d0cb5fb21e749eb23509413548dc8df95cda93e1dc8833a3987e5227bf51c578fc990f3689e7c0fef9da250230350"}
|
||||
{"kind":21059,"id":"9aa8c8f7a20f62091f9b3ba3ac8262c9c2bc1a40d87ad1c75f0683c0e757a983","pubkey":"8f3f5b88fc7641fc8cba3f85d31023c07562c05290bd8dcda72efbf444f69926","created_at":1785676829,"tags":[["p","de2474ebae76da5fc0dbbfde5128465ece9adb6174dc5210014f277e2c54a093"],["expiration","1785676948"]],"content":"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","sig":"857148777b63e5e0ee1eeb98b12539466cbcd35b21514484fad507c6230b9e71d3d565af406cd8b97b0966f7e83bb212ae21eaf8a57162b2f47bcac7c293e427"}
|
||||
{"kind":24242,"id":"443bf61bd52ead74bbf7f3e0d147845f0ed9edf680334029c1252c41a58caa4f","pubkey":"0214d7edd25fe949a9978de3b36f90f7a4ec432dc9753087044be638e7f2d3a8","created_at":1785676829,"tags":[["r","2145c86a56b377b435b1a17888dd93707e0991ed524c613f9ba73541c94e14f0"],["t","P"]],"content":"{\"t\": \"P\", \"d\": \"VeNHJfdrPLMeFtNrqqVREOclr1Pj8K8tan/m+4DPgHeYoq1KI2ryYNcOurYaDy13Cq5YEJGD4EZtB0CxAl4Su48pTzXdmuSs1IHm0lBYtkHuxEhUZigIGi9aNYY=\"}","sig":"c350662d3c997e8238be51564efb0172005507fe2e73f882bae32108fa272d6c4fa2edc55866d899b01ec3944578133092220e5451cbad4d5ac171827ab1744c"}
|
||||
{"kind":5,"id":"22f5949ec55c1ed8ce97c6d7d2bac71992efccff6b5eec37d4329c5f44b79f4a","pubkey":"a104303328d41ca62add479f54d19467aaf0969ce09024e0d46dd577706c9bae","created_at":1785676829,"tags":[["e","958d7a6b0092f0d0e331b2dbb7f197504de75ba442b7fea806be2098c7c2eb2a"]],"content":"","sig":"dce8d65f9939f32c404db12b3ac29ebf01d28bea8a58346a8d886cd174e799e46d945c97d96bdc0ba4345c5ca44b6e9827cede44ac10efb931bb3f831e8935d2"}
|
||||
{"kind":22455,"id":"173ac3706d5caf2f883cede799f54e93a1b89dbb4cafa1885703562208a2350a","pubkey":"146c70d40e1f4f96528309629258f8dc97e9a61aa53e54e13b999ba5d2276968","created_at":1785676829,"tags":[["x","i10614r6s6x481r3l6875fg1631u55a564j"]],"content":"{\"peerId\":\"9IVDCiG4hlib9t5iG017\",\"offer\":{\"type\":\"offer\",\"sdp\":\"214,198,243,224,5,154,106,180,224,102,15,15,79,30,115,171$ff2wqB0tK5EY9LkoZ8yHi/oyz+MfFpi/6sLjRP++zumM+33SIHLHt5lk9bEZeCZGnWaJm/xGeBLkAjrIvGLeCU4T5FZ3vuFvQUWJmo2MmdbCPISD6scgXXpVx854ExqWcJjRrTa6eFY1/2bhJZ1/9gxjPZ+gX4NoXcQpk5FbTFI9scY+tokJCGS/VWIt9on3dKA1ABXvfHUaV49hlTi2VmR1/RZsz6UEzSdz4RJ1erFZer0R12CGhJ5QAg8YTAcfbFe7D1gKQPb2RnFUMNyBEHbJNys9jPnq5sF3QoA8JnxgSZgDs0nttXfmuTtywGqY9zvCNp3kV/n0BatZUlAyzhcPgAqlkA+I6L82hT2vY6Z2uUJOYRi/yiAswm7BU8PaV5vkgViODnqANVnnOHHyDpRrMhWEKmFuenxp5cBs505WkauYI5gSIuAJCE2aWhcQs1jX5uGMU6UsqJkUv83FdEZ6Syi4EEVxT9waIZmBuNE6XOKn2WG7DhY56FZoquzH9b+Nh1yeJiYkBldP5AMQhmzUHK0oP0iF1EfmxW8D6sJEWYhR+3mNkOF+cITYdVbwotN6Ijpitj07yP7/QtzeaWENsEJ4hEz9vODuSkgiFVNX8bwSjwHoreD6O/71DSsHve5WUe8Tld9K4xMv7+Qwe1pnbLea3F8qxEfBAnJVVpVXUZ1u97NuO4bsQ1TduEH+ie2cFE3MKZq16IIz3+8+fjMa0DO0UrxaBa4dX1au6Yxgd0EV42gCEu6uGqSnf6VzTjBwMoGdQsDK4PswZ8M6052ik7MBBYbq18VMm0eqBfhN19R2IFB6s9k7P20gzQYd+r4no4ynERuOyJrGKD9RrSJ8L9Ta8n+5ssFcHOFrFAehxoD82XWUtv2tviwLvjKUlU0ocvbiHAOssJ60cFha0Bt+zJqlPjhjH93MciW6Sk3FeaFsFZteilwQI1sn0f3rmk5p8xXFG7An21gswdcCEXnssKxLi5dQ5CsBD3+qz7sNzxHALi2KnVWZbqhi347XZ8HMcXeGE3HM+bKkKJ/RkJ6c0ofhqAwp5ign3Njtey6hLkFKz6sF9Oh6x6e80ec58nAsIQxRApzLgojJ5lUKVCb7dyhtJpkeGrCNVuVqiwe5dttQVNeWk8HHsbBznLF65OKy7tJ9CjVRibeybSLpNNZPDyFk2H4UGC1jSbwRWQM9kymWRruuIGrUdLLtvHtbakA+RVDItKHh+tuchA3ghtsBw+0x1YTzNg/uewokU6Ts6g1xcYn34PKCuoEbAm7B0xijw8HRaUA7/1lSb6XupDcddAMsdXDR\"}}","sig":"b4df17fe73796261f380dbf59cd4c253691f7df7c5ed02ea7ce17ff08ece4e1244ae692d384577c3d5a4b3a52ed1823f4e21a3b709fb8228966e01fd9cd96446"}
|
||||
{"kind":22795,"id":"51840075a161979e0960dee2cf985dcff29ce8024542224f1e8d270f05d266dc","pubkey":"146c70d40e1f4f96528309629258f8dc97e9a61aa53e54e13b999ba5d2276968","created_at":1785676829,"tags":[["x","2t6r5t3g2w4ke3c5q5fe155b4733m3m4d204h"]],"content":"{\"peerId\":\"9IVDCiG4hlib9t5iG017\",\"offer\":{\"type\":\"offer\",\"sdp\":\"223,148,124,74,154,14,67,150,164,85,250,22,207,70,113,66$GQ31axJJQOIow+lfqV1YKLNxUh+V1rAioseBNHgVEhYONSeICwYKTUGHaVGQjflxRs1atY42oGidpCqpxjDXdpUgIQb3/EzXDCEydaqqyLy5l3m25dy5k7ufZFX15VcXR8wcDi0RYRFN/iGE9mSHsLV5w6lQqv3jpTsKAeFYqwCkvzh5WnUwM8PvmR+PYFTXbb3HXYwJp76QGR3POTyJxvijjtjkP0Or3V1JrPLxMDJIeNlNjWi4r5CzFzO79ymTE2/5b2IBlN5FaZbTYxRvICaKVA42gztpDDUFUaOfsS74xCun+wQfnwf4cefm7h8HochY45m/43oZ+B69kHmQlXdzRDtxPyW4Nlhakp4+fpvMuaO+AbAjLuJeKxOXbBdheXjQ8WBJyJU6xXgDmUy/x8cSJtMfshnAR86ENlKSe5TNR4ZGEkDGt8ZibqtHzr3U0lUFhfCNTnqdGhPKPFCr89W6ifbWkY6Ap+8DsiqzBZdS9Jm/rj6dBpADWXu1eCH95TNRUhA344wAGCdLITq+5HFEG3U1+F9e9Kv9anp+QXFRo1DSs9sBdKIzH2GOoYgvv/amzP0t/ujF0jVC50YbJ+vcD2Mk738T/RoSw6fenLHR+vuSo5GEQZKfIqsDnLol9MuHwilistA/EiTl+g/5oVoZfFz9Ka+paRsyE3jVx/r9q0/XqGqCIVGPuq8Zq8Q9upXxHZJ6GDWWDnkbW/Jdh7lzkPEgPk8A6mhv6tKVo9yKPGQvcRC6ir65pvnpr8LkcmGD0ZcmyUJZgcS7QYtHdFr5nEm97uOkDEcjWNsEY4BGuZLquE5YXA/FEKT9OfF9IGANGeFCejUxYC6wmfBgNKPHn4y8dwF4O1VS2dyzvIEMeQOWZfLX18Rfzwer2DUqhy9Vug0UlH85Zg7BO3xsd7HckWkGhaQe9/OoYc/J7qu7kgGGaJEot4tkVx1jqodqfQ8231pFSFYAPzqO7ARdk5Iah+4o5leT7/3etL+NGI0P5NRngirLDwDf3usWIoP8rZHH3X80VvUdSaXfNNVIfGtVtVEoldpJdLMgBjjrZN4bSfw0Vrxq8ARXPF1XhziTKhhUknepY9kinMynYwebwmr9jxFJhFOvrh40Pm1SNAEegoMxrBoz/BfSUuFlo4ZUOdT4H29npvGYrQQ6icPfu3ksOI/a1jEzIlf3Mi97gW3q+rVj4vNVx3PoqOi6Ndbp/vSqa3cMNJXXPfTQ0V8w+4SW/PwyVqnhIl01kqxjNdtdis4EMQ4ceGJ3MDbgCdLA6lG6tGvogy4V9/esn71GfC/fD1Wz\"}}","sig":"88644bb037cd5b75c311efc06f45f39c6e8100615abcc08ed0f285ec9e282733a88838369e318af75e2687b7bdd6d0904a4bb90fc2f16027755d3d060f5e30e7"}
|
||||
{"kind":38501,"id":"bc1428364c22cadcdda9e97f47a30dd3da07d32bef447c987e007e6cf33b7cbb","pubkey":"8b46fa734a7230497197cb033e6f10e55fa400e90447cfe5651c9ad30a9f7b4a","created_at":1785676829,"tags":[["d","btf-descriptor-2"]],"content":"{\"created\":1785676829,\"enc\":\"97f504ab5a031b93d29a813de02ccbec80f0345b11ade65b66cc0f89c8470920\",\"meeting_node\":\"90.156.222.107:8434\",\"pubkey\":\"8b46fa734a7230497197cb033e6f10e55fa400e90447cfe5651c9ad30a9f7b4a\",\"sig\":\"eb1094bc2e5aa1c3d49bb21f9ccd24b96a8066e1efe7400d649c97a03c7e599b1f5c820dd700a3502b675c52513bd0f2bea34a4dc41fd4c101dc621e4971378c\",\"v\":2}","sig":"2053e323b44d3fdff3f956edf9a61ceb3651ee517eea4bf11adbe7e4438fe63234aa7304ed3cf5e13455ef6037576e89c6587a771e514540624b2f4157531e27"}
|
||||
{"kind":20001,"id":"6c2fac4c1a3d24f3c83db08fd810cbdb92e47b48b9b0bb3e54ff7081882250f5","pubkey":"bf5ceea34cb45bd0d4903e83c62a49ba1c80d589934d83fd4b2c616aa7c3df57","created_at":1785676829,"tags":[["g","u3"]],"content":"","sig":"ad150f48ecf1ccfb096cdcde24a846a8396d1f8586e238a778916836c78a56752070c2833ec655350d9241cabb4785dc4e48501dba5ee1b35ee442b80f677de5"}
|
||||
{"kind":7,"id":"c138c6daa6626d75a2621f1c15729f63abbc682773bbfb278412b6545131ac5f","pubkey":"e4146d1d7fb2f7f6e6b3c799eaeaba6f7446fd28ccea2592671cb239a13f4d81","created_at":1785676829,"tags":[["e","f148576d2a0f9754d8006ea10f31531c600ca6abbbb64f92b13146ab32316e12"],["p","c79200d36c345e41d46c135b30077b2f15d43cb286069f1e4f2e65c09162a900"]],"content":"+","sig":"f02914b8b9345f45f4ee7cbdf7e058e3a15c976436df11b71ebbbb7f62d08bfbb8398cfbd202095bf9dd3d4bee6ad597d9289d12c8bf32a8b57323666ccf5028"}
|
||||
{"kind":5,"id":"05a69cae2f6f03f85d49ce912ffb234405ebd40b4619afd0f48e79f4c9afaf8a","pubkey":"3b6b4b29eb5b65aedb5d5291ed382d64dd62c555911380bd0dd27f160446a025","created_at":1785676828,"tags":[["e","64b710cf656b37c7d2df8935752af4914b88f8bb1ce3536c1315da43b72b6820"]],"content":"","sig":"f62372888a6e0ecc9b865ea00c18425f46984212a929441def9ca841e7216f95e4ceaa6eb39e25dc8a533d3455dbc1191450c053e894cd7a6a752b3026694d86"}
|
||||
{"kind":22850,"id":"d502724e18c11af192ee65a8798828a5839de91251fb80dde196e09751600622","pubkey":"972698b75bab763abf02e914c05ab10ba92946d949e44994914bc8ec0f0c8356","created_at":1785676828,"tags":[["x","154a6xc4s1134333k6j1w3i5z2u4x2g27363w6q"]],"content":"{\"peerId\":\"E4BBrrzMaIncSQjB5BIY\"}","sig":"ce077337ae276256eb927f006fe5ebd9062272852330909b8e372176ac17e9cde6c75f95a91a8a31971fd50e39d3f09bb78a8469444feaf934e220ffe295b1cf"}
|
||||
{"kind":21059,"id":"c70dc8831fdbe3c9e881ec501b0164baad462fb4cdf966b232771faa15faf8d1","pubkey":"f6618de562d05fc1544e473cd2de7d19172886a84413f09be3580091b0c6166c","created_at":1785676828,"tags":[["p","d71691e02c10d3564530a86b51598532eef5f3d62317ff93cea2c3b9c4d4526a"],["expiration","1785676949"]],"content":"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","sig":"15cb4aa077947993d94481c3ec275fb4905a66a0b0309ed2962170c104900322ef9cebdfb10c28f55e91d2ea1c5ab66682d570f8146db4b1e35ce71eb465ba15"}
|
||||
{"kind":5,"id":"4465287c1593ab85700231ff2bdb75b84cdcd7f1110333bb4d615fad2d73b147","pubkey":"fde8ca9b4a9d1f5d2ed8b82ea13766c37bdbf6cb50bd272d642eaeacc713563d","created_at":1785676828,"tags":[["e","5982eb4b4dc892cdaeb1a37d3329c3b11633be2b19401d1e0f2881309be0616b"],["e","64b710cf656b37c7d2df8935752af4914b88f8bb1ce3536c1315da43b72b6820"]],"content":"","sig":"806cc8d8fb44a1b2fddc62950e525f42bcc3dd184ded730235b0c4bc36c13017e86a512f98a3d005c20affd8a546fcdb99ec3c90e4550a47e1dc2034cd86cb16"}
|
||||
{"kind":21059,"id":"638a053daeb7e0a7a0f36a2e2b1c0e2e36d25c58142139f99f706244fc7c09d8","pubkey":"1a54ab43a4bdcf983de90f5bcb7ec25cb61b7cee8a5a719faa7c7f0abdbbc88b","created_at":1785676828,"tags":[["p","92e744f3d9e8ca5888da31ac871ef9eed2a0b198ba08f417937cbff3030b0000"],["expiration","1785676948"]],"content":"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","sig":"134ad847b73bdec6eb45c66e2971175bedd00fb7a6c1a6c708beaa65fe8d4089fdb58e3c347631cb298e209df1a5183a0b84513e271bb8fd1f7a20696da68c66"}
|
||||
{"kind":22668,"id":"ddc1eb28e2625a90f93416b40326661d5f5b627056519d83e58625ea117a5a67","pubkey":"645d864f8e4df2e7961010c726ca1dfee79c1f849e89981f38c67954ab27ab44","created_at":1785676828,"tags":[["x","3h4b5840o6s3o6aq23294k3l3u32544u3s7266"]],"content":"{\"peerId\":\"XLa4RppouLPlwZlPEN1L\"}","sig":"9bf8af313f3c5596cb8f4d0696b8d72cd268af14bfaa38b831caafe1248eb58a40af81fb3a43fadd6491b086f811f18fa6c4422548ec58c37fd3d157f4bf8eb3"}
|
||||
{"kind":5,"id":"0b34123c6c388de6d35d821348dcc9651adb2eec495f020f9bf29e32a9ee5282","pubkey":"a6cd35843a1471debb1b174b5bab472d9f5a2e2391e92207c2279468c3e9ac9d","created_at":1785676828,"tags":[["e","8290a6025d0f18c48f30f52570181ff53bb29b44cb2af6234857b7792650cc17"]],"content":"","sig":"a00555524925631aa1e50be3f5bb87518191259643f46806d55e13a5c791a3f073eb82e8e442b0979f269eaf323c846b8d3e0bb6185f622c1f734eeb444c4216"}
|
||||
{"kind":5,"id":"290ae3e79db0ee20be75bb4368fcd1ca3e4e97fce13390c135f5a00e24daab6d","pubkey":"f562b3ec661872d7e53a9babc2e75aefcc3d1d658aa32070d7a6e3948dab2af2","created_at":1785676828,"tags":[["e","c75edbfe2657b06d905d775d476618bc97a68398447ed36b5b53e381ff34b99b"]],"content":"","sig":"ad8cb04b8a8d861e079d122c5e459fb9d505a4e024fca20d606df2cb0cd5a5701fff566d0b52e22d978e76eb2bfa8b115a207a1de074dbb307bb8b8c1b0bb614"}
|
||||
{"kind":5,"id":"da568c14b08dd42c0455f01d8239aade88c77ce1994de16260dd198b308a3421","pubkey":"b454400c0f61af322680e46825a10c69aaa4226be2f474dc21fab2c7271d4ddd","created_at":1785676828,"tags":[["e","098b11ac3a658a5f260afe741b1e702b6ceb795073d0fd67f2b39893c9f5f1a5"]],"content":"","sig":"860316ca6bfbf5032c9086ae56d89b65085e4adb6c083f0f2a5b369cdf4951673b4a4dbd565190b071d12681f11e55495b3a354a41b85a19f68c064d3f010bc8"}
|
||||
{"kind":22668,"id":"2e19b89f9daadb9436e59f893fbe4cfb06d233052bb1aa2e8e2a5f2ded14bd1a","pubkey":"983451ee5aa44cfd054418a4b4d61389f6cacfe5bc8ad63f247040506a7bc8f1","created_at":1785676828,"tags":[["x","3h4b5840o6s3o6aq23294k3l3u32544u3s7266"]],"content":"{\"peerId\":\"MOfdN8BFCzSXK2ClbLZp\"}","sig":"7a7fa69ff865ca2548336fe3bb0c8fc72033822efc524f28f0056654fd8f70ddf0c4d0bf6266bcea2d320204fd7e87b9304ebfddbbb46dd528816e7a5adbd93d"}
|
||||
{"kind":21059,"id":"c76184eeacfdd807619fc4cfea4d898e87cd44a25b4f534f22f4de068974a659","pubkey":"756284430945b4e12636df19fb8892364d6b685f15724c3cd4cf8089aebce8e8","created_at":1785676828,"tags":[["p","c3d2d513091f404497181534e7965d2b80da38f82ac76bdc8faa2ee9b20b7fe8"],["expiration","1785676948"]],"content":"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","sig":"8a7c9e47f5e301802cb6eddf0c11109a161c7873aebfc4bdfb6660dd4da3d772d4c9f13ed6708a6726770a19a931b0d912ad7ef9b2289e1471e0503b64a9de9c"}
|
||||
{"kind":22734,"id":"c4eb84f16a0b91da08b80674809ff770cf2fbbbea535222f71a6f70b1afaae2f","pubkey":"62131eedf03e285f05e7327cd868d6cf04567658e72f09f6a027a2cb526491b2","created_at":1785676828,"tags":[["x","2n2c211h5a65204bmik1t4y663e1k2jq1j2w"]],"content":"{\"peerId\":\"5JyB3m4D09Af6swaeL6g\"}","sig":"b025b0f3d0f2d5de0256a1401816a8393a3109bdb2446b4a4986fde228438a1837a54a3b0d9debda4528c9e840e6acd458daa7d7e88d45c735ebe0149868160d"}
|
||||
{"kind":21059,"id":"f8bb284d3b89bf6edc85ac8157f4fe146b1fe1201164a094e85dfdd6bc9004e5","pubkey":"8a67ab6ff23ea573d894131bbee2f3b49dddd2cbbe9c532b0ea8bab5dde6c27e","created_at":1785676828,"tags":[["p","2b794b141e7490a4f53e23d41286cecdecdc1bba9aac19dc92ddc3984d361992"],["expiration","1785676948"]],"content":"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","sig":"726a670d5ca1bd6ce671f3c34ec0f4102cf8a9253380154b0621849290fe856b805fb69b772e55cee187879f4a4759e044e679c03455e513764ec7dbc50bdcf5"}
|
||||
{"kind":22734,"id":"69a3ed5c758ed45a82812314ef3dac047107069f56f1f938dc6e26a0d87ea86e","pubkey":"fe577acc08542c36add5fd831b6ca9e248d98f2a24f9648ec71f42947e289710","created_at":1785676828,"tags":[["x","2n2c211h5a65204bmik1t4y663e1k2jq1j2w"]],"content":"{\"peerId\":\"FjdIMX0nehvvfKeE8uS3\"}","sig":"8c52eb4118de1f91350941bd08b6953d6681afce8158c4fdf2da1addf2e15e07454a671bfb8b5600bccb4544380b3f2ff49161d22330a1138943781392a1ff75"}
|
||||
{"kind":38501,"id":"8bb6cd8e927c497c1d0d43380fae119b3e1de4bbed9df532ca8c85b956508b14","pubkey":"be43349f0292354b71e5857cd3ef5577e4d8882b50d5853b8d0d2e6f33cb9b17","created_at":1785676828,"tags":[["d","btf-descriptor-2"]],"content":"{\"created\":1785676828,\"enc\":\"ae5076051e63594c2bbaca4fbd1dfdeb661276f7bfc325f7b6e6e227068e6248\",\"meeting_node\":\"90.156.222.107:8434\",\"pubkey\":\"be43349f0292354b71e5857cd3ef5577e4d8882b50d5853b8d0d2e6f33cb9b17\",\"sig\":\"9199cc8116a79d3de74e28e1171a5f88f8ba0d3ee58fd620a9bc06b63652f85b9b03e583b4a3f5960a2d56a1f4d9c3eb2731def42d75bd28ee6ed7c65609b4a1\",\"v\":2}","sig":"de12e3a0b7ca656aad163076e2f32e5de2878a55b163e7ddad075e6e8ae9d98d4aac1502bb76f69c03086d4e7350f5d32686dba1295788ceb9dfd4049cc657f2"}
|
||||
{"kind":24242,"id":"967ecb7f628c4c40e6142b01d1e4fcfc021af09ceffabdf3e6e5616acebbba13","pubkey":"a975b6d0b2376a560d115745432db9828936b586e85baab34b0faedc1ec69cc9","created_at":1785676828,"tags":[["r","5ae4bcc88c92069957e24564ee8f8f0bbc50aa0ec33740fa6df513c5b4261c58"],["t","P"]],"content":"{\"t\": \"P\", \"d\": \"i22abIUK979JGbf+XiW0SEkynRl3oeD+ub6fdvXs9e1HiuSYhHzExoBu9kIDplEXnBZLQ5GckxdvfPVMCI5wLRruGhCQ8FyJxZMN3BOlkS7ExKGTXSCX7ckXAro=\"}","sig":"9ae34fa8b69db93c5469d472d3fe3e357370412926cbbd161c1c65ddf8a01531b0cbd184f46531169d738dc97f9ad647a8ad0eb0b8f768bc1bd05b21e424e086"}
|
||||
{"kind":10011,"id":"9fc9a8ddbcea381b42dc97807b9eda3e22ef405d389804ad1ed86e2c72f39534","pubkey":"5de310432a95a13ba1905b5c78b511b931fa7efa86bea15057ebe16424cb9273","created_at":1785676828,"tags":[["t","relay-monitor"]],"content":"[relay-monitor] health check at 2026-08-02T13:20:28.031870+00:00","sig":"aa3d24c702a8172c6a28e59ab84ef4e831c7ebe2153f19dea71f92cdb8d4c35495669bc5eb80df2c9c7eea273d919fbce1e26fc226ab22cd4cfa202aae6e0aef"}
|
||||
{"kind":5,"id":"a9a5a2840cdedd585ef53eb3fb086119b09d6ec97614a19e7014edc8e9fbfdd8","pubkey":"abb85588adc1f9fc70c07c2d6119c7ea8483e05674d85e89fd12fe26f37d7b80","created_at":1785676828,"tags":[["e","6baaf169c5a412c48bc05796ae31420fbf0abf7f4425030a02a5b5fb6e89095f"],["p","abb85588adc1f9fc70c07c2d6119c7ea8483e05674d85e89fd12fe26f37d7b80"],["k","7"],["client","Amethyst"]],"content":"","sig":"49e4211186e0ba933c513078fad6bc0e40c496573adef997be03e343ceff2dc309616a22f44b110ae2d7ce840f969140ac83dd764d4afb0c7e52fcd47442aeeb"}
|
||||
{"kind":24133,"id":"65468cf8859c2651655aef77fc73e162475671a1b9fe78507a75e8e1b0fce9c7","pubkey":"adc534e19063daed4a5fcffafcabac5c69ea92781fb870b800ada248494388e8","created_at":1785676827,"tags":[["p","8bf629b3d519a0f8a8390137a445c0eb2f5f2b4a8ed71151de898051e8006f13"]],"content":"AnvGOKiC2qxlzPRhokNkl7/Mv18NnRtNUDK3VpuOS8rGYCpUPhpICdZpq+OUZWQ12gFqaWNWEinqLyR8FXRCGKxeJ5iArhWFMF2+IpFe4mCj3Kg/bdu02V3waBzg0T4rAOaRWqsWQBSUz8ENTaeJUUhAyx11INFOWvh4MEh4ablqPY1ONZrMlfOrK5h/rqNQ0b9zbbzoeocfSUKrblTU/TcAa7bm8EnCOGjkyvfkW0PHbIND12NZG/zOBmvQIUTOkCkC","sig":"2e56dfe53f064ddcd45d09ef9211fb7d685cec414fd75537504a023be2fb8ad13b7c2ff34117e1b467902ec7fb207bd5bf17f28f83569ecbbe724e484a560767"}
|
||||
{"kind":20001,"id":"828803cdb45f3fe3f1d3ad30cec52a0a608cd44aa575eb61e4781236d206dac6","pubkey":"e1ef740bbab4a0d7fa489084a5dc41bd3c829bfa80cacbd2c3fe104ef41b258c","created_at":1785676827,"tags":[["g","u2sh7"]],"content":"","sig":"e3b6b73b3d9583c71795ed5d9a73375cca25202a48f9083c6e2fd001951ab60fbdb03f30ae4958570dfb62999d8c776d5cbe6e3f0278591873ebabf0e260d40e"}
|
||||
{"kind":21059,"id":"add2aaee09d5b4616d2688c3c1acd0c093f8f3e609676adb8433e7a4802b3d80","pubkey":"362e1183392e4916b8c309fd22d11b54ff7f50fb31f775c4ed7cb6c6da4cb9c4","created_at":1785676827,"tags":[["p","904d65c28c1bc185277f9e60de40e9044650b0c59e2729a4458e3c4ab6ba4efc"],["expiration","1785676947"]],"content":"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","sig":"0b358a00881890d1170b455ad5f23800a8620026939af6e98fa1d12bf5ac052b57347ce0cb15acf46c2b800be9a1e4f4ea331ef3a6186920db69fc9c43c0172b"}
|
||||
{"kind":5,"id":"8cb0ebc4d6307a3df82ac8e660e4ef9e7988cea03fde286f21277ab17e67991f","pubkey":"0a4f177b087b133099e52e5b50456f0d4c832db60c0f35d3269a6a055f25522a","created_at":1785676827,"tags":[["e","ad604a106024742fe765459c43b7f45f2c7cc3123454d4d517d34c3c539686f4"]],"content":"","sig":"217950b519bd5343ca498e48b4b04637ce09ec405d211913d85201bdc76561d61b6628424ad33dfb607c0150fe63b5197230b66991ce011b8dea3734cba0b66b"}
|
||||
{"kind":21059,"id":"c3d841341e03f0f22b2e6e7cd0811954f7590ff69c785965c2afe1e91cc6558a","pubkey":"608696506aca54466d337ef6dccb9cc714dd94ca1f88e91939fabec7d3114024","created_at":1785676827,"tags":[["p","08e99116ad58c5aa5e6e7dc40668d5d7f2c080fc9fd697ec0aeb76880cf54bd9"],["expiration","1785676947"]],"content":"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","sig":"887844fc5f7ce096fe528ed0a1891992556d30ae6f3e9a06177ce638f2a0dc21433678ad30483ddef40584048986d2d0cc3090975b9c96e13d8ad163b5aafbff"}
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user