Skip to content

Commit 28027d8

Browse files
authored
Merge pull request #13 from zetroot/feature/persist-observes
Persist observations in database +semver: breaking
2 parents 4b4963a + 0d6f94e commit 28027d8

Some content is hidden

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

50 files changed

+966
-78
lines changed

.github/workflows/docker.yml

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,14 @@ on:
1212
env:
1313
REGISTRY: ghcr.io
1414
# github.repository as <account>/<repo>
15-
IMAGE_NAME: ${{ github.repository }}
15+
OBSERVER_IMAGE_NAME: "zetroot/ntorspectator-observer"
16+
BUNDLE_IMAGE_NAME: "zetroot/ntorspectator-efbundle"
1617

1718
jobs:
18-
build:
19-
19+
tag-sources:
2020
runs-on: ubuntu-latest
2121
permissions:
2222
contents: write
23-
packages: write
2423

2524
steps:
2625
- name: Checkout repository
@@ -35,14 +34,78 @@ jobs:
3534

3635
- name: Determine Version
3736
uses: gittools/actions/gitversion/execute@v0
38-
37+
3938
- name: Tag commit
4039
if: github.event_name == 'push'
4140
uses: ydataai/create-tag@v1
4241
with:
4342
tag: "${{ env.GitVersion_SemVer }}"
4443
message: "Automated tagging of master commits"
4544

45+
build:
46+
needs: tag-sources
47+
runs-on: ubuntu-latest
48+
permissions:
49+
contents: write
50+
packages: write
51+
52+
steps:
53+
- name: Checkout repository
54+
uses: actions/checkout@v3
55+
56+
- name: Set up QEMU
57+
uses: docker/setup-qemu-action@master
58+
with:
59+
platforms: all
60+
# Workaround: https://github.com/docker/build-push-action/issues/461
61+
- name: Setup Docker buildx
62+
uses: docker/setup-buildx-action@v2
63+
64+
# Login against a Docker registry except on PR
65+
# https://github.com/docker/login-action
66+
- name: Log into registry ${{ env.REGISTRY }}
67+
if: github.event_name != 'pull_request'
68+
uses: docker/login-action@v2
69+
with:
70+
registry: ${{ env.REGISTRY }}
71+
username: ${{ github.actor }}
72+
password: ${{ secrets.GITHUB_TOKEN }}
73+
74+
# Extract metadata (tags, labels) for Docker
75+
# https://github.com/docker/metadata-action
76+
- name: Extract Docker metadata for observer image
77+
id: meta
78+
uses: docker/metadata-action@v4
79+
with:
80+
images: ${{ env.REGISTRY }}/${{ env.OBSERVER_IMAGE_NAME }}
81+
82+
# Build and push Docker image with Buildx (don't push on PR)
83+
# https://github.com/docker/build-push-action
84+
- name: Build and push observer image
85+
id: build-and-push
86+
uses: docker/build-push-action@master
87+
with:
88+
file: Observer.Dockerfile
89+
context: .
90+
platforms: linux/arm64
91+
push: ${{ github.event_name != 'pull_request' }}
92+
tags: ${{ steps.meta.outputs.tags }}
93+
labels: ${{ steps.meta.outputs.labels }}
94+
cache-from: type=gha
95+
cache-to: type=gha,mode=max
96+
97+
98+
bundle:
99+
needs: tag-sources
100+
runs-on: ubuntu-latest
101+
permissions:
102+
contents: write
103+
packages: write
104+
105+
steps:
106+
- name: Checkout repository
107+
uses: actions/checkout@v3
108+
46109
- name: Set up QEMU
47110
uses: docker/setup-qemu-action@master
48111
with:
@@ -63,18 +126,19 @@ jobs:
63126

64127
# Extract metadata (tags, labels) for Docker
65128
# https://github.com/docker/metadata-action
66-
- name: Extract Docker metadata
129+
- name: Extract Docker metadata for bundle image
67130
id: meta
68131
uses: docker/metadata-action@v4
69132
with:
70-
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
133+
images: ${{ env.REGISTRY }}/${{ env.BUNDLE_IMAGE_NAME }}
71134

