From cdd2c375608139ca5e166cff5daa7225b1538711 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 17 Oct 2024 02:44:17 +0200 Subject: [PATCH 1/8] Add `jsr:@logtape/logtape@^0.6.3` dependency --- deno.json | 1 + deno.lock | 1 + 2 files changed, 2 insertions(+) diff --git a/deno.json b/deno.json index 62ec572..b9438cd 100644 --- a/deno.json +++ b/deno.json @@ -5,6 +5,7 @@ "imports": { "@fedify/fedify": "jsr:@fedify/fedify@^1.0.2", "@fedify/redis": "jsr:@fedify/redis@^0.3.0", + "@logtape/logtape": "jsr:@logtape/logtape@^0.6.3", "@std/assert": "jsr:@std/assert@1", "ioredis": "npm:ioredis@^5.4.1" }, diff --git a/deno.lock b/deno.lock index 86beb42..13359fc 100644 --- a/deno.lock +++ b/deno.lock @@ -348,6 +348,7 @@ "dependencies": [ "jsr:@fedify/fedify@^1.0.2", "jsr:@fedify/redis@^0.3.0", + "jsr:@logtape/logtape@^0.6.3", "jsr:@std/assert@1", "npm:ioredis@^5.4.1" ] -- 2.45.2 From dbf7f6d49f7c07955e41988321df3b9d1c6b9a9e Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 17 Oct 2024 02:46:08 +0200 Subject: [PATCH 2/8] Auto-reformat code from now on --- src/main.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main.ts b/src/main.ts index b6c6041..470acc6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,12 +1,12 @@ import {createFederation} from "@fedify/fedify" import {RedisKvStore} from "https://jsr.io/@fedify/redis/0.3.0/src/kv.ts" -import {Redis} from "ioredis"; +import {Redis} from "ioredis" const federation = createFederation({ kv: new RedisKvStore( new Redis({}), - {} + {}, ), }); @@ -15,16 +15,15 @@ const handler: Deno.ServeHandler = function handler(request) { request, { contextData: undefined, - } - ) + }, + ); return response -} - +}; Deno.serve( { - port: 8080 + port: 8080, }, - handler -) + handler, +); -- 2.45.2 From 25fad11afb331868423c3649cb3d6d06a8c01d45 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 17 Oct 2024 02:55:32 +0200 Subject: [PATCH 3/8] Setup logging --- src/main.ts | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/main.ts b/src/main.ts index 470acc6..356e6d6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,15 +1,31 @@ import {createFederation} from "@fedify/fedify" +import {configure, getConsoleSink, getLogger} from "@logtape/logtape" import {RedisKvStore} from "https://jsr.io/@fedify/redis/0.3.0/src/kv.ts" import {Redis} from "ioredis" -const federation = createFederation({ - kv: new RedisKvStore( - new Redis({}), - {}, - ), +await configure({ + sinks: {console: getConsoleSink()}, + filters: {}, + loggers: [ + {category: ["logtape", "meta"], sinks: ["console"], level: "warning"}, + {category: ["fedify"], sinks: ["console"], level: "info"}, + {category: ["dotino-veloce"], sinks: ["console"], level: "debug"}, + ], }); +const l = getLogger(["dotino-veloce", "main"]) + +l.debug`Creating redis object...` +const redis = new Redis({}) + +l.debug`Creating federation object...` +const kv = new RedisKvStore(redis, {}) + +l.debug`Creating federation object...` +const federation = createFederation({kv}) + +l.debug`Creating Deno handler...` const handler: Deno.ServeHandler = function handler(request) { const response = federation.fetch( request, @@ -21,9 +37,12 @@ const handler: Deno.ServeHandler = function handler(request) { return response }; +l.info`Starting server...` Deno.serve( { port: 8080, + onListen: (_localAddr) => { + }, }, handler, ); -- 2.45.2 From 1310f4a4a4373cd37af7ec236da7bf4dec6579a2 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 17 Oct 2024 03:03:30 +0200 Subject: [PATCH 4/8] Configure lint rules --- deno.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/deno.json b/deno.json index b9438cd..5cbf232 100644 --- a/deno.json +++ b/deno.json @@ -11,5 +11,15 @@ }, "unstable": [ "temporal" - ] + ], + "lint": { + "rules": { + "exclude": [ + "no-implicit-any", + "no-explicit-any", + "no-inner-declarations", + "no-var" + ] + } + } } -- 2.45.2 From 88c68122a605406c6c07da01704ac29d370f511d Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 17 Oct 2024 03:04:00 +0200 Subject: [PATCH 5/8] Remove unused task as IntelliJ ignores it anyways --- deno.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/deno.json b/deno.json index 5cbf232..79b104f 100644 --- a/deno.json +++ b/deno.json @@ -1,7 +1,4 @@ { - "tasks": { - "dev": "deno run --watch src/main.ts" - }, "imports": { "@fedify/fedify": "jsr:@fedify/fedify@^1.0.2", "@fedify/redis": "jsr:@fedify/redis@^0.3.0", -- 2.45.2 From c002b0e1d1a145e8741468fc5af1a08d06aee3b1 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 17 Oct 2024 03:46:40 +0200 Subject: [PATCH 6/8] Create basic author dispatcher --- src/main.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index 356e6d6..e619da0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import {createFederation} from "@fedify/fedify" +import {createFederation, Service} from "@fedify/fedify" import {configure, getConsoleSink, getLogger} from "@logtape/logtape" import {RedisKvStore} from "https://jsr.io/@fedify/redis/0.3.0/src/kv.ts" import {Redis} from "ioredis" @@ -25,6 +25,24 @@ const kv = new RedisKvStore(redis, {}) l.debug`Creating federation object...` const federation = createFederation({kv}) +l.debug`Creating actor dispatcher...` +const actorDispatcher = async function actorDispatcher(ctx: any, id: string) { + if(id !== "service") { + return null + } + + return new Service({ + id: ctx.getActorUri(id), + name: "[TEST] Dotino Service", + summary: "Core account of a Dotino Veloce instance.", + preferredUsername: id, + url: new URL("/", ctx.url), + }) +} + +l.debug`Connecting actor dispatcher to federation object...` +federation.setActorDispatcher("/users/{identifier}", actorDispatcher) + l.debug`Creating Deno handler...` const handler: Deno.ServeHandler = function handler(request) { const response = federation.fetch( -- 2.45.2 From 3e7ed401265d1d351e0e647a6bad00281db2da42 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 17 Oct 2024 07:41:28 +0200 Subject: [PATCH 7/8] Add `denoland.vscode-deno` VSCode extension recommendation --- .vscode/extensions.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .vscode/extensions.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..cbbd017 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "denoland.vscode-deno" + ] +} \ No newline at end of file -- 2.45.2 From 2bcc6b54ef109e02af037897c3ba6b703af8ea54 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 17 Oct 2024 23:24:44 +0200 Subject: [PATCH 8/8] Get federation with Akkoma --- deno.json | 55 ++++++++++++++++++++++++++---------------- deno.lock | 16 ++++--------- src/federation.ts | 42 ++++++++++++++++++++++++++++++++ src/handler.ts | 40 +++++++++++++++++++++++++++++++ src/main.ts | 60 +++++++--------------------------------------- src/redis.ts | 11 +++++++++ tests/main_test.ts | 8 +++---- 7 files changed, 145 insertions(+), 87 deletions(-) create mode 100644 src/federation.ts create mode 100644 src/handler.ts create mode 100644 src/redis.ts diff --git a/deno.json b/deno.json index 79b104f..6f1df61 100644 --- a/deno.json +++ b/deno.json @@ -1,22 +1,35 @@ { - "imports": { - "@fedify/fedify": "jsr:@fedify/fedify@^1.0.2", - "@fedify/redis": "jsr:@fedify/redis@^0.3.0", - "@logtape/logtape": "jsr:@logtape/logtape@^0.6.3", - "@std/assert": "jsr:@std/assert@1", - "ioredis": "npm:ioredis@^5.4.1" - }, - "unstable": [ - "temporal" - ], - "lint": { - "rules": { - "exclude": [ - "no-implicit-any", - "no-explicit-any", - "no-inner-declarations", - "no-var" - ] - } - } -} + "imports": { + "@fedify/fedify": "jsr:@fedify/fedify@^1.0.2", + "@fedify/redis": "jsr:@fedify/redis@^0.3.0", + "@logtape/logtape": "jsr:@logtape/logtape@^0.6.3", + "@std/assert": "jsr:@std/assert@1", + "@hongminhee/x-forwarded-fetch": "jsr:@hongminhee/x-forwarded-fetch@^0.2.0", + "@@npm/ioredis": "npm:ioredis@^5.4.1" + }, + "unstable": [ + "temporal" + ], + "lint": { + "rules": { + "exclude": [ + "no-implicit-any", + "no-explicit-any", + "no-inner-declarations", + "no-var" + ] + } + }, + "fmt": { + "include": [ + "src/**", + "tests/**" + ], + "indentWidth": 4, + "lineWidth": 280, + "semiColons": false, + "proseWrap": "never", + "singleQuote": false, + "useTabs": true + } +} \ No newline at end of file diff --git a/deno.lock b/deno.lock index 13359fc..428a561 100644 --- a/deno.lock +++ b/deno.lock @@ -4,15 +4,14 @@ "specifiers": { "jsr:@fedify/fedify@^1.0.2": "jsr:@fedify/fedify@1.0.2", "jsr:@fedify/redis@^0.3.0": "jsr:@fedify/redis@0.3.0", + "jsr:@hongminhee/x-forwarded-fetch@^0.2.0": "jsr:@hongminhee/x-forwarded-fetch@0.2.0", "jsr:@hugoalh/http-header-link@^1.0.2": "jsr:@hugoalh/http-header-link@1.0.2", "jsr:@hugoalh/is-string-singleline@1.0.2": "jsr:@hugoalh/is-string-singleline@1.0.2", "jsr:@logtape/logtape@^0.6.2": "jsr:@logtape/logtape@0.6.3", "jsr:@logtape/logtape@^0.6.3": "jsr:@logtape/logtape@0.6.3", - "jsr:@std/assert@1": "jsr:@std/assert@1.0.6", "jsr:@std/bytes@^1.0.2": "jsr:@std/bytes@1.0.2", "jsr:@std/encoding@^1.0.5": "jsr:@std/encoding@1.0.5", "jsr:@std/http@^1.0.6": "jsr:@std/http@1.0.8", - "jsr:@std/internal@^1.0.4": "jsr:@std/internal@1.0.4", "jsr:@std/semver@^1.0.3": "jsr:@std/semver@1.0.3", "npm:@phensley/language-tag@^1.9.0": "npm:@phensley/language-tag@1.9.0", "npm:asn1js@^3.0.5": "npm:asn1js@3.0.5", @@ -52,6 +51,9 @@ "jsr:@logtape/logtape@^0.6.3" ] }, + "@hongminhee/x-forwarded-fetch@0.2.0": { + "integrity": "8a347e061974e07b480e9461c7d84047e12e92c462fe7679a6f0f59b5c5f48d5" + }, "@hugoalh/http-header-link@1.0.2": { "integrity": "1f607e34ac0790a0b0759f89ade294ab3a1d211e46a8dea337eaafa26950205f", "dependencies": [ @@ -64,12 +66,6 @@ "@logtape/logtape@0.6.3": { "integrity": "64cac3459fddf0455b85d36c8ca3e21764d6b2965c426fb40a0e4a98be436d2b" }, - "@std/assert@1.0.6": { - "integrity": "1904c05806a25d94fe791d6d883b685c9e2dcd60e4f9fc30f4fc5cf010c72207", - "dependencies": [ - "jsr:@std/internal@^1.0.4" - ] - }, "@std/bytes@1.0.2": { "integrity": "fbdee322bbd8c599a6af186a1603b3355e59a5fb1baa139f8f4c3c9a1b3e3d57" }, @@ -79,9 +75,6 @@ "@std/http@1.0.8": { "integrity": "6ea1b2e8d33929967754a3b6d6c6f399ad6647d7bbb5a466c1eaf9b294a6ebcd" }, - "@std/internal@1.0.4": { - "integrity": "62e8e4911527e5e4f307741a795c0b0a9e6958d0b3790716ae71ce085f755422" - }, "@std/semver@1.0.3": { "integrity": "7c139c6076a080eeaa4252c78b95ca5302818d7eafab0470d34cafd9930c13c8" } @@ -348,6 +341,7 @@ "dependencies": [ "jsr:@fedify/fedify@^1.0.2", "jsr:@fedify/redis@^0.3.0", + "jsr:@hongminhee/x-forwarded-fetch@^0.2.0", "jsr:@logtape/logtape@^0.6.3", "jsr:@std/assert@1", "npm:ioredis@^5.4.1" diff --git a/src/federation.ts b/src/federation.ts new file mode 100644 index 0000000..6b4c6d1 --- /dev/null +++ b/src/federation.ts @@ -0,0 +1,42 @@ +import { createFederation, Follow, Service } from "@fedify/fedify" +import { kv } from "./redis.ts" +import { getLogger } from "https://jsr.io/@logtape/logtape/0.6.3/logtape/logger.ts" + +const l = getLogger(["dotino-veloce", "federation"]) + +l.debug`Creating federation object...` +export const federation = createFederation({ kv }) + +l.debug`Creating actor dispatcher...` +// deno-lint-ignore require-await +async function actorDispatcher(ctx: any, handle: string) { + l.debug`Received request for actor ${handle}, handling...` + + if (handle !== "service") { + l.debug`No match found for ${handle}, returning null.` + return null + } + + l.debug`Determining id of actor ${handle}...` + const id = ctx.getActorUri(handle) + + l.info`Returning actor: ${id.href}` + return new Service({ + id, + name: "[TEST] Dotino Veloce", + summary: "Core account of a Dotino Veloce instance.", + preferredUsername: id.href, + // Akkoma expects URL to be equal to ID + // https://akkoma.dev/AkkomaGang/akkoma/src/commit/f1018867097e6f293d8b2b5b6935f0a7ebf99bd0/lib/pleroma/object/fetcher.ex#L287 + url: id, + inbox: ctx.getInboxUri(handle), + }) +} + +l.debug`Connecting actor dispatcher to federation object...` +federation.setActorDispatcher("/users/{identifier}", actorDispatcher) + +// Akkoma requires inboxes to be setup to display profiles +// https://akkoma.dev/AkkomaGang/akkoma/src/commit/f1018867097e6f293d8b2b5b6935f0a7ebf99bd0/lib/pleroma/web/activity_pub/object_validators/user_validator.ex#L72 +l.debug`Initializing inbox listener...` +federation.setInboxListeners("/inbox/{identifier}") // I don't really care about the shared inbox for this project diff --git a/src/handler.ts b/src/handler.ts new file mode 100644 index 0000000..da7fb02 --- /dev/null +++ b/src/handler.ts @@ -0,0 +1,40 @@ +import { getLogger } from "@logtape/logtape" +import { behindProxy, Fetch } from "@hongminhee/x-forwarded-fetch" +import { federation } from "./federation.ts" + +const l = getLogger(["dotino-veloce", "handler"]) + +l.debug`Creating Deno handler...` +function handler(request: Request, _info: Deno.ServeHandlerInfo) { + l.debug`Received a request, processing...` + + const agent = request.headers.get("User-Agent") + const requestUrl = new URL(request.url) + l.debug`Received request from ${agent} to ${requestUrl.href}` + + // Akkoma expects host-meta to be correctly setup + // https://akkoma.dev/AkkomaGang/akkoma/src/commit/f1018867097e6f293d8b2b5b6935f0a7ebf99bd0/lib/pleroma/web/web_finger.ex#L177 + l.debug`Routing request to: ${requestUrl.pathname}` + if (requestUrl.pathname === "/.well-known/host-meta") { + l.debug`Intercepting request to inject host-meta for ${requestUrl.origin}` + return new Response( + ``, + { + headers: { + "Content-Type": "application/xml", + }, + }, + ) + } + + l.debug`Delegating request to Federation...` + return federation.fetch( + request, + { + contextData: undefined, + }, + ) +} + +l.debug`Creating proxyied Deno handler...` +export const proxyHandler: Deno.ServeHandler = behindProxy(handler as Fetch) // Should be good. diff --git a/src/main.ts b/src/main.ts index e619da0..82c2f3a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,60 +1,18 @@ -import {createFederation, Service} from "@fedify/fedify" -import {configure, getConsoleSink, getLogger} from "@logtape/logtape" -import {RedisKvStore} from "https://jsr.io/@fedify/redis/0.3.0/src/kv.ts" -import {Redis} from "ioredis" - +import { configure, getConsoleSink, getLogger } from "@logtape/logtape" +import { proxyHandler } from "./handler.ts" await configure({ - sinks: {console: getConsoleSink()}, + sinks: { console: getConsoleSink() }, filters: {}, loggers: [ - {category: ["logtape", "meta"], sinks: ["console"], level: "warning"}, - {category: ["fedify"], sinks: ["console"], level: "info"}, - {category: ["dotino-veloce"], sinks: ["console"], level: "debug"}, + { category: ["logtape", "meta"], sinks: ["console"], level: "warning" }, + { category: ["fedify"], sinks: ["console"], level: "info" }, + { category: ["dotino-veloce"], sinks: ["console"], level: "debug" }, ], -}); +}) const l = getLogger(["dotino-veloce", "main"]) -l.debug`Creating redis object...` -const redis = new Redis({}) - -l.debug`Creating federation object...` -const kv = new RedisKvStore(redis, {}) - -l.debug`Creating federation object...` -const federation = createFederation({kv}) - -l.debug`Creating actor dispatcher...` -const actorDispatcher = async function actorDispatcher(ctx: any, id: string) { - if(id !== "service") { - return null - } - - return new Service({ - id: ctx.getActorUri(id), - name: "[TEST] Dotino Service", - summary: "Core account of a Dotino Veloce instance.", - preferredUsername: id, - url: new URL("/", ctx.url), - }) -} - -l.debug`Connecting actor dispatcher to federation object...` -federation.setActorDispatcher("/users/{identifier}", actorDispatcher) - -l.debug`Creating Deno handler...` -const handler: Deno.ServeHandler = function handler(request) { - const response = federation.fetch( - request, - { - contextData: undefined, - }, - ); - - return response -}; - l.info`Starting server...` Deno.serve( { @@ -62,5 +20,5 @@ Deno.serve( onListen: (_localAddr) => { }, }, - handler, -); + proxyHandler, +) diff --git a/src/redis.ts b/src/redis.ts new file mode 100644 index 0000000..deae4f9 --- /dev/null +++ b/src/redis.ts @@ -0,0 +1,11 @@ +import { RedisKvStore } from "@fedify/redis" +import { getLogger } from "@logtape/logtape" +import { Redis } from "@@npm/ioredis" + +const l = getLogger(["dotino-veloce", "redis"]) + +l.debug`Creating redis object...` +export const redis = new Redis({}) + +l.debug`Creating federation object...` +export const kv = new RedisKvStore(redis, {}) diff --git a/tests/main_test.ts b/tests/main_test.ts index b2e5c11..93299e9 100644 --- a/tests/main_test.ts +++ b/tests/main_test.ts @@ -1,6 +1,6 @@ -import { assertEquals } from "@std/assert"; -import { add } from "../src/main.ts"; +import { assertEquals } from "@std/assert" +import { add } from "../src/main.ts" Deno.test(function addTest() { - assertEquals(add(2, 3), 5); -}); + assertEquals(add(2, 3), 5) +}) -- 2.45.2