tangled
alpha
login
or
join now
rocksky.app
/
rocksky
96
fork
atom
A decentralized music tracking and discovery platform built on AT Protocol 🎵
rocksky.app
spotify
atproto
lastfm
musicbrainz
scrobbling
listenbrainz
96
fork
atom
overview
issues
7
pulls
pipelines
Add webhook service, Dockerfile and admin auth
tsiry-sandratraina.com
1 month ago
ee49ebfa
00c4d15f
+31
-1
4 changed files
expand all
collapse all
unified
split
tap
.dockerignore
Dockerfile
compose.yaml
src
main.ts
+6
tap/.dockerignore
···
1
1
+
.env
2
2
+
data/
3
3
+
*.db
4
4
+
*.db-shm
5
5
+
*.db-wal
6
6
+
node_modules/
+11
tap/Dockerfile
···
1
1
+
FROM denoland/deno:2.6.5
2
2
+
3
3
+
WORKDIR /app
4
4
+
5
5
+
COPY . .
6
6
+
7
7
+
RUN deno cache src/main.ts
8
8
+
9
9
+
EXPOSE 2481
10
10
+
11
11
+
CMD ["run", "-A", "src/main.ts"]
+6
tap/compose.yaml
···
9
9
environment:
10
10
TAP_DATABASE_URL: sqlite:///data/tap.db
11
11
TAP_RELAY_URL: https://relay1.us-east.bsky.network
12
12
+
TAP_WEBHOOK_URL: http://webhook:2481
12
13
TAP_SIGNAL_COLLECTION: app.rocksky.scrobble
13
14
TAP_COLLECTION_FILTERS: app.rocksky.graph.follow,app.rocksky.*
15
15
+
webhook:
16
16
+
build: .
17
17
+
restart: always
18
18
+
ports:
19
19
+
- "2481:2481"
+8
-1
tap/src/main.ts
···
4
4
import { asc, inArray } from "drizzle-orm";
5
5
import { omit } from "@es-toolkit/es-toolkit/compat";
6
6
import type { SelectEvent } from "./schema/event.ts";
7
7
-
import { parseTapEvent } from "@atproto/tap";
7
7
+
import { assureAdminAuth, parseTapEvent } from "@atproto/tap";
8
8
import { addToBatch, flushBatch } from "./batch.ts";
9
9
10
10
const PAGE_SIZE = 100;
11
11
const YIELD_EVERY_N_PAGES = 5;
12
12
const YIELD_DELAY_MS = 100;
13
13
+
const ADMIN_PASSWORD = Deno.env.get("TAP_ADMIN_PASSWORD")!;
13
14
14
15
interface ClientState {
15
16
socket: WebSocket;
···
71
72
72
73
Deno.serve({ port: parseInt(Deno.env.get("WS_PORT") || "2481") }, (req) => {
73
74
if (req.method === "POST") {
75
75
+
try {
76
76
+
assureAdminAuth(ADMIN_PASSWORD, req.headers.get("authorization")!);
77
77
+
} catch {
78
78
+
logger.warn`Unauthorized access attempt ${req.headers.get("authorization")}`;
79
79
+
return new Response(null, { status: 401 });
80
80
+
}
74
81
const evt = parseTapEvent(req.body);
75
82
switch (evt.type) {
76
83
case "identity": {