72135
# Build and push Docker image with Buildx (don't push on PR)
73136
# https://github.com/docker/build-push-action
74-
- name: Build and push Docker image
137+
- name: Build and push bundle image
75138
id: build-and-push
76139
uses: docker/build-push-action@master
77140
with:
141+
file: MigrationBundle.Dockerfile
78142
context: .
79143
platforms: linux/arm64
80144
push: ${{ github.event_name != 'pull_request' }}

.github/workflows/smoke.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
workflow_dispatch:
99

1010
jobs:
11-
build:
11+
smoke-test:
1212
permissions: write-all
1313
runs-on: ubuntu-latest
1414
steps:

Dockerfile

Lines changed: 0 additions & 19 deletions
This file was deleted.

MigrationBundle.Dockerfile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FROM --platform=linux/arm64 mcr.microsoft.com/dotnet/runtime:7.0 AS base
2+
#FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base
3+
WORKDIR /app
4+
5+
FROM mcr.microsoft.com/dotnet/sdk:7.0.102-jammy-amd64 AS build
6+
RUN dotnet tool install --global dotnet-ef
7+
ENV PATH="${PATH}:/root/.dotnet/tools"
8+
WORKDIR /src
9+
COPY ["src/", "./"]
10+
RUN mkdir "/publish"
11+
WORKDIR "/src/NTorSpectator.Database"
12+
RUN dotnet ef migrations bundle -r linux-arm64 -f -o /publish/bundle --verbose
13+
14+
FROM base AS final
15+
WORKDIR /app
16+
COPY --from=build /publish .

