mirror of
https://github.com/bitvora/wot-relay.git
synced 2025-04-22 16:51:28 +00:00
Compare commits
159 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 | ||
![]() |
87fb79fd52 | ||
![]() |
0f3578c5a5 | ||
![]() |
cead2aa446 | ||
![]() |
58953dacc0 | ||
![]() |
5d9325793f | ||
![]() |
f1ff8bb6bb | ||
![]() |
3fdc038310 | ||
![]() |
489e51e274 | ||
![]() |
559d0ca1f4 | ||
![]() |
f684c13b7f | ||
![]() |
0897e1634b | ||
![]() |
9efa2149d0 | ||
![]() |
2aab9f3e49 | ||
![]() |
13d23ee8a2 | ||
![]() |
c8353369a3 | ||
![]() |
047774a027 | ||
![]() |
814706b22c | ||
![]() |
307eab490d | ||
![]() |
6a6f1c9108 | ||
![]() |
413e6df9e6 | ||
![]() |
89a0552ce8 | ||
![]() |
3bcf881473 | ||
![]() |
282f8ef71f | ||
![]() |
241c94e4d7 | ||
![]() |
7a114cb3a8 | ||
![]() |
2ce02fba9c | ||
![]() |
0505740f1e | ||
![]() |
f2f3d83eba | ||
![]() |
ee2b4eef6d | ||
![]() |
ae947e2f1f | ||
![]() |
cee4d78223 | ||
![]() |
7fa90fa885 | ||
![]() |
b8ae4a5ccb | ||
![]() |
dd9763e967 | ||
![]() |
55bae27490 | ||
![]() |
f60362cd14 | ||
![]() |
d1198a31b5 | ||
![]() |
6ccb91e652 | ||
![]() |
a97e0ab2d8 | ||
![]() |
62aac83d0a | ||
![]() |
a385e86bad | ||
![]() |
5ba7aae9cd | ||
![]() |
ea3c498e24 | ||
![]() |
6115af6ccd | ||
![]() |
3f3e42267e | ||
![]() |
3f38d91de6 | ||
![]() |
3698089a8f | ||
![]() |
4dc6cab618 | ||
![]() |
6372f55a7b | ||
![]() |
8458b2a10f | ||
![]() |
ca8dde54f1 | ||
![]() |
e38dcc71ba |
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
db
|
28
.env.example
28
.env.example
@ -1,6 +1,30 @@
|
|||||||
|
# Relay Metadata
|
||||||
RELAY_NAME="utxo WoT relay"
|
RELAY_NAME="utxo WoT relay"
|
||||||
RELAY_PUBKEY="e2ccf7cf20403f3f2a4a55b328f0de3be38558a7d5f33632fdaaefc726c1c8eb"
|
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_DESCRIPTION="Only notes in utxo WoT"
|
||||||
RELAY_URL="wss://wot.utxo.one"
|
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"
|
DB_PATH="db"
|
||||||
INDEX_PATH="templates/index.html"
|
|
||||||
|
# where we should store the index.html and static files
|
||||||
|
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
|
22
Dockerfile
22
Dockerfile
@ -4,18 +4,22 @@ FROM golang:bookworm
|
|||||||
# Set the working directory within the container
|
# Set the working directory within the container
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Clone the repository
|
# Copy go.mod and go.sum files
|
||||||
RUN git clone https://github.com/bitvora/wot-relay .
|
COPY go.mod go.sum ./
|
||||||
|
|
||||||
# Download Go module dependencies
|
# Download dependencies
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
# Write the .env file
|
# Copy the rest of the application source code
|
||||||
RUN touch .env && \
|
COPY . .
|
||||||
echo "RELAY_NAME=${RELAY_NAME}" >> .env && \
|
|
||||||
echo "RELAY_PUBKEY=${RELAY_PUBKEY}" >> .env && \
|
# Set fixed environment variables
|
||||||
echo "RELAY_DESCRIPTION=${RELAY_DESCRIPTION}" >> .env && \
|
ENV DB_PATH="db"
|
||||||
echo "DB_PATH=${DB_PATH}" >> .env
|
ENV INDEX_PATH="templates/index.html"
|
||||||
|
ENV STATIC_PATH="templates/static"
|
||||||
|
|
||||||
|
# touch a .env (https://github.com/bitvora/wot-relay/pull/4)
|
||||||
|
RUN touch .env
|
||||||
|
|
||||||
# Build the Go application
|
# Build the Go application
|
||||||
RUN go build -o main .
|
RUN go build -o main .
|
||||||
|
44
Dockerfile-optimized
Normal file
44
Dockerfile-optimized
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Stage 1: Build the Go application
|
||||||
|
FROM golang:bookworm AS builder
|
||||||
|
|
||||||
|
# Set the working directory within the container
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy go.mod and go.sum files
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
|
||||||
|
# Download dependencies
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Copy the rest of the application source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Set fixed environment variables for build
|
||||||
|
ENV DB_PATH="db"
|
||||||
|
ENV INDEX_PATH="templates/index.html"
|
||||||
|
ENV STATIC_PATH="templates/static"
|
||||||
|
|
||||||
|
# touch a .env
|
||||||
|
RUN touch .env
|
||||||
|
|
||||||
|
# Build the Go application
|
||||||
|
RUN go build -o main .
|
||||||
|
|
||||||
|
# Stage 2: Create a minimal image to run the Go application
|
||||||
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
|
# Set the working directory within the container
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the Go binary from the builder stage
|
||||||
|
COPY --from=builder /app/main /app/
|
||||||
|
|
||||||
|
# Copy any necessary files like templates, static assets, etc.
|
||||||
|
COPY --from=builder /app/templates /app/templates
|
||||||
|
COPY --from=builder /app/.env /app/
|
||||||
|
|
||||||
|
# Expose the port that the application will run on
|
||||||
|
EXPOSE 3334
|
||||||
|
|
||||||
|
# Set the command to run the executable
|
||||||
|
CMD ["./main"]
|
154
README.md
154
README.md
@ -1,10 +1,34 @@
|
|||||||
# WOT Relay
|
# WoT Relay
|
||||||
|
|
||||||
WOT Relay is a Nostr relay that saves all the notes that people you follow, and people they follow are posting.
|
WOT Relay is a Nostr relay that saves all the notes that people you follow, and people they follow are posting. It's built on the [Khatru](https://khatru.nostr.technology) framework.
|
||||||
|
|
||||||
|
# Available Relays
|
||||||
|
|
||||||
|
Don't want to run the relay, just want to connect to some? Here are some available relays:
|
||||||
|
|
||||||
|
- [wss://wot.utxo.one](https://wot.utxo.one)
|
||||||
|
- [wss://nostrelites.org](https://nostrelites.org)
|
||||||
|
- [wss://wot.nostr.party](https://wot.nostr.party)
|
||||||
|
- [wss://wot.sovbit.host](https://wot.sovbit.host)
|
||||||
|
- [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
|
## Prerequisites
|
||||||
|
|
||||||
- **Go**: Ensure you have Go installed on your system. You can download it from [here](https://golang.org/dl/).
|
- **Go**: Ensure you have Go installed on your system. You can download it from [here](https://golang.org/dl/).
|
||||||
|
- **Build Essentials**: If you're using Linux, you may need to install build essentials. You can do this by running `sudo apt install build-essential`.
|
||||||
|
|
||||||
## Setup Instructions
|
## Setup Instructions
|
||||||
|
|
||||||
@ -31,9 +55,16 @@ Open the `.env` file and set the necessary environment variables. Example variab
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
RELAY_NAME="YourRelayName"
|
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"
|
RELAY_DESCRIPTION="Your relay description"
|
||||||
DB_PATH="/path/to/your/database"
|
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
|
### 4. Build the project
|
||||||
@ -41,12 +72,12 @@ DB_PATH="/path/to/your/database"
|
|||||||
Run the following command to build the relay:
|
Run the following command to build the relay:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go build
|
go build -ldflags "-X main.version=$(git describe --tags --always)"
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. Create a Systemd Service (optional)
|
### 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:
|
1. Create the file:
|
||||||
|
|
||||||
@ -62,10 +93,10 @@ Description=WOT Relay Service
|
|||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/path/to/wot-relay
|
ExecStart=/home/ubuntu/wot-relay/wot-relay
|
||||||
WorkingDirectory=/path/to/wot-relay
|
WorkingDirectory=/home/ubuntu/wot-relay
|
||||||
Restart=always
|
Restart=always
|
||||||
EnvironmentFile=/path/to/.env
|
MemoryLimit=2G
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
@ -91,32 +122,117 @@ sudo systemctl start wot-relay
|
|||||||
sudo systemctl enable wot-relay
|
sudo systemctl enable wot-relay
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6. Start the Project with Docker Compose (optional)
|
#### Permission Issues on Some Systems
|
||||||
|
|
||||||
|
the relay may not have permissions to read and write to the database. To fix this, you can change the permissions of the database folder:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo chmod -R 777 /path/to/db
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Serving over nginx (optional)
|
||||||
|
|
||||||
|
You can serve the relay over nginx by adding the following configuration to your nginx configuration file:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name yourdomain.com;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://localhost:3334;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `yourdomain.com` with your actual domain name.
|
||||||
|
|
||||||
|
After adding the configuration, restart nginx:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl restart nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Install Certbot (optional)
|
||||||
|
|
||||||
|
If you want to serve the relay over HTTPS, you can use Certbot to generate an SSL certificate.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install certbot python3-certbot-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
After installing Certbot, run the following command to generate an SSL certificate:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo certbot --nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
Follow the instructions to generate the certificate.
|
||||||
|
|
||||||
|
### 8. Access the relay
|
||||||
|
|
||||||
|
Once everything is set up, the relay will be running on `localhost:3334` or your domain name if you set up nginx.
|
||||||
|
|
||||||
|
## Start the Project with Docker Compose
|
||||||
|
|
||||||
To start the project using Docker Compose, follow these steps:
|
To start the project using Docker Compose, follow these steps:
|
||||||
|
|
||||||
1. Ensure Docker and Docker Compose are installed on your system.
|
1. Ensure Docker and Docker Compose are installed on your system.
|
||||||
2. Navigate to the project directory.
|
2. Navigate to the project directory.
|
||||||
3. Edit the `docker-compose.yml` file to update the environment variables as needed:
|
3. Ensure the `.env` file is present in the project directory and has the necessary environment variables set.
|
||||||
|
4. You can also change the paths of the `db` folder and `templates` folder in the `docker-compose.yml` file.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
environment:
|
volumes:
|
||||||
RELAY_NAME: "utxo WoT relay"
|
- "./db:/app/db" # only change the left side before the colon
|
||||||
RELAY_PUBKEY: "YOURPUBKEY"
|
- "./templates/index.html:${INDEX_PATH}" # only change the left side before the colon
|
||||||
RELAY_DESCRIPTION: "Only notes in utxo WoT"
|
- "./templates/static:${INDEX_PATH}" # only change the left side before the colon
|
||||||
DB_PATH: "./db"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Run the following command:
|
5. Run the following command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker-compose up --build
|
# in foreground
|
||||||
|
docker compose up --build
|
||||||
|
# in background
|
||||||
|
docker compose up --build -d
|
||||||
|
```
|
||||||
|
|
||||||
|
6. For updating the relay, run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git pull
|
||||||
|
docker compose build --no-cache
|
||||||
|
# in foreground
|
||||||
|
docker compose up
|
||||||
|
# in background
|
||||||
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
This will build the Docker image and start the `wot-relay` service as defined in the `docker-compose.yml` file. The application will be accessible on port 3334.
|
This will build the Docker image and start the `wot-relay` service as defined in the `docker-compose.yml` file. The application will be accessible on port 3334.
|
||||||
|
|
||||||
|
### 7. Hidden Service with Tor (optional)
|
||||||
|
|
||||||
### 7. Access the relay
|
Same as the step 6, but with the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# in foreground
|
||||||
|
docker compose -f docker-compose.tor.yml up --build
|
||||||
|
# in background
|
||||||
|
docker compose -f docker-compose.tor.yml up --build -d
|
||||||
|
```
|
||||||
|
|
||||||
|
You can find the onion address here: `tor/data/relay/hostname`
|
||||||
|
|
||||||
|
### 8. Access the relay
|
||||||
|
|
||||||
Once everything is set up, the relay will be running on `localhost:3334`.
|
Once everything is set up, the relay will be running on `localhost:3334`.
|
||||||
|
|
||||||
|
31
arm64.Dockerfile
Normal file
31
arm64.Dockerfile
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Use Golang image based on Debian Bookworm
|
||||||
|
FROM golang:bookworm
|
||||||
|
|
||||||
|
# Set the working directory within the container
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy go.mod and go.sum files
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
|
||||||
|
# Download dependencies
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Copy the rest of the application source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Set fixed environment variables
|
||||||
|
ENV DB_PATH="db"
|
||||||
|
ENV INDEX_PATH="templates/index.html"
|
||||||
|
ENV STATIC_PATH="templates/static"
|
||||||
|
|
||||||
|
# touch a .env (https://github.com/bitvora/wot-relay/pull/4)
|
||||||
|
RUN touch .env
|
||||||
|
|
||||||
|
# Build the Go application
|
||||||
|
RUN go build -tags badger -o main .
|
||||||
|
|
||||||
|
# Expose the port that the application will run on
|
||||||
|
EXPOSE 3334
|
||||||
|
|
||||||
|
# Set the command to run the executable
|
||||||
|
CMD ["./main"]
|
16
docker-compose.arm64.yml
Normal file
16
docker-compose.arm64.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
services:
|
||||||
|
relay:
|
||||||
|
container_name: wot-relay
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: arm64.Dockerfile
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
volumes:
|
||||||
|
- "./db:/app/db"
|
||||||
|
- "./templates/index.html:${INDEX_PATH}"
|
||||||
|
- "./templates/static:${STATIC_PATH}"
|
||||||
|
ports:
|
||||||
|
- "3334:3334"
|
||||||
|
restart: unless-stopped
|
||||||
|
init: true
|
28
docker-compose.tor.yml
Normal file
28
docker-compose.tor.yml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
services:
|
||||||
|
relay:
|
||||||
|
container_name: wot-relay
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
volumes:
|
||||||
|
- "./db:/app/db"
|
||||||
|
- "./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
|
||||||
|
container_name: wot-relay-tor
|
||||||
|
depends_on:
|
||||||
|
- relay
|
||||||
|
volumes:
|
||||||
|
- ./tor/torrc:/etc/tor/torrc
|
||||||
|
- ./tor/data:/var/lib/tor
|
||||||
|
restart: on-failure
|
||||||
|
stop_grace_period: 10m30s
|
||||||
|
init: true
|
@ -1,14 +1,16 @@
|
|||||||
services:
|
services:
|
||||||
wot-relay:
|
relay:
|
||||||
|
container_name: wot-relay
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
environment:
|
env_file:
|
||||||
RELAY_NAME: "utxo WoT relay"
|
- .env
|
||||||
RELAY_PUBKEY: "e2ccf7cf20403f3f2a4a55b328f0de3be38558a7d5f33632fdaaefc726c1c8eb"
|
|
||||||
RELAY_DESCRIPTION: "Only notes in utxo WoT"
|
|
||||||
DB_PATH: "./db"
|
|
||||||
volumes:
|
volumes:
|
||||||
- "./db:/app/db"
|
- "./db:/app/db"
|
||||||
|
- "./templates/index.html:${INDEX_PATH}"
|
||||||
|
- "./templates/static:${STATIC_PATH}"
|
||||||
ports:
|
ports:
|
||||||
- "3334:3334"
|
- "3334:3334"
|
||||||
|
restart: unless-stopped
|
||||||
|
init: true
|
||||||
|
67
go.mod
67
go.mod
@ -1,36 +1,55 @@
|
|||||||
module github.com/bitvora/wot-relay
|
module github.com/bitvora/wot-relay
|
||||||
|
|
||||||
go 1.23.0
|
go 1.23.1
|
||||||
|
|
||||||
toolchain go1.23.1
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PowerDNS/lmdb-go v1.9.2 // indirect
|
github.com/fiatjaf/eventstore v0.14.4
|
||||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
github.com/fiatjaf/khatru v0.14.0
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect
|
github.com/nbd-wtf/go-nostr v0.44.2
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
|
)
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
|
||||||
github.com/fasthttp/websocket v1.5.7 // indirect
|
require (
|
||||||
github.com/fiatjaf/eventstore v0.8.1 // indirect
|
fiatjaf.com/lib v0.2.0 // indirect
|
||||||
github.com/fiatjaf/khatru v0.8.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/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.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.11 // indirect
|
||||||
github.com/gobwas/httphead v0.1.0 // indirect
|
github.com/gobwas/httphead v0.1.0 // indirect
|
||||||
github.com/gobwas/pool v0.2.1 // indirect
|
github.com/gobwas/pool v0.2.1 // indirect
|
||||||
github.com/gobwas/ws v1.3.1 // indirect
|
github.com/gobwas/ws v1.4.0 // indirect
|
||||||
github.com/joho/godotenv v1.5.1 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang/glog v1.1.2 // 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 v24.3.25+incompatible // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/klauspost/compress v1.17.8 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/klauspost/compress v1.17.11 // indirect
|
||||||
github.com/nbd-wtf/go-nostr v0.34.14 // 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/puzpuzpuz/xsync/v3 v3.4.0 // indirect
|
||||||
github.com/rs/cors v1.7.0 // indirect
|
github.com/rs/cors v1.11.1 // indirect
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
|
||||||
github.com/tidwall/gjson v1.17.0 // indirect
|
github.com/tidwall/gjson v1.18.0 // indirect
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.1 // indirect
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // 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
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
golang.org/x/net v0.18.0 // indirect
|
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
|
||||||
golang.org/x/sys v0.20.0 // 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
|
||||||
)
|
)
|
||||||
|
287
go.sum
287
go.sum
@ -1,56 +1,175 @@
|
|||||||
github.com/PowerDNS/lmdb-go v1.9.2 h1:Cmgerh9y3ZKBZGz1irxSShhfmFyRUh+Zdk4cZk7ZJvU=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/PowerDNS/lmdb-go v1.9.2/go.mod h1:TE0l+EZK8Z1B4dx070ZxkWTlp8RG1mjN0/+FkFRQMtU=
|
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/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
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/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
|
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM=
|
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
|
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
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/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.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.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=
|
||||||
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
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 h1:0a6o2OfeATvtGgoMKleURhLT6JqWPg7fYfWnH4KHau4=
|
||||||
github.com/fasthttp/websocket v1.5.7/go.mod h1:bC4fxSono9czeXHQUVKxsC0sNjbm7lPJR04GDFqClfU=
|
github.com/fasthttp/websocket v1.5.7/go.mod h1:bC4fxSono9czeXHQUVKxsC0sNjbm7lPJR04GDFqClfU=
|
||||||
github.com/fiatjaf/eventstore v0.5.1 h1:tTh+JYP0RME51VY2QB2Gvtzj6QTaZAnSVhgZtrYqY2A=
|
github.com/fasthttp/websocket v1.5.11 h1:TCO3H2VSxeTJQ+Ij+w8q7UBvdVedMOy/G7aZ0a6V19s=
|
||||||
github.com/fiatjaf/eventstore v0.5.1/go.mod h1:r5yCFmrVNT2b1xUOuMnDVS3xPGh97y8IgTcLyY2rYP8=
|
github.com/fasthttp/websocket v1.5.11/go.mod h1:QWILjDXurHFN5519nH2Pe9rtRuKZ/OIx/rlBF9coYds=
|
||||||
github.com/fiatjaf/eventstore v0.8.1 h1:51LchQNy0Hpb0YQHwqYR5pKBpfDs/KjySlWCbbz2pkc=
|
github.com/fiatjaf/eventstore v0.10.1 h1:zgXrRhpyjzX0Eub4T6zkMZ60zRnIPJqy/Ipfx5h+yWo=
|
||||||
github.com/fiatjaf/eventstore v0.8.1/go.mod h1:bsp0Ibv0CIcVuFcoM2AEerMWmXRhF8uWXMf+dClhuow=
|
github.com/fiatjaf/eventstore v0.10.1/go.mod h1:h5CdLSF7mEQ7/rWpEABTRIrNuFoSwdQDi/nZkW/vVFU=
|
||||||
github.com/fiatjaf/khatru v0.8.0 h1:hofUi4qbSqkJiKD4rC9EyNdi9obzBvp3ykJOBxuu/h8=
|
github.com/fiatjaf/eventstore v0.11.2 h1:gJTATGOk7RtDGt1qs47cLyTzko9phFyXlmWQb0zR7Lg=
|
||||||
github.com/fiatjaf/khatru v0.8.0/go.mod h1:jRmqbbIbEH+y0unt3wMUBwqY/btVussqx5SmBoGhXtg=
|
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 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
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 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
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.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
|
||||||
github.com/gobwas/ws v1.2.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
|
||||||
github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
|
||||||
|
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
|
||||||
|
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=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
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=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
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/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
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 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
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 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
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 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/nbd-wtf/go-nostr v0.34.14 h1:o4n2LkuAtdIjNYJ23sFbcx68UXLnji4j8hYR1Sd2wgI=
|
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||||
github.com/nbd-wtf/go-nostr v0.34.14/go.mod h1:NZQkxl96ggbO8rvDpVjcsojJqKTPwqhP4i82O7K5DJs=
|
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbAaew=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
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.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
|
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/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 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
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 h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
||||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
|
||||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
|
||||||
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
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/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 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
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.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
@ -58,14 +177,104 @@ 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/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 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||||
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
|
github.com/valyala/fasthttp v1.58.0 h1:GGB2dWxSbEprU9j0iMJHgdKYJVDyjrOwF9RE59PbRuE=
|
||||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
github.com/valyala/fasthttp v1.58.0/go.mod h1:SYXvHHaFp7QZHGKSHmoMipInhrI5StHrhDTYVEjK/Kw=
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
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-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=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
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.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=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
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=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
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.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=
|
||||||
|
482
main.go
482
main.go
@ -4,18 +4,26 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fiatjaf/eventstore/lmdb"
|
"github.com/fiatjaf/eventstore"
|
||||||
|
"github.com/fiatjaf/eventstore/badger"
|
||||||
"github.com/fiatjaf/khatru"
|
"github.com/fiatjaf/khatru"
|
||||||
|
"github.com/fiatjaf/khatru/policies"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"github.com/nbd-wtf/go-nostr"
|
"github.com/nbd-wtf/go-nostr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
version string
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
RelayName string
|
RelayName string
|
||||||
RelayPubkey string
|
RelayPubkey string
|
||||||
@ -24,59 +32,109 @@ type Config struct {
|
|||||||
RelayURL string
|
RelayURL string
|
||||||
IndexPath string
|
IndexPath string
|
||||||
StaticPath string
|
StaticPath string
|
||||||
|
RefreshInterval int
|
||||||
|
MinimumFollowers int
|
||||||
|
ArchivalSync bool
|
||||||
|
RelayContact string
|
||||||
|
RelayIcon string
|
||||||
|
MaxAgeDays int
|
||||||
|
ArchiveReactions bool
|
||||||
|
IgnoredPubkeys []string
|
||||||
}
|
}
|
||||||
|
|
||||||
var archivePool *nostr.SimplePool
|
var pool *nostr.SimplePool
|
||||||
var fetchingPool *nostr.SimplePool
|
var wdb nostr.RelayStore
|
||||||
|
|
||||||
var relays []string
|
var relays []string
|
||||||
var config Config
|
var config Config
|
||||||
var trustNetwork []string
|
var trustNetwork []string
|
||||||
var mu 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() {
|
func main() {
|
||||||
fmt.Println("starting")
|
nostr.InfoLogger = log.New(io.Discard, "", 0)
|
||||||
|
booted = false
|
||||||
|
green := "\033[32m"
|
||||||
|
reset := "\033[0m"
|
||||||
|
|
||||||
|
art := `
|
||||||
|
888 888 88888888888 8888888b. 888
|
||||||
|
888 o 888 888 888 Y88b 888
|
||||||
|
888 d8b 888 888 888 888 888
|
||||||
|
888 d888b 888 .d88b. 888 888 d88P .d88b. 888 8888b. 888 888
|
||||||
|
888d88888b888 d88""88b 888 8888888P" d8P Y8b 888 "88b 888 888
|
||||||
|
88888P Y88888 888 888 888 888 T88b 88888888 888 .d888888 888 888
|
||||||
|
8888P Y8888 Y88..88P 888 888 T88b Y8b. 888 888 888 Y88b 888
|
||||||
|
888P Y888 "Y88P" 888 888 T88b "Y8888 888 "Y888888 "Y88888
|
||||||
|
888
|
||||||
|
Y8b d88P
|
||||||
|
powered by: khatru "Y88P"
|
||||||
|
`
|
||||||
|
|
||||||
|
fmt.Println(green + art + reset)
|
||||||
|
log.Println("🚀 booting up web of trust relay")
|
||||||
relay := khatru.NewRelay()
|
relay := khatru.NewRelay()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
pool = nostr.NewSimplePool(ctx)
|
||||||
config = LoadConfig()
|
config = LoadConfig()
|
||||||
|
|
||||||
relay.Info.Name = config.RelayName
|
relay.Info.Name = config.RelayName
|
||||||
relay.Info.PubKey = config.RelayPubkey
|
relay.Info.PubKey = config.RelayPubkey
|
||||||
|
relay.Info.Icon = config.RelayIcon
|
||||||
|
relay.Info.Contact = config.RelayContact
|
||||||
relay.Info.Description = config.RelayDescription
|
relay.Info.Description = config.RelayDescription
|
||||||
|
relay.Info.Software = "https://github.com/bitvora/wot-relay"
|
||||||
|
relay.Info.Version = version
|
||||||
|
|
||||||
appendPubkey(config.RelayPubkey)
|
appendPubkey(config.RelayPubkey)
|
||||||
|
|
||||||
db := lmdb.LMDBBackend{
|
db := getDB()
|
||||||
Path: getEnv("DB_PATH"),
|
|
||||||
}
|
|
||||||
if err := db.Init(); err != nil {
|
if err := db.Init(); err != nil {
|
||||||
panic(err)
|
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.StoreEvent = append(relay.StoreEvent, db.SaveEvent)
|
||||||
relay.QueryEvents = append(relay.QueryEvents, db.QueryEvents)
|
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) {
|
relay.RejectEvent = append(relay.RejectEvent, func(ctx context.Context, event *nostr.Event) (bool, string) {
|
||||||
for _, pk := range trustNetwork {
|
if !trustNetworkMap[event.PubKey] {
|
||||||
if pk == event.PubKey {
|
return true, "we are rebuilding the trust network, please try again later"
|
||||||
|
}
|
||||||
|
if event.Kind == nostr.KindEncryptedDirectMessage {
|
||||||
|
return true, "only gift wrapped DMs are allowed"
|
||||||
|
}
|
||||||
|
|
||||||
return false, ""
|
return false, ""
|
||||||
}
|
|
||||||
}
|
|
||||||
return true, "you are not in the web of trust"
|
|
||||||
})
|
})
|
||||||
|
|
||||||
mu.Lock()
|
seedRelays = []string{
|
||||||
relays = []string{
|
|
||||||
"wss://nos.lol",
|
"wss://nos.lol",
|
||||||
"wss://nostr.mom",
|
"wss://nostr.mom",
|
||||||
"wss://purplepag.es",
|
"wss://purplepag.es",
|
||||||
"wss://purplerelay.com",
|
"wss://purplerelay.com",
|
||||||
"wss://relay.damus.io",
|
"wss://relay.damus.io",
|
||||||
"wss://relay.mostr.pub",
|
|
||||||
"wss://relay.nos.social",
|
|
||||||
"wss://relay.nostr.band",
|
"wss://relay.nostr.band",
|
||||||
"wss://relay.snort.social",
|
"wss://relay.snort.social",
|
||||||
"wss://relayable.org",
|
"wss://relayable.org",
|
||||||
"wss://pyramid.fiatjaf.com",
|
|
||||||
"wss://relay.primal.net",
|
"wss://relay.primal.net",
|
||||||
"wss://relay.nostr.bg",
|
"wss://relay.nostr.bg",
|
||||||
"wss://no.str.cr",
|
"wss://no.str.cr",
|
||||||
@ -84,12 +142,15 @@ func main() {
|
|||||||
"wss://nostrue.com",
|
"wss://nostrue.com",
|
||||||
"wss://relay.siamstr.com",
|
"wss://relay.siamstr.com",
|
||||||
}
|
}
|
||||||
mu.Unlock()
|
|
||||||
|
|
||||||
go refreshTrustNetwork(relay, ctx)
|
go refreshTrustNetwork(ctx, relay)
|
||||||
go archiveTrustedNotes(relay, ctx)
|
|
||||||
|
|
||||||
mux := relay.Router()
|
mux := relay.Router()
|
||||||
|
static := http.FileServer(http.Dir(config.StaticPath))
|
||||||
|
|
||||||
|
mux.Handle("GET /static/", http.StripPrefix("/static/", static))
|
||||||
|
mux.Handle("GET /favicon.ico", http.StripPrefix("/", static))
|
||||||
|
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
tmpl := template.Must(template.ParseFiles(os.Getenv("INDEX_PATH")))
|
tmpl := template.Must(template.ParseFiles(os.Getenv("INDEX_PATH")))
|
||||||
data := struct {
|
data := struct {
|
||||||
@ -109,9 +170,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("/favicon.ico", http.StripPrefix("/", http.FileServer(http.Dir(config.StaticPath))))
|
log.Println("🎉 relay running on port :3334")
|
||||||
|
|
||||||
fmt.Println("running on :3334")
|
|
||||||
err := http.ListenAndServe(":3334", relay)
|
err := http.ListenAndServe(":3334", relay)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -119,19 +178,63 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LoadConfig() Config {
|
func LoadConfig() Config {
|
||||||
err := godotenv.Load(".env")
|
godotenv.Load(".env")
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error loading .env file")
|
if os.Getenv("REFRESH_INTERVAL_HOURS") == "" {
|
||||||
|
os.Setenv("REFRESH_INTERVAL_HOURS", "3")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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{
|
config := Config{
|
||||||
RelayName: getEnv("RELAY_NAME"),
|
RelayName: getEnv("RELAY_NAME"),
|
||||||
RelayPubkey: getEnv("RELAY_PUBKEY"),
|
RelayPubkey: getEnv("RELAY_PUBKEY"),
|
||||||
RelayDescription: getEnv("RELAY_DESCRIPTION"),
|
RelayDescription: getEnv("RELAY_DESCRIPTION"),
|
||||||
|
RelayContact: getEnv("RELAY_CONTACT"),
|
||||||
|
RelayIcon: getEnv("RELAY_ICON"),
|
||||||
DBPath: getEnv("DB_PATH"),
|
DBPath: getEnv("DB_PATH"),
|
||||||
RelayURL: getEnv("RELAY_URL"),
|
RelayURL: getEnv("RELAY_URL"),
|
||||||
IndexPath: getEnv("INDEX_PATH"),
|
IndexPath: getEnv("INDEX_PATH"),
|
||||||
StaticPath: getEnv("STATIC_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
|
return config
|
||||||
@ -145,118 +248,165 @@ func getEnv(key string) string {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) []string {
|
func updateTrustNetworkFilter() {
|
||||||
fetchingPool = nostr.NewSimplePool(ctx)
|
trustNetworkMap = make(map[string]bool)
|
||||||
|
|
||||||
|
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 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) {
|
||||||
|
|
||||||
// Function to refresh the trust network
|
|
||||||
runTrustNetworkRefresh := func() {
|
runTrustNetworkRefresh := func() {
|
||||||
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
filters := []nostr.Filter{{
|
filters := []nostr.Filter{{
|
||||||
Authors: []string{config.RelayPubkey},
|
Authors: []string{config.RelayPubkey},
|
||||||
Kinds: []int{nostr.KindContactList},
|
Kinds: []int{nostr.KindFollowList},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for ev := range fetchingPool.SubManyEose(timeoutCtx, relays, filters) {
|
log.Println("🔍 fetching owner's follows")
|
||||||
|
for ev := range pool.SubManyEose(timeoutCtx, seedRelays, filters) {
|
||||||
for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) {
|
for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) {
|
||||||
appendPubkey(contact[1])
|
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])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chunks := make([][]string, 0)
|
log.Println("🌐 building web of trust graph")
|
||||||
for i := 0; i < len(trustNetwork); i += 100 {
|
for i := 0; i < len(oneHopNetwork); i += 100 {
|
||||||
|
timeout, cancel := context.WithTimeout(ctx, 4*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
end := i + 100
|
end := i + 100
|
||||||
if end > len(trustNetwork) {
|
if end > len(oneHopNetwork) {
|
||||||
end = len(trustNetwork)
|
end = len(oneHopNetwork)
|
||||||
}
|
}
|
||||||
chunks = append(chunks, trustNetwork[i:end])
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, chunk := range chunks {
|
|
||||||
threeTimeoutCtx, tenCancel := context.WithTimeout(ctx, 10*time.Second)
|
|
||||||
defer tenCancel()
|
|
||||||
|
|
||||||
filters = []nostr.Filter{{
|
filters = []nostr.Filter{{
|
||||||
Authors: chunk,
|
Authors: oneHopNetwork[i:end],
|
||||||
Kinds: []int{nostr.KindContactList},
|
Kinds: []int{nostr.KindFollowList, nostr.KindRelayListMetadata, nostr.KindProfileMetadata},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for ev := range fetchingPool.SubManyEose(threeTimeoutCtx, relays, filters) {
|
for ev := range pool.SubManyEose(timeout, seedRelays, filters) {
|
||||||
for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) {
|
for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) {
|
||||||
if len(contact) > 1 {
|
if len(contact) > 1 {
|
||||||
appendPubkey(contact[1])
|
pubkeyFollowerCount[contact[1]]++ // Increment follower count for the pubkey
|
||||||
} else {
|
|
||||||
fmt.Println("Skipping malformed tag: ", contact)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("trust network size:", len(trustNetwork))
|
for _, relay := range ev.Event.Tags.GetAll([]string{"r"}) {
|
||||||
getTrustNetworkProfileMetadata(relay, ctx)
|
appendRelay(relay[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ev.Event.Kind == nostr.KindProfileMetadata {
|
||||||
|
wdb.Publish(ctx, *ev.Event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Println("🫂 total network size:", len(pubkeyFollowerCount))
|
||||||
|
log.Println("🔗 relays discovered:", len(relays))
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
runTrustNetworkRefresh()
|
runTrustNetworkRefresh()
|
||||||
|
updateTrustNetworkFilter()
|
||||||
ticker := time.NewTicker(10 * time.Minute)
|
deleteOldNotes(relay)
|
||||||
defer ticker.Stop()
|
archiveTrustedNotes(ctx, relay)
|
||||||
|
|
||||||
for range ticker.C {
|
|
||||||
runTrustNetworkRefresh()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return trustNetwork
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTrustNetworkProfileMetadata(relay *khatru.Relay, ctx context.Context) {
|
func appendRelay(relay string) {
|
||||||
chunks := make([][]string, 0)
|
|
||||||
for i := 0; i < len(trustNetwork); i += 100 {
|
|
||||||
end := i + 100
|
|
||||||
if end > len(trustNetwork) {
|
|
||||||
end = len(trustNetwork)
|
|
||||||
}
|
|
||||||
chunks = append(chunks, trustNetwork[i:end])
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, chunk := range chunks {
|
for _, r := range relays {
|
||||||
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
if r == relay {
|
||||||
defer cancel()
|
return
|
||||||
filters := []nostr.Filter{{
|
|
||||||
Authors: chunk,
|
|
||||||
Kinds: []int{nostr.KindProfileMetadata},
|
|
||||||
}}
|
|
||||||
|
|
||||||
for ev := range fetchingPool.SubManyEose(timeoutCtx, relays, filters) {
|
|
||||||
relay.AddEvent(ctx, ev.Event)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
relays = append(relays, relay)
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendPubkey(pubkey string) {
|
func appendPubkey(pubkey string) {
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
|
|
||||||
for _, pk := range trustNetwork {
|
for _, pk := range trustNetwork {
|
||||||
if pk == pubkey {
|
if pk == pubkey {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(pubkey) != 64 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
trustNetwork = append(trustNetwork, pubkey)
|
trustNetwork = append(trustNetwork, pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) {
|
func appendOneHopNetwork(pubkey string) {
|
||||||
ticker := time.NewTicker(1 * time.Minute)
|
for _, pk := range oneHopNetwork {
|
||||||
defer ticker.Stop()
|
if pk == pubkey {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
archivePool = nostr.NewSimplePool(ctx)
|
if len(pubkey) != 64 {
|
||||||
for range ticker.C {
|
return
|
||||||
timeout, cancel := context.WithTimeout(ctx, 58*time.Second)
|
}
|
||||||
filters := []nostr.Filter{{
|
|
||||||
|
oneHopNetwork = append(oneHopNetwork, pubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func archiveTrustedNotes(ctx context.Context, relay *khatru.Relay) {
|
||||||
|
timeout, cancel := context.WithTimeout(ctx, time.Duration(config.RefreshInterval)*time.Hour)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if config.ArchivalSync {
|
||||||
|
go refreshProfiles(ctx)
|
||||||
|
|
||||||
|
var filters []nostr.Filter
|
||||||
|
if config.ArchiveReactions {
|
||||||
|
|
||||||
|
filters = []nostr.Filter{{
|
||||||
Kinds: []int{
|
Kinds: []int{
|
||||||
nostr.KindArticle,
|
nostr.KindArticle,
|
||||||
nostr.KindDeletion,
|
nostr.KindDeletion,
|
||||||
nostr.KindContactList,
|
nostr.KindFollowList,
|
||||||
nostr.KindEncryptedDirectMessage,
|
nostr.KindEncryptedDirectMessage,
|
||||||
nostr.KindMuteList,
|
nostr.KindMuteList,
|
||||||
nostr.KindReaction,
|
nostr.KindReaction,
|
||||||
@ -267,21 +417,139 @@ func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) {
|
|||||||
nostr.KindTextNote,
|
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,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
for ev := range archivePool.SubManyEose(timeout, relays, filters) {
|
log.Println("📦 archiving trusted notes...")
|
||||||
for _, trustedPubkey := range trustNetwork {
|
|
||||||
if ev.Event.PubKey == trustedPubkey {
|
for ev := range pool.SubMany(timeout, seedRelays, filters) {
|
||||||
if ev.Event.Kind == nostr.KindContactList {
|
go archiveEvent(ctx, relay, *ev.Event)
|
||||||
if len(ev.Event.Tags.GetAll([]string{"p"})) > 2000 {
|
}
|
||||||
fmt.Println("archiveTrustedNotes: skipping contact list with more than 2000 contacts. NoteID: ", ev.Event.ID)
|
|
||||||
continue
|
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():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
relay.AddEvent(ctx, ev.Event)
|
|
||||||
fmt.Println("archived trusted note: ", ev.Event.ID)
|
close(done)
|
||||||
}
|
}()
|
||||||
}
|
|
||||||
}
|
select {
|
||||||
cancel()
|
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.KindFollowList,
|
||||||
|
nostr.KindEncryptedDirectMessage,
|
||||||
|
nostr.KindMuteList,
|
||||||
|
nostr.KindReaction,
|
||||||
|
nostr.KindRelayListMetadata,
|
||||||
|
nostr.KindRepost,
|
||||||
|
nostr.KindZapRequest,
|
||||||
|
nostr.KindZap,
|
||||||
|
nostr.KindTextNote,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ch, err := relay.QueryEvents[0](ctx, filter)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("query error %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
events := make([]*nostr.Event, 0)
|
||||||
|
|
||||||
|
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.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 -->
|
||||||
<footer class="text-center py-6 bg-gray-800 w-full">
|
<footer class="text-center py-6 bg-gray-800 w-full">
|
||||||
<p class="text-lg text-gray-400">
|
<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
|
<a
|
||||||
href="https://khatru.nostr.technology/"
|
href="https://khatru.nostr.technology/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
2
tor/data/.gitignore
vendored
Normal file
2
tor/data/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
Loading…
x
Reference in New Issue
Block a user