mirror of
https://github.com/bitvora/wot-relay.git
synced 2025-04-22 16:51:28 +00:00
Compare commits
107 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
929e6f8318 | ||
![]() |
9a74359210 | ||
![]() |
f90926d573 | ||
![]() |
b5519e2f74 | ||
![]() |
0b9ecaa6cc | ||
![]() |
89bef01c48 | ||
![]() |
972b62b823 | ||
![]() |
17209ceb2d | ||
![]() |
9bb573a73f | ||
![]() |
b181b2225e | ||
![]() |
853d522946 | ||
![]() |
a294071f9f | ||
![]() |
705a281d39 | ||
![]() |
d2a6801f15 | ||
![]() |
03a8f6e674 | ||
![]() |
ccb6af8714 | ||
![]() |
7f7b2c07f8 | ||
![]() |
c5e9843d41 | ||
![]() |
87b3889746 | ||
![]() |
7770b92e3d | ||
![]() |
6626ae768e | ||
![]() |
bc3653c9b5 | ||
![]() |
577e82e5bb | ||
![]() |
246ff19253 | ||
![]() |
1a536bc9f9 | ||
![]() |
1a21abee7f | ||
![]() |
ba4fa1d031 | ||
![]() |
deed7b7c2d | ||
![]() |
e76839077f | ||
![]() |
46ec59996e | ||
![]() |
3ceeaf77da | ||
![]() |
a2080cbb61 | ||
![]() |
7666d3e9f5 | ||
![]() |
644afa30d0 | ||
![]() |
7b71d98633 | ||
![]() |
8e5dc79f3b | ||
![]() |
38dd6fb13c | ||
![]() |
5ca37ff165 | ||
![]() |
a5bbfe6165 | ||
![]() |
809d87e283 | ||
![]() |
8ce120bcf2 | ||
![]() |
e5ec9d9e63 | ||
![]() |
ff3079cbb9 | ||
![]() |
eb25be49e2 | ||
![]() |
295e2f7f95 | ||
![]() |
7fc7fc2019 | ||
![]() |
1a1a643d49 | ||
![]() |
1758708e9a | ||
![]() |
c0093880c0 | ||
![]() |
a2b2ac9fd7 | ||
![]() |
2bf2945db5 | ||
![]() |
7f35c801b8 | ||
![]() |
0ce65fb549 | ||
![]() |
d291251887 | ||
![]() |
a43e1ff9f8 | ||
![]() |
372ccbe0c0 | ||
![]() |
1309979d1c | ||
![]() |
845f02b381 | ||
![]() |
57fb3885ad | ||
![]() |
26110bb059 | ||
![]() |
f5fa8fcafb | ||
![]() |
8a69e7e0af | ||
![]() |
71f71ee0a5 | ||
![]() |
aae474531f | ||
![]() |
aaa0047a74 | ||
![]() |
02fc217510 | ||
![]() |
1db8134648 | ||
![]() |
51d8a6e6f0 | ||
![]() |
11ab126d31 | ||
![]() |
95efd8247a | ||
![]() |
dc935b9565 | ||
![]() |
307967ad6e | ||
![]() |
7232b14a29 | ||
![]() |
6cef35e0f1 | ||
![]() |
cce891e477 | ||
![]() |
47f1b9422b | ||
![]() |
3c6f93cb33 | ||
![]() |
d5ee8a3291 | ||
![]() |
e99c5dd753 | ||
![]() |
bbabc0eb1a | ||
![]() |
7434ee12f1 | ||
![]() |
4d97bb361d | ||
![]() |
2bd132cf73 | ||
![]() |
20b0272ade | ||
![]() |
ed76ae568e | ||
![]() |
37a9e1c0cc | ||
![]() |
49bd213942 | ||
![]() |
b862a0c21c | ||
![]() |
9124cc3204 | ||
![]() |
84ec835dcb | ||
![]() |
06d673a190 | ||
![]() |
067849d1a1 | ||
![]() |
323a801130 | ||
![]() |
a4116a31f9 | ||
![]() |
434b3fb398 | ||
![]() |
10b2e071d6 | ||
![]() |
5193f93900 | ||
![]() |
059500b2e9 | ||
![]() |
c12335effb | ||
![]() |
5d27b71860 | ||
![]() |
af155c1f48 | ||
![]() |
2e7105fbdd | ||
![]() |
5cc3c33ed5 | ||
![]() |
49bf83bbab | ||
![]() |
2b4c335b59 | ||
![]() |
0740531c26 | ||
![]() |
7a59c4cb79 |
19
.env.example
19
.env.example
@ -1,17 +1,30 @@
|
||||
# Relay Metadata
|
||||
RELAY_NAME="utxo WoT relay"
|
||||
RELAY_PUBKEY="e2ccf7cf20403f3f2a4a55b328f0de3be38558a7d5f33632fdaaefc726c1c8eb" # not your npub!
|
||||
RELAY_PUBKEY="e2ccf7cf20403f3f2a4a55b328f0de3be38558a7d5f33632fdaaefc726c1c8eb" # the owner's hexkey, not npub. Convert npub to hex here: https://nostrcheck.me/converter/
|
||||
RELAY_DESCRIPTION="Only notes in utxo WoT"
|
||||
RELAY_URL="wss://wot.utxo.one"
|
||||
RELAY_ICON="https://nostr.build/i/53866b44135a27d624e99c6165cabd76ac8f72797209700acb189fce75021f47.jpg"
|
||||
RELAY_CONTACT="https://utxo.one"
|
||||
|
||||
# where we should store the database
|
||||
DB_PATH="db"
|
||||
|
||||
# where we should store the index.html and static files
|
||||
INDEX_PATH="templates/index.html"
|
||||
STATIC_PATH="templates/static"
|
||||
INDEX_PATH="/mnt/dev/bitvora/wot-relay/templates/index.html"
|
||||
STATIC_PATH="/mnt/dev/bitvora/wot-relay/templates/static/"
|
||||
|
||||
# relay behavior
|
||||
|
||||
# how often to refresh the relay's view of the WoT in HOURS
|
||||
REFRESH_INTERVAL_HOURS=1
|
||||
MINIMUM_FOLLOWERS=5
|
||||
|
||||
# archive all notes from everyone in your WoT from other relays
|
||||
ARCHIVAL_SYNC="FALSE"
|
||||
ARCHIVE_REACTIONS="FALSE" # optional, reactions take up a lot of space and compute
|
||||
|
||||
# optional, certain note kinds older than this many days will be deleted
|
||||
MAX_AGE_DAYS=365
|
||||
|
||||
# comma delimited list of pubkeys who follow bots and ruin the WoT
|
||||
IGNORE_FOLLOWS_LIST=""
|
36
.github/workflows/docker-build.yml
vendored
Normal file
36
.github/workflows/docker-build.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: Docker Build and Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
pull_request:
|
||||
branches: ["master"]
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile-optimized
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: |
|
||||
ghcr.io/${{ github.repository }}:latest
|
||||
ghcr.io/${{ github.repository }}:${{ github.sha }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
46
.github/workflows/release.yml
vendored
46
.github/workflows/release.yml
vendored
@ -1,46 +0,0 @@
|
||||
name: build relay for all platforms
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
make-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/create-release@latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: ${{ github.ref }}
|
||||
build-all-for-all:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- make-release
|
||||
strategy:
|
||||
matrix:
|
||||
goos: [linux, freebsd, darwin, windows]
|
||||
goarch: [amd64, arm64, riscv64]
|
||||
exclude:
|
||||
- goarch: arm64
|
||||
goos: windows
|
||||
- goarch: riscv64
|
||||
goos: windows
|
||||
- goarch: riscv64
|
||||
goos: darwin
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: wangyoucao577/go-release-action@v1.40
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goos: ${{ matrix.goos }}
|
||||
goarch: ${{ matrix.goarch }}
|
||||
overwrite: true
|
||||
md5sum: false
|
||||
sha256sum: false
|
||||
compress_assets: false
|
33
README.md
33
README.md
@ -13,6 +13,17 @@ Don't want to run the relay, just want to connect to some? Here are some availab
|
||||
- [wss://wot.girino.org](https://wot.girino.org)
|
||||
- [wss://relay.lnau.net](https://relay.lnau.net)
|
||||
- [wss://wot.siamstr.com](https://wot.siamstr.com)
|
||||
- [wss://relay.lexingtonbitcoin.org](https://relay.lexingtonbitcoin.org)
|
||||
- [wss://wot.azzamo.net](https://wot.azzamo.net)
|
||||
- [wss://wot.swarmstr.com](https://wot.swarmstr.com)
|
||||
- [wss://zap.watch](https://zap.watch)
|
||||
- [wss://satsage.xyz](https://satsage.xyz)
|
||||
- [wss://wons.calva.dev](https://wons.calva.dev)
|
||||
- [wss://wot.zacoos.com](https://wot.zacoos.com)
|
||||
- [wss://wot.shaving.kiwi](https://wot.shaving.kiwi)
|
||||
- [wss://wot.tealeaf.dev](https://wot.tealeaf.dev)
|
||||
- [wss://wot.nostr.net](https://wot.nostr.net)
|
||||
- [wss://relay.goodmorningbitcoin.com](https://relay.goodmorningbitcoin.com)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@ -44,12 +55,16 @@ Open the `.env` file and set the necessary environment variables. Example variab
|
||||
|
||||
```bash
|
||||
RELAY_NAME="YourRelayName"
|
||||
RELAY_PUBKEY="YourPublicKey"
|
||||
RELAY_PUBKEY="YourPublicKey" # the owner's hexkey, not npub. Convert npub to hex here: https://nostrcheck.me/converter/
|
||||
RELAY_DESCRIPTION="Your relay description"
|
||||
DB_PATH="/home/ubuntu/wot-relay/db" # any path you would like the database to be saved.
|
||||
INDEX_PATH="/home/ubuntu/wot-relay/templates/index.html" # path to the index.html file
|
||||
STATIC_PATH="/home/ubuntu/wot-relay/templates/static" # path to the static folder
|
||||
REFRESH_INTERVAL_HOURS=24 # interval in hours to refresh the web of trust
|
||||
MINIMUM_FOLLOWERS=3 #how many followers before they're allowed in the WoT
|
||||
ARCHIVAL_SYNC="FALSE" # set to TRUE to archive every note from every person in the WoT (not recommended)
|
||||
ARCHIVE_REACTIONS="FALSE" # set to TRUE to archive every reaction from every person in the WoT (not recommended)
|
||||
IGNORE_FOLLOWS_LIST="" # comma separated list of pubkeys who follow too many bots and ruin the WoT
|
||||
```
|
||||
|
||||
### 4. Build the project
|
||||
@ -57,12 +72,12 @@ REFRESH_INTERVAL_HOURS=24 # interval in hours to refresh the web of trust
|
||||
Run the following command to build the relay:
|
||||
|
||||
```bash
|
||||
go build
|
||||
go build -ldflags "-X main.version=$(git describe --tags --always)"
|
||||
```
|
||||
|
||||
### 5. Create a Systemd Service (optional)
|
||||
|
||||
To have the relay run as a service, create a systemd unit file. Here's an example:
|
||||
To have the relay run as a service, create a systemd unit file. Make sure to limit the memory usage to less than your system's total memory to prevent the relay from crashing the system.
|
||||
|
||||
1. Create the file:
|
||||
|
||||
@ -78,9 +93,10 @@ Description=WOT Relay Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/home/ubuntu/wot-relay/wot-relay #change this to your path
|
||||
WorkingDirectory=/home/ubuntu/wot-relay #change this to your path
|
||||
ExecStart=/home/ubuntu/wot-relay/wot-relay
|
||||
WorkingDirectory=/home/ubuntu/wot-relay
|
||||
Restart=always
|
||||
MemoryLimit=2G
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@ -129,6 +145,9 @@ server {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -174,8 +193,8 @@ To start the project using Docker Compose, follow these steps:
|
||||
```yaml
|
||||
volumes:
|
||||
- "./db:/app/db" # only change the left side before the colon
|
||||
- "./templates/index.html:/app/templates/index.html" # only change the left side before the colon
|
||||
- "./templates/static:/app/templates/static" # only change the left side before the colon
|
||||
- "./templates/index.html:${INDEX_PATH}" # only change the left side before the colon
|
||||
- "./templates/static:${INDEX_PATH}" # only change the left side before the colon
|
||||
```
|
||||
|
||||
5. Run the following command:
|
||||
|
14
db_badger.go
14
db_badger.go
@ -1,14 +0,0 @@
|
||||
// +build badger
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/fiatjaf/eventstore/badger"
|
||||
)
|
||||
|
||||
func getDB() badger.BadgerBackend {
|
||||
return badger.BadgerBackend{
|
||||
Path: getEnv("DB_PATH"),
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
// +build !badger
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/fiatjaf/eventstore/lmdb"
|
||||
)
|
||||
|
||||
func getDB() lmdb.LMDBBackend {
|
||||
return lmdb.LMDBBackend{
|
||||
Path: getEnv("DB_PATH"),
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,10 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- "./db:/app/db" # only change the left side before the colon
|
||||
- "./templates/index.html:/app/templates/index.html" # only change the left side before the colon
|
||||
- "./templates/static:/app/templates/static" # only change the left side before the colon
|
||||
- "./db:/app/db"
|
||||
- "./templates/index.html:${INDEX_PATH}"
|
||||
- "./templates/static:${STATIC_PATH}"
|
||||
ports:
|
||||
- "3334:3334"
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
|
@ -8,10 +8,12 @@ services:
|
||||
- .env
|
||||
volumes:
|
||||
- "./db:/app/db"
|
||||
- "./templates/index.html:/app/templates/index.html"
|
||||
- "./templates/static:/app/templates/static"
|
||||
- "./templates/index.html:${INDEX_PATH}"
|
||||
- "./templates/static:${STATIC_PATH}"
|
||||
ports:
|
||||
- "3334"
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
|
||||
tor:
|
||||
image: lncm/tor:0.4.7.9@sha256:86c2fe9d9099e6376798979110b8b9a3ee5d8adec27289ac4a5ee892514ffe92
|
||||
@ -23,3 +25,4 @@ services:
|
||||
- ./tor/data:/var/lib/tor
|
||||
restart: on-failure
|
||||
stop_grace_period: 10m30s
|
||||
init: true
|
@ -7,8 +7,10 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- "./db:/app/db" # only change the left side before the colon
|
||||
- "./templates/index.html:/app/templates/index.html" # only change the left side before the colon
|
||||
- "./templates/static:/app/templates/static" # only change the left side before the colon
|
||||
- "./db:/app/db"
|
||||
- "./templates/index.html:${INDEX_PATH}"
|
||||
- "./templates/static:${STATIC_PATH}"
|
||||
ports:
|
||||
- "3334:3334"
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
|
58
go.mod
58
go.mod
@ -1,51 +1,55 @@
|
||||
module github.com/bitvora/wot-relay
|
||||
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.23.1
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
github.com/PowerDNS/lmdb-go v1.9.2 // indirect
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/fiatjaf/eventstore v0.14.4
|
||||
github.com/fiatjaf/khatru v0.14.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/nbd-wtf/go-nostr v0.44.2
|
||||
)
|
||||
|
||||
require (
|
||||
fiatjaf.com/lib v0.2.0 // indirect
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/bep/debounce v1.2.1 // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
|
||||
github.com/dgraph-io/badger/v4 v4.2.0 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dgraph-io/badger/v4 v4.5.0 // indirect
|
||||
github.com/dgraph-io/ristretto v1.0.0 // indirect
|
||||
github.com/dgraph-io/ristretto/v2 v2.0.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fasthttp/websocket v1.5.7 // indirect
|
||||
github.com/fiatjaf/eventstore v0.8.2 // indirect
|
||||
github.com/fiatjaf/khatru v0.8.0 // indirect
|
||||
github.com/fasthttp/websocket v1.5.11 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.4.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v1.1.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/flatbuffers v23.5.26+incompatible // indirect
|
||||
github.com/greatroar/blobloom v0.8.0 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/google/flatbuffers v24.3.25+incompatible // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/nbd-wtf/go-nostr v0.35.1-0.20240912000534-64c6057c08ec // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect
|
||||
github.com/rs/cors v1.7.0 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
||||
github.com/tidwall/gjson v1.17.3 // indirect
|
||||
github.com/rs/cors v1.11.1 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
|
||||
github.com/tidwall/gjson v1.18.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||
github.com/valyala/fasthttp v1.58.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
|
||||
golang.org/x/net v0.18.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
google.golang.org/protobuf v1.35.2 // indirect
|
||||
)
|
||||
|
147
go.sum
147
go.sum
@ -1,40 +1,43 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
fiatjaf.com/lib v0.2.0 h1:TgIJESbbND6GjOgGHxF5jsO6EMjuAxIzZHPo5DXYexs=
|
||||
fiatjaf.com/lib v0.2.0/go.mod h1:Ycqq3+mJ9jAWu7XjbQI1cVr+OFgnHn79dQR5oTII47g=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PowerDNS/lmdb-go v1.9.2 h1:Cmgerh9y3ZKBZGz1irxSShhfmFyRUh+Zdk4cZk7ZJvU=
|
||||
github.com/PowerDNS/lmdb-go v1.9.2/go.mod h1:TE0l+EZK8Z1B4dx070ZxkWTlp8RG1mjN0/+FkFRQMtU=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
|
||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs=
|
||||
github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak=
|
||||
github.com/dgraph-io/badger/v4 v4.3.1 h1:7r5wKqmoRpGgSxqa0S/nGdpOpvvzuREGPLSua73C8tw=
|
||||
github.com/dgraph-io/badger/v4 v4.3.1/go.mod h1:oObz97DImXpd6O/Dt8BqdKLLTDmEmarAimo72VV5whQ=
|
||||
github.com/dgraph-io/badger/v4 v4.5.0 h1:TeJE3I1pIWLBjYhIYCA1+uxrjWEoJXImFBMEBVSm16g=
|
||||
github.com/dgraph-io/badger/v4 v4.5.0/go.mod h1:ysgYmIeG8dS/E8kwxT7xHyc7MkmwNYLRoYnFbr7387A=
|
||||
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
|
||||
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
||||
github.com/dgraph-io/ristretto v1.0.0 h1:SYG07bONKMlFDUYu5pEu3DGAh8c2OFNzKm6G9J4Si84=
|
||||
github.com/dgraph-io/ristretto v1.0.0/go.mod h1:jTi2FiYEhQ1NsMmA7DeBykizjOuY88NhKBkepyu1jPc=
|
||||
github.com/dgraph-io/ristretto/v2 v2.0.0 h1:l0yiSOtlJvc0otkqyMaDNysg8E9/F/TYZwMbxscNOAQ=
|
||||
github.com/dgraph-io/ristretto/v2 v2.0.0/go.mod h1:FVFokF2dRqXyPyeMnK1YDy8Fc6aTe0IKgbcd03CYeEk=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
@ -45,22 +48,24 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fasthttp/websocket v1.5.7 h1:0a6o2OfeATvtGgoMKleURhLT6JqWPg7fYfWnH4KHau4=
|
||||
github.com/fasthttp/websocket v1.5.7/go.mod h1:bC4fxSono9czeXHQUVKxsC0sNjbm7lPJR04GDFqClfU=
|
||||
github.com/fiatjaf/eventstore v0.5.1 h1:tTh+JYP0RME51VY2QB2Gvtzj6QTaZAnSVhgZtrYqY2A=
|
||||
github.com/fiatjaf/eventstore v0.5.1/go.mod h1:r5yCFmrVNT2b1xUOuMnDVS3xPGh97y8IgTcLyY2rYP8=
|
||||
github.com/fiatjaf/eventstore v0.8.1 h1:51LchQNy0Hpb0YQHwqYR5pKBpfDs/KjySlWCbbz2pkc=
|
||||
github.com/fiatjaf/eventstore v0.8.1/go.mod h1:bsp0Ibv0CIcVuFcoM2AEerMWmXRhF8uWXMf+dClhuow=
|
||||
github.com/fiatjaf/eventstore v0.8.2 h1:nCa3UuJNV5Y5t+SDoPQe7PBmKJ6dhm9TQ/WyR4SCbIM=
|
||||
github.com/fiatjaf/eventstore v0.8.2/go.mod h1:ck3RxufitHUBjID1RLcRxfX+NMywQzMsdfNpSt6m+9U=
|
||||
github.com/fiatjaf/khatru v0.8.0 h1:hofUi4qbSqkJiKD4rC9EyNdi9obzBvp3ykJOBxuu/h8=
|
||||
github.com/fiatjaf/khatru v0.8.0/go.mod h1:jRmqbbIbEH+y0unt3wMUBwqY/btVussqx5SmBoGhXtg=
|
||||
github.com/fasthttp/websocket v1.5.11 h1:TCO3H2VSxeTJQ+Ij+w8q7UBvdVedMOy/G7aZ0a6V19s=
|
||||
github.com/fasthttp/websocket v1.5.11/go.mod h1:QWILjDXurHFN5519nH2Pe9rtRuKZ/OIx/rlBF9coYds=
|
||||
github.com/fiatjaf/eventstore v0.10.1 h1:zgXrRhpyjzX0Eub4T6zkMZ60zRnIPJqy/Ipfx5h+yWo=
|
||||
github.com/fiatjaf/eventstore v0.10.1/go.mod h1:h5CdLSF7mEQ7/rWpEABTRIrNuFoSwdQDi/nZkW/vVFU=
|
||||
github.com/fiatjaf/eventstore v0.11.2 h1:gJTATGOk7RtDGt1qs47cLyTzko9phFyXlmWQb0zR7Lg=
|
||||
github.com/fiatjaf/eventstore v0.11.2/go.mod h1:oCHPB4TprrNjbhH2kjMKt1O48O1pk3VxAy5iZkB5Fb0=
|
||||
github.com/fiatjaf/eventstore v0.14.0 h1:eAyugJGFRCrXYJLCc2nC/BIApmBbQN/Z4dxvNz1SIvI=
|
||||
github.com/fiatjaf/eventstore v0.14.0/go.mod h1:XOl5B6WGBX1a0ww6s3WT94QVOmye/6zDTtyWHVtHQ5U=
|
||||
github.com/fiatjaf/eventstore v0.14.4 h1:bqJQit/M5E6vwbWwgrL4kTPoWCbt1Hb9H/AH4xf9uVQ=
|
||||
github.com/fiatjaf/eventstore v0.14.4/go.mod h1:3Kkujc6A8KjpNvSKu1jNCcFjSgEEyCxaDJVgShHz0J8=
|
||||
github.com/fiatjaf/khatru v0.8.2-0.20240913013357-18fc0dc1dd58 h1:F5Cy44IzxeIhzY8bf34rnORw0pYn6ZT/pIuyMO02Kjs=
|
||||
github.com/fiatjaf/khatru v0.8.2-0.20240913013357-18fc0dc1dd58/go.mod h1:jRmqbbIbEH+y0unt3wMUBwqY/btVussqx5SmBoGhXtg=
|
||||
github.com/fiatjaf/khatru v0.14.0 h1:zpWlAA87XBpDKBPIDbAuNw/HpKXzyt5XHVDbSvUbmDo=
|
||||
github.com/fiatjaf/khatru v0.14.0/go.mod h1:uxE5e8DBXPZqbHjr/gfatQas5bEJIMmsOCDcdF4LoRQ=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.2.0 h1:u0p9s3xLYpZCA1z5JgCkMeB34CKCMMQbM+G8Ii7YD0I=
|
||||
github.com/gobwas/ws v1.2.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU=
|
||||
github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
|
||||
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
@ -71,6 +76,8 @@ github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@ -84,10 +91,14 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg=
|
||||
github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
|
||||
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
@ -95,54 +106,70 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/greatroar/blobloom v0.8.0 h1:I9RlEkfqK9/6f1v9mFmDYegDQ/x0mISCpiNpAm23Pt4=
|
||||
github.com/greatroar/blobloom v0.8.0/go.mod h1:mjMJ1hh1wjGVfr93QIHJ6FfDNVrA0IELv8OvMHJxHKs=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0=
|
||||
github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/nbd-wtf/go-nostr v0.34.14 h1:o4n2LkuAtdIjNYJ23sFbcx68UXLnji4j8hYR1Sd2wgI=
|
||||
github.com/nbd-wtf/go-nostr v0.34.14/go.mod h1:NZQkxl96ggbO8rvDpVjcsojJqKTPwqhP4i82O7K5DJs=
|
||||
github.com/nbd-wtf/go-nostr v0.34.15 h1:InUaCM3Mw20U3hyoZBpY39LELHBmMa4bK81iGCY5+W4=
|
||||
github.com/nbd-wtf/go-nostr v0.34.15/go.mod h1:NZQkxl96ggbO8rvDpVjcsojJqKTPwqhP4i82O7K5DJs=
|
||||
github.com/nbd-wtf/go-nostr v0.35.1-0.20240912000534-64c6057c08ec h1:83Ce39kWnvq6VgfMKSMtcbwBcSmnab2VDX+tlKWZuqo=
|
||||
github.com/nbd-wtf/go-nostr v0.35.1-0.20240912000534-64c6057c08ec/go.mod h1:RNovrTNC8aQNqkwfdX6y4thxHN3zueewqyZoSiDBaQY=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/nbd-wtf/go-nostr v0.38.1 h1:D0moEtIpjhWs2zbgeRyokA4TOLzBdumtpL1/O7/frww=
|
||||
github.com/nbd-wtf/go-nostr v0.38.1/go.mod h1:TGKGj00BmJRXvRe0LlpDN3KKbELhhPXgBwUEhzu3Oq0=
|
||||
github.com/nbd-wtf/go-nostr v0.42.0 h1:EofWfXEhKic9AYVf4RHuXZr+kKUZE2jVyJtJByNe1rE=
|
||||
github.com/nbd-wtf/go-nostr v0.42.0/go.mod h1:FBa4FBJO7NuANvkeKSlrf0BIyxGufmrUbuelr6Q4Ick=
|
||||
github.com/nbd-wtf/go-nostr v0.44.2 h1:+DHDbHuUZS3Fkh9w4j2v64sTLC4fY8ktuiBsNg9GcXg=
|
||||
github.com/nbd-wtf/go-nostr v0.44.2/go.mod h1:m0ID2gSA2Oak/uaPnM1uN22JhDRZS4UVJG2c8jo19rg=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbAaew=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
|
||||
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
|
||||
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
|
||||
github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
@ -150,6 +177,9 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||
github.com/valyala/fasthttp v1.58.0 h1:GGB2dWxSbEprU9j0iMJHgdKYJVDyjrOwF9RE59PbRuE=
|
||||
github.com/valyala/fasthttp v1.58.0/go.mod h1:SYXvHHaFp7QZHGKSHmoMipInhrI5StHrhDTYVEjK/Kw=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
@ -158,12 +188,10 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
|
||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
|
||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
@ -178,8 +206,12 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -192,12 +224,12 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@ -233,11 +265,16 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
|
||||
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
339
main.go
339
main.go
@ -9,16 +9,21 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cespare/xxhash"
|
||||
"github.com/fiatjaf/eventstore"
|
||||
"github.com/fiatjaf/eventstore/badger"
|
||||
"github.com/fiatjaf/khatru"
|
||||
"github.com/greatroar/blobloom"
|
||||
"github.com/fiatjaf/khatru/policies"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
)
|
||||
|
||||
var (
|
||||
version string
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
RelayName string
|
||||
RelayPubkey string
|
||||
@ -28,18 +33,27 @@ type Config struct {
|
||||
IndexPath string
|
||||
StaticPath string
|
||||
RefreshInterval int
|
||||
MinimumFollowers int
|
||||
ArchivalSync bool
|
||||
RelayContact string
|
||||
RelayIcon string
|
||||
MaxAgeDays int
|
||||
ArchiveReactions bool
|
||||
IgnoredPubkeys []string
|
||||
}
|
||||
|
||||
var pool *nostr.SimplePool
|
||||
var wdb nostr.RelayStore
|
||||
var relays []string
|
||||
var config Config
|
||||
var trustNetwork []string
|
||||
var mu sync.Mutex
|
||||
var trustNetworkFilter *blobloom.Filter
|
||||
var trustNetworkFilterMu sync.Mutex
|
||||
var seedRelays []string
|
||||
var booted bool
|
||||
var oneHopNetwork []string
|
||||
var trustNetworkMap map[string]bool
|
||||
var pubkeyFollowerCount = make(map[string]int)
|
||||
var trustedNotes uint64
|
||||
var untrustedNotes uint64
|
||||
|
||||
func main() {
|
||||
nostr.InfoLogger = log.New(io.Discard, "", 0)
|
||||
@ -70,27 +84,48 @@ func main() {
|
||||
|
||||
relay.Info.Name = config.RelayName
|
||||
relay.Info.PubKey = config.RelayPubkey
|
||||
relay.Info.Icon = config.RelayIcon
|
||||
relay.Info.Contact = config.RelayContact
|
||||
relay.Info.Description = config.RelayDescription
|
||||
relay.Info.Software = "https://github.com/bitvora/wot-relay"
|
||||
relay.Info.Version = version
|
||||
|
||||
appendPubkey(config.RelayPubkey)
|
||||
|
||||
db := getDB()
|
||||
if err := db.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wdb = eventstore.RelayWrapper{Store: &db}
|
||||
|
||||
relay.RejectEvent = append(relay.RejectEvent,
|
||||
policies.RejectEventsWithBase64Media,
|
||||
policies.EventIPRateLimiter(5, time.Minute*1, 30),
|
||||
)
|
||||
|
||||
relay.RejectFilter = append(relay.RejectFilter,
|
||||
policies.NoEmptyFilters,
|
||||
policies.NoComplexFilters,
|
||||
)
|
||||
|
||||
relay.RejectConnection = append(relay.RejectConnection,
|
||||
policies.ConnectionRateLimiter(10, time.Minute*2, 30),
|
||||
)
|
||||
|
||||
relay.StoreEvent = append(relay.StoreEvent, db.SaveEvent)
|
||||
relay.QueryEvents = append(relay.QueryEvents, db.QueryEvents)
|
||||
relay.DeleteEvent = append(relay.DeleteEvent, db.DeleteEvent)
|
||||
relay.RejectEvent = append(relay.RejectEvent, func(ctx context.Context, event *nostr.Event) (bool, string) {
|
||||
for _, pk := range trustNetwork {
|
||||
if pk == event.PubKey {
|
||||
return false, ""
|
||||
}
|
||||
if !trustNetworkMap[event.PubKey] {
|
||||
return true, "we are rebuilding the trust network, please try again later"
|
||||
}
|
||||
return true, "you are not in the web of trust"
|
||||
if event.Kind == nostr.KindEncryptedDirectMessage {
|
||||
return true, "only gift wrapped DMs are allowed"
|
||||
}
|
||||
|
||||
return false, ""
|
||||
})
|
||||
|
||||
mu.Lock()
|
||||
seedRelays = []string{
|
||||
"wss://nos.lol",
|
||||
"wss://nostr.mom",
|
||||
@ -107,9 +142,8 @@ func main() {
|
||||
"wss://nostrue.com",
|
||||
"wss://relay.siamstr.com",
|
||||
}
|
||||
mu.Unlock()
|
||||
|
||||
go refreshTrustNetwork(relay, ctx)
|
||||
go refreshTrustNetwork(ctx, relay)
|
||||
|
||||
mux := relay.Router()
|
||||
static := http.FileServer(http.Dir(config.StaticPath))
|
||||
@ -153,15 +187,54 @@ func LoadConfig() Config {
|
||||
refreshInterval, _ := strconv.Atoi(os.Getenv("REFRESH_INTERVAL_HOURS"))
|
||||
log.Println("🔄 refresh interval set to", refreshInterval, "hours")
|
||||
|
||||
if os.Getenv("MINIMUM_FOLLOWERS") == "" {
|
||||
os.Setenv("MINIMUM_FOLLOWERS", "1")
|
||||
}
|
||||
|
||||
if os.Getenv("ARCHIVAL_SYNC") == "" {
|
||||
os.Setenv("ARCHIVAL_SYNC", "TRUE")
|
||||
}
|
||||
|
||||
if os.Getenv("RELAY_ICON") == "" {
|
||||
os.Setenv("RELAY_ICON", "https://pfp.nostr.build/56306a93a88d4c657d8a3dfa57b55a4ed65b709eee927b5dafaab4d5330db21f.png")
|
||||
}
|
||||
|
||||
if os.Getenv("RELAY_CONTACT") == "" {
|
||||
os.Setenv("RELAY_CONTACT", getEnv("RELAY_PUBKEY"))
|
||||
}
|
||||
|
||||
if os.Getenv("MAX_AGE_DAYS") == "" {
|
||||
os.Setenv("MAX_AGE_DAYS", "0")
|
||||
}
|
||||
|
||||
if os.Getenv("ARCHIVE_REACTIONS") == "" {
|
||||
os.Setenv("ARCHIVE_REACTIONS", "FALSE")
|
||||
}
|
||||
|
||||
ignoredPubkeys := []string{}
|
||||
if ignoreList := os.Getenv("IGNORE_FOLLOWS_LIST"); ignoreList != "" {
|
||||
ignoredPubkeys = splitAndTrim(ignoreList)
|
||||
}
|
||||
|
||||
minimumFollowers, _ := strconv.Atoi(os.Getenv("MINIMUM_FOLLOWERS"))
|
||||
maxAgeDays, _ := strconv.Atoi(os.Getenv("MAX_AGE_DAYS"))
|
||||
|
||||
config := Config{
|
||||
RelayName: getEnv("RELAY_NAME"),
|
||||
RelayPubkey: getEnv("RELAY_PUBKEY"),
|
||||
RelayDescription: getEnv("RELAY_DESCRIPTION"),
|
||||
RelayContact: getEnv("RELAY_CONTACT"),
|
||||
RelayIcon: getEnv("RELAY_ICON"),
|
||||
DBPath: getEnv("DB_PATH"),
|
||||
RelayURL: getEnv("RELAY_URL"),
|
||||
IndexPath: getEnv("INDEX_PATH"),
|
||||
StaticPath: getEnv("STATIC_PATH"),
|
||||
RefreshInterval: refreshInterval,
|
||||
MinimumFollowers: minimumFollowers,
|
||||
ArchivalSync: getEnv("ARCHIVAL_SYNC") == "TRUE",
|
||||
MaxAgeDays: maxAgeDays,
|
||||
ArchiveReactions: getEnv("ARCHIVE_REACTIONS") == "TRUE",
|
||||
IgnoredPubkeys: ignoredPubkeys,
|
||||
}
|
||||
|
||||
return config
|
||||
@ -176,21 +249,42 @@ func getEnv(key string) string {
|
||||
}
|
||||
|
||||
func updateTrustNetworkFilter() {
|
||||
trustNetworkFilterMu.Lock()
|
||||
defer trustNetworkFilterMu.Unlock()
|
||||
trustNetworkMap = make(map[string]bool)
|
||||
|
||||
nKeys := uint64(len(trustNetwork))
|
||||
log.Println("🌐 updating trust network filter with", nKeys, "keys")
|
||||
trustNetworkFilter = blobloom.NewOptimized(blobloom.Config{
|
||||
Capacity: nKeys,
|
||||
FPRate: 1e-4,
|
||||
})
|
||||
for _, trustedPubkey := range trustNetwork {
|
||||
trustNetworkFilter.Add(xxhash.Sum64([]byte(trustedPubkey)))
|
||||
log.Println("🌐 updating trust network map")
|
||||
for pubkey, count := range pubkeyFollowerCount {
|
||||
if count >= config.MinimumFollowers {
|
||||
trustNetworkMap[pubkey] = true
|
||||
appendPubkey(pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("🌐 trust network map updated with", len(trustNetwork), "keys")
|
||||
}
|
||||
|
||||
func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) {
|
||||
func refreshProfiles(ctx context.Context) {
|
||||
for i := 0; i < len(trustNetwork); i += 200 {
|
||||
timeout, cancel := context.WithTimeout(ctx, 4*time.Second)
|
||||
defer cancel()
|
||||
|
||||
end := i + 200
|
||||
if end > len(trustNetwork) {
|
||||
end = len(trustNetwork)
|
||||
}
|
||||
|
||||
filters := []nostr.Filter{{
|
||||
Authors: trustNetwork[i:end],
|
||||
Kinds: []int{nostr.KindProfileMetadata},
|
||||
}}
|
||||
|
||||
for ev := range pool.SubManyEose(timeout, seedRelays, filters) {
|
||||
wdb.Publish(ctx, *ev.Event)
|
||||
}
|
||||
}
|
||||
log.Println("👤 profiles refreshed: ", len(trustNetwork))
|
||||
}
|
||||
|
||||
func refreshTrustNetwork(ctx context.Context, relay *khatru.Relay) {
|
||||
|
||||
runTrustNetworkRefresh := func() {
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||
@ -198,12 +292,18 @@ func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) {
|
||||
|
||||
filters := []nostr.Filter{{
|
||||
Authors: []string{config.RelayPubkey},
|
||||
Kinds: []int{nostr.KindContactList},
|
||||
Kinds: []int{nostr.KindFollowList},
|
||||
}}
|
||||
|
||||
log.Println("🔍 fetching owner's follows")
|
||||
for ev := range pool.SubManyEose(timeoutCtx, seedRelays, filters) {
|
||||
for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) {
|
||||
pubkey := contact[1]
|
||||
if isIgnored(pubkey, config.IgnoredPubkeys) {
|
||||
fmt.Println("ignoring follows from pubkey: ", pubkey)
|
||||
continue
|
||||
}
|
||||
pubkeyFollowerCount[contact[1]]++ // Increment follower count for the pubkey
|
||||
appendOneHopNetwork(contact[1])
|
||||
}
|
||||
}
|
||||
@ -220,13 +320,13 @@ func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) {
|
||||
|
||||
filters = []nostr.Filter{{
|
||||
Authors: oneHopNetwork[i:end],
|
||||
Kinds: []int{nostr.KindContactList, nostr.KindRelayListMetadata, nostr.KindProfileMetadata},
|
||||
Kinds: []int{nostr.KindFollowList, nostr.KindRelayListMetadata, nostr.KindProfileMetadata},
|
||||
}}
|
||||
|
||||
for ev := range pool.SubManyEose(timeout, seedRelays, filters) {
|
||||
for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) {
|
||||
if len(contact) > 1 {
|
||||
appendPubkey(contact[1])
|
||||
pubkeyFollowerCount[contact[1]]++ // Increment follower count for the pubkey
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,25 +335,23 @@ func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) {
|
||||
}
|
||||
|
||||
if ev.Event.Kind == nostr.KindProfileMetadata {
|
||||
relay.AddEvent(ctx, ev.Event)
|
||||
wdb.Publish(ctx, *ev.Event)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
log.Println("🫂 network size:", len(trustNetwork))
|
||||
log.Println("🫂 total network size:", len(pubkeyFollowerCount))
|
||||
log.Println("🔗 relays discovered:", len(relays))
|
||||
}
|
||||
|
||||
for {
|
||||
runTrustNetworkRefresh()
|
||||
updateTrustNetworkFilter()
|
||||
archiveTrustedNotes(relay, ctx)
|
||||
deleteOldNotes(relay)
|
||||
archiveTrustedNotes(ctx, relay)
|
||||
}
|
||||
}
|
||||
|
||||
func appendRelay(relay string) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
for _, r := range relays {
|
||||
if r == relay {
|
||||
@ -264,9 +362,6 @@ func appendRelay(relay string) {
|
||||
}
|
||||
|
||||
func appendPubkey(pubkey string) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
for _, pk := range trustNetwork {
|
||||
if pk == pubkey {
|
||||
return
|
||||
@ -281,9 +376,6 @@ func appendPubkey(pubkey string) {
|
||||
}
|
||||
|
||||
func appendOneHopNetwork(pubkey string) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
for _, pk := range oneHopNetwork {
|
||||
if pk == pubkey {
|
||||
return
|
||||
@ -297,15 +389,107 @@ func appendOneHopNetwork(pubkey string) {
|
||||
oneHopNetwork = append(oneHopNetwork, pubkey)
|
||||
}
|
||||
|
||||
func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) {
|
||||
func archiveTrustedNotes(ctx context.Context, relay *khatru.Relay) {
|
||||
timeout, cancel := context.WithTimeout(ctx, time.Duration(config.RefreshInterval)*time.Hour)
|
||||
defer cancel()
|
||||
|
||||
filters := []nostr.Filter{{
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
if config.ArchivalSync {
|
||||
go refreshProfiles(ctx)
|
||||
|
||||
var filters []nostr.Filter
|
||||
if config.ArchiveReactions {
|
||||
|
||||
filters = []nostr.Filter{{
|
||||
Kinds: []int{
|
||||
nostr.KindArticle,
|
||||
nostr.KindDeletion,
|
||||
nostr.KindFollowList,
|
||||
nostr.KindEncryptedDirectMessage,
|
||||
nostr.KindMuteList,
|
||||
nostr.KindReaction,
|
||||
nostr.KindRelayListMetadata,
|
||||
nostr.KindRepost,
|
||||
nostr.KindZapRequest,
|
||||
nostr.KindZap,
|
||||
nostr.KindTextNote,
|
||||
},
|
||||
}}
|
||||
} else {
|
||||
filters = []nostr.Filter{{
|
||||
Kinds: []int{
|
||||
nostr.KindArticle,
|
||||
nostr.KindDeletion,
|
||||
nostr.KindFollowList,
|
||||
nostr.KindEncryptedDirectMessage,
|
||||
nostr.KindMuteList,
|
||||
nostr.KindRelayListMetadata,
|
||||
nostr.KindRepost,
|
||||
nostr.KindZapRequest,
|
||||
nostr.KindZap,
|
||||
nostr.KindTextNote,
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
log.Println("📦 archiving trusted notes...")
|
||||
|
||||
for ev := range pool.SubMany(timeout, seedRelays, filters) {
|
||||
go archiveEvent(ctx, relay, *ev.Event)
|
||||
}
|
||||
|
||||
log.Println("📦 archived", trustedNotes, "trusted notes and discarded", untrustedNotes, "untrusted notes")
|
||||
} else {
|
||||
log.Println("🔄 web of trust will refresh in", config.RefreshInterval, "hours")
|
||||
select {
|
||||
case <-timeout.Done():
|
||||
}
|
||||
}
|
||||
|
||||
close(done)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-timeout.Done():
|
||||
log.Println("restarting process")
|
||||
case <-done:
|
||||
log.Println("📦 archiving process completed")
|
||||
}
|
||||
}
|
||||
|
||||
func archiveEvent(ctx context.Context, relay *khatru.Relay, ev nostr.Event) {
|
||||
if trustNetworkMap[ev.PubKey] {
|
||||
wdb.Publish(ctx, ev)
|
||||
relay.BroadcastEvent(&ev)
|
||||
trustedNotes++
|
||||
} else {
|
||||
untrustedNotes++
|
||||
}
|
||||
}
|
||||
|
||||
func deleteOldNotes(relay *khatru.Relay) error {
|
||||
ctx := context.TODO()
|
||||
|
||||
if config.MaxAgeDays <= 0 {
|
||||
log.Printf("MAX_AGE_DAYS disabled")
|
||||
return nil
|
||||
}
|
||||
|
||||
maxAgeSecs := nostr.Timestamp(config.MaxAgeDays * 86400)
|
||||
oldAge := nostr.Now() - maxAgeSecs
|
||||
if oldAge <= 0 {
|
||||
log.Printf("MAX_AGE_DAYS too large")
|
||||
return nil
|
||||
}
|
||||
|
||||
filter := nostr.Filter{
|
||||
Until: &oldAge,
|
||||
Kinds: []int{
|
||||
nostr.KindArticle,
|
||||
nostr.KindDeletion,
|
||||
nostr.KindContactList,
|
||||
nostr.KindFollowList,
|
||||
nostr.KindEncryptedDirectMessage,
|
||||
nostr.KindMuteList,
|
||||
nostr.KindReaction,
|
||||
@ -315,34 +499,57 @@ func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) {
|
||||
nostr.KindZap,
|
||||
nostr.KindTextNote,
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
log.Println("📦 archiving trusted notes...")
|
||||
var trustedNotes uint64
|
||||
var untrustedNotes uint64
|
||||
trustNetworkFilterMu.Lock()
|
||||
defer trustNetworkFilterMu.Unlock()
|
||||
ch, err := relay.QueryEvents[0](ctx, filter)
|
||||
if err != nil {
|
||||
log.Printf("query error %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for ev := range pool.SubMany(timeout, seedRelays, filters) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Println("⏰ Archive process terminated due to timeout")
|
||||
return
|
||||
default:
|
||||
if trustNetworkFilter.Has(xxhash.Sum64([]byte(ev.Event.PubKey))) {
|
||||
if len(ev.Event.Tags) > 3000 {
|
||||
continue
|
||||
}
|
||||
events := make([]*nostr.Event, 0)
|
||||
|
||||
relay.AddEvent(ctx, ev.Event)
|
||||
log.Println("📦 archived note: ", ev.Event.ID)
|
||||
trustedNotes++
|
||||
} else {
|
||||
untrustedNotes++
|
||||
for evt := range ch {
|
||||
events = append(events, evt)
|
||||
}
|
||||
|
||||
if len(events) < 1 {
|
||||
log.Println("0 old notes found")
|
||||
return nil
|
||||
}
|
||||
|
||||
for num_evt, del_evt := range events {
|
||||
for _, del := range relay.DeleteEvent {
|
||||
if err := del(ctx, del_evt); err != nil {
|
||||
log.Printf("error deleting note %d of %d. event id: %s", num_evt, len(events), del_evt.ID)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("📦 archived", trustedNotes, "trusted notes and discarded", untrustedNotes, "untrusted notes")
|
||||
return
|
||||
log.Printf("%d old (until %d) notes deleted", len(events), oldAge)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDB() badger.BadgerBackend {
|
||||
return badger.BadgerBackend{
|
||||
Path: getEnv("DB_PATH"),
|
||||
}
|
||||
}
|
||||
|
||||
func splitAndTrim(input string) []string {
|
||||
items := strings.Split(input, ",")
|
||||
for i, item := range items {
|
||||
items[i] = strings.TrimSpace(item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func isIgnored(pubkey string, ignoredPubkeys []string) bool {
|
||||
for _, ignored := range ignoredPubkeys {
|
||||
if pubkey == ignored {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -44,7 +44,14 @@
|
||||
<!-- Footer -->
|
||||
<footer class="text-center py-6 bg-gray-800 w-full">
|
||||
<p class="text-lg text-gray-400">
|
||||
Proudly powered by
|
||||
Built with love by
|
||||
<a
|
||||
href="https://bitvora.com"
|
||||
target="_blank"
|
||||
class="text-purple-300 hover:text-purple-400 underline"
|
||||
>Bitvora</a
|
||||
>
|
||||
and Proudly powered by
|
||||
<a
|
||||
href="https://khatru.nostr.technology/"
|
||||
target="_blank"
|
||||
|
Loading…
x
Reference in New Issue
Block a user