NTorSpectator.sln

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NTorSpectator", "NTorSpectator\NTorSpectator.csproj", "{1F4AA365-C2C1-4CEB-B84B-37AF167110F3}"
3+
EndProject
4+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NTorSpectator.Observer", "src\NTorSpectator.Observer\NTorSpectator.Observer.csproj", "{8D938363-29D0-41C1-8C0F-FD89956F7A8F}"
5+
EndProject
6+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0C068D08-CE4D-41B4-A27B-81B25C7AB8FE}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NTorSpectator.Database", "src\NTorSpectator.Database\NTorSpectator.Database.csproj", "{816C35A4-1244-4940-93C6-AB440ADB6363}"
9+
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NTorSpectator.Services", "src\NTorSpectator.Services\NTorSpectator.Services.csproj", "{BBDADD62-DE6E-4F3D-9E72-3B82FC7A8B3E}"
411
EndProject
512
Global
613
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -12,5 +19,22 @@ Global
1219
{1F4AA365-C2C1-4CEB-B84B-37AF167110F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
1320
{1F4AA365-C2C1-4CEB-B84B-37AF167110F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
1421
{1F4AA365-C2C1-4CEB-B84B-37AF167110F3}.Release|Any CPU.Build.0 = Release|Any CPU
22+
{8D938363-29D0-41C1-8C0F-FD89956F7A8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23+
{8D938363-29D0-41C1-8C0F-FD89956F7A8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
24+
{8D938363-29D0-41C1-8C0F-FD89956F7A8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
25+
{8D938363-29D0-41C1-8C0F-FD89956F7A8F}.Release|Any CPU.Build.0 = Release|Any CPU
26+
{816C35A4-1244-4940-93C6-AB440ADB6363}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27+
{816C35A4-1244-4940-93C6-AB440ADB6363}.Debug|Any CPU.Build.0 = Debug|Any CPU
28+
{816C35A4-1244-4940-93C6-AB440ADB6363}.Release|Any CPU.ActiveCfg = Release|Any CPU
29+
{816C35A4-1244-4940-93C6-AB440ADB6363}.Release|Any CPU.Build.0 = Release|Any CPU
30+
{BBDADD62-DE6E-4F3D-9E72-3B82FC7A8B3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31+
{BBDADD62-DE6E-4F3D-9E72-3B82FC7A8B3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
32+
{BBDADD62-DE6E-4F3D-9E72-3B82FC7A8B3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
33+
{BBDADD62-DE6E-4F3D-9E72-3B82FC7A8B3E}.Release|Any CPU.Build.0 = Release|Any CPU
34+
EndGlobalSection
35+
GlobalSection(NestedProjects) = preSolution
36+
{8D938363-29D0-41C1-8C0F-FD89956F7A8F} = {0C068D08-CE4D-41B4-A27B-81B25C7AB8FE}
37+
{816C35A4-1244-4940-93C6-AB440ADB6363} = {0C068D08-CE4D-41B4-A27B-81B25C7AB8FE}
38+
{BBDADD62-DE6E-4F3D-9E72-3B82FC7A8B3E} = {0C068D08-CE4D-41B4-A27B-81B25C7AB8FE}
1539
EndGlobalSection
1640
EndGlobal

NTorSpectator/Mastodon/IReporter.cs

Lines changed: 0 additions & 8 deletions
This file was deleted.

Observer.Dockerfile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
FROM --platform=linux/arm64 mcr.microsoft.com/dotnet/aspnet:7.0-jammy-arm64v8 AS base
2+
WORKDIR /app
3+
EXPOSE 8000
4+
5+
FROM mcr.microsoft.com/dotnet/sdk:7.0.102-jammy-amd64 AS build
6+
WORKDIR /src
7+
COPY ["src/NTorSpectator.Database/NTorSpectator.Database.csproj", "NTorSpectator.Database/"]
8+
COPY ["src/NTorSpectator.Services/NTorSpectator.Services.csproj", "NTorSpectator.Services/"]
9+
COPY ["src/NTorSpectator.Observer/NTorSpectator.Observer.csproj", "NTorSpectator.Observer/"]
10+
RUN dotnet restore -r linux-arm64 "NTorSpectator.Observer/NTorSpectator.Observer.csproj"
11+
COPY /src .
12+
WORKDIR "/src/NTorSpectator.Observer"
13+
RUN dotnet build -r linux-arm64 --no-self-contained --no-restore "NTorSpectator.Observer.csproj" -c Release -o /app/build
14+
15+
FROM build AS publish
16+
RUN dotnet publish "NTorSpectator.Observer.csproj" -c Release -o /app/publish -r linux-arm64 --no-self-contained
17+
18+
FROM base AS final
19+
WORKDIR /app
20+
COPY --from=publish /app/publish .
21+
ENTRYPOINT ["dotnet", "NTorSpectator.Observer.dll"]

README.md

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ This is a small bot to have fun with several things:
44
- Tor daemon interaction
55
- Mastodon posting
66

7-
This small thing starts and tries to get service descriptors for sites mentioned in `sites.txt`. If hidden service descriptor received - the site is marked as up. Else - down. That's simple.
7+
This small bot loads sites from `sites.txt` into database and tries to get descriptors for them. If hidden service descriptor received - the site is marked as up. Else - down. That's simple.
88

99
## Where is the bot
1010

11-
Follow the bot on mastodon. Staging account is [devmacaca@botsin.space](https://botsin.space/@devmacaca)
11+
Follow the bot on mastodon [ntorspectator@botsin.space](https://botsin.space/@ntorspectator)
1212

1313
## Prerequisites
1414

15-
There are some prerequisites for set up. You need Tor deamon running to request hidden service descriptors, you will need a mastodon account to post collected statuses and you'd better have Seq to collect logs from application.
15+
There are some prerequisites for set up. You need Tor deamon running to request hidden service descriptors, you will need a mastodon account to post collected statuses and you'd better have Seq to collect logs from application. All collected data is stored in Postgresql, so you will need it too.
1616

1717
### Tor daemon
1818

@@ -28,21 +28,31 @@ Also, save information on toot length on this instance. It will be used in confi
2828

2929
Logging to console is great, but i prefer seq for pet projects. It is small, fast, reliable, painless log collector. The Seq Serilog sink is already built in NTorSpectator, pointing to `http://seq:5341`
3030

31+
### PostgreSQL
32+
33+
Database will run in container, for easier maintanence and setup, but you can run it wherever you want.
34+
3135
## Setup
3236

33-
The best way to run applications is docker compose. So the sample file looks like this:
37+
The best way to run applications is docker compose. Try change my mind. So the sample file looks like this:
3438

3539
```yaml
3640
version: "3"
3741

38-
services:
42+
services:
3943
tor_spectator:
40-
image: ghcr.io/zetroot/ntorspectator:latest
44+
image: ghcr.io/zetroot/ntorspectator-observer:master
4145
platform: linux/arm64
4246
restart: always
4347
depends_on:
4448
seq:
4549
condition: service_started
50+
database:
51+
condition: service_healthy
52+
migrator:
53+
condition: service_completed_successfully
54+
ports:
55+
- 81:8000
4656
container_name: ntorspectator
4757
environment:
4858
- ASPNETCORE_ENVIRONMENT=Production # this is production environment, is not it?
@@ -51,7 +61,16 @@ services:
5161
- "./appsettings.Production.json:/app/appsettings.Production.json" # mount production config into app folder
5262
- "/run/tor/control:/run/tor/control" # also mount tor unix-socket
5363
- "/run/tor/control.authcookie:/run/tor/control.authcookie" # and not forget about auth cookie
54-
64+
65+
migrator:
66+
image: ghcr.io/zetroot/ntorspectator-efbundle:master
67+
depends_on:
68+
database:
69+
condition: service_healthy
70+
platform: linux/arm64
71+
restart: no
72+
command: /app/bundle --connection "Server=pgdb;Port=5432;Database=ntorspectator;User Id=postgres;Password=password" # connection string to database to apply migrations
73+
5574
seq:
5675
image: datalust/seq:latest
5776
container_name: seq_torspec
@@ -64,6 +83,26 @@ services:
6483
- "5342:5341"
6584
environment:
6685
- ACCEPT_EULA=Y
86+
87+
database:
88+
image: 'postgres:15'
89+
container_name: pg_torspec
90+
hostname: pgdb
91+
user: postgres
92+
healthcheck:
93+
test: ["CMD-SHELL", "pg_isready"]
94+
interval: 1s
95+
timeout: 5s
96+
retries: 10
97+
ports:
98+
- 5432:5432
99+
environment:
100+
- POSTGRES_USER=postgres # The PostgreSQL user (useful to connect to the database)
101+
- POSTGRES_PASSWORD=password # The PostgreSQL password (useful to connect to the database)
102+
- POSTGRES_DB=postgres # The PostgreSQL default database (automatically created at first launch)
103+
volumes:
104+
- "./db-data/:/var/lib/postgresql/data/"
105+
67106
```
68107

69108
`Sites.txt` is a file with tor onion links, one at a line:
@@ -78,6 +117,9 @@ hzwjmjimhr7bdmfv.........ibt5ojjmpo3pbp5ctwcg37n3hyk7qzid.onion
78117
And provide production config in `appsettings.Production.json`:
79118
```json
80119
{
120+
"ConnectionStrings": {
121+
"SpectatorDatabase":"Server=pgdb;Port=5432;Database=ntorspectator;User Id=postgres;Password=password;"
122+
},
81123
"MastodonSettings" : {
82124
"Instance" : "https://your.cool.mastodon.instance.prod",
83125
"Token": "YourSuperSecretApiTokenGoesHere"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
3+
using NTorSpectator.Database.Models;
4+
5+
namespace NTorSpectator.Database.Configuration;
6+
7+
internal class ObservationEntityConfiguration : IEntityTypeConfiguration<Observation>
8+
{
9+
public void Configure(EntityTypeBuilder<Observation> builder)
10+
{
11+
builder.ToTable("observations");
12+
builder.HasKey(x => x.Id);
13+
builder.HasIndex(x => x.ObservedAt);
14+
builder.HasIndex(x => x.SiteId);
15+
16+
builder.HasOne(x => x.Site).WithMany().HasForeignKey(x => x.SiteId).OnDelete(DeleteBehavior.Restrict);
17+
}
18+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
3+
using NTorSpectator.Database.Models;
4+
5+
namespace NTorSpectator.Database.Configuration;
6+
7+
internal class SiteEntityConfiguration : IEntityTypeConfiguration<Site>
8+
{
9+
public void Configure(EntityTypeBuilder<Site> builder)
10+
{
11+
builder.ToTable("sites");
12+
builder.HasKey(x => x.Id);
13+
builder.HasIndex(x => x.SiteUri);
14+
}
15+
}

0 commit comments

Comments
 (0)