Skip to content

Commit 6da77f9

Browse files
committed
Changed dispatchers to use ctx site and account
ref https://linear.app/ghost/issue/BER-2904 - The middleware already fetches `site` and `account` and sets it in the context variable. This makes dispatchers uses it instead of re-fetching from the database.
1 parent 1b93944 commit 6da77f9

File tree

9 files changed

+101
-98
lines changed

9 files changed

+101
-98
lines changed

src/account/account.entity.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ export interface Account {
2424
readonly bannerImageUrl: URL | null;
2525
readonly apId: URL;
2626
readonly apFollowers: URL | null;
27+
readonly apFollowing: URL | null;
2728
readonly apInbox: URL | null;
29+
readonly apOutbox: URL | null;
30+
readonly apLiked: URL | null;
2831
readonly isInternal: boolean;
2932
readonly customFields: Record<string, string> | null;
3033
unblock(account: Account): Account;
@@ -81,7 +84,10 @@ export class AccountEntity implements Account {
8184
public readonly bannerImageUrl: URL | null,
8285
public readonly apId: URL,
8386
public readonly apFollowers: URL | null,
87+
public readonly apFollowing: URL | null,
8488
public readonly apInbox: URL | null,
89+
public readonly apOutbox: URL | null,
90+
public readonly apLiked: URL | null,
8591
public readonly isInternal: boolean,
8692
public readonly customFields: Record<string, string> | null,
8793
private events: AccountEvent[],
@@ -108,7 +114,10 @@ export class AccountEntity implements Account {
108114
data.bannerImageUrl,
109115
data.apId,
110116
data.apFollowers,
117+
data.apFollowing,
111118
data.apInbox,
119+
data.apOutbox,
120+
data.apLiked,
112121
data.isInternal,
113122
data.customFields,
114123
events,
@@ -128,7 +137,10 @@ export class AccountEntity implements Account {
128137
draft.bannerImageUrl,
129138
draft.apId,
130139
draft.apFollowers,
140+
draft.apFollowing,
131141
draft.apInbox,
142+
draft.apOutbox,
143+
draft.apLiked,
132144
draft.isInternal,
133145
draft.customFields,
134146
events,

src/account/account.repository.knex.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ interface AccountRow {
3131
banner_image_url: string | null;
3232
ap_id: string;
3333
ap_followers_url: string | null;
34+
ap_following_url: string | null;
3435
ap_inbox_url: string | null;
36+
ap_outbox_url: string | null;
37+
ap_liked_url: string | null;
3538
custom_fields: Record<string, string> | null;
3639
site_id: number | null;
3740
}
@@ -376,7 +379,10 @@ export class KnexAccountRepository {
376379
bannerImageUrl: parseURL(row.banner_image_url),
377380
apId: new URL(row.ap_id),
378381
apFollowers: parseURL(row.ap_followers_url),
382+
apFollowing: parseURL(row.ap_following_url),
379383
apInbox: parseURL(row.ap_inbox_url),
384+
apOutbox: parseURL(row.ap_outbox_url),
385+
apLiked: parseURL(row.ap_liked_url),
380386
isInternal: row.site_id !== null,
381387
customFields: row.custom_fields,
382388
});

src/app.ts

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ await configure({
169169
export type ContextData = {
170170
globaldb: KvStore;
171171
logger: Logger;
172+
site?: Site;
173+
account?: Account;
172174
};
173175

174176
// Register all dependencies
@@ -693,20 +695,6 @@ app.use(async (ctx, next) => {
693695
await next();
694696
});
695697

696-
app.use(async (ctx, next) => {
697-
const globaldb = ctx.get('globaldb');
698-
const logger = ctx.get('logger');
699-
700-
const fedifyContext = globalFedify.createContext(ctx.req.raw as Request, {
701-
globaldb,
702-
logger,
703-
});
704-
705-
const fedifyContextFactory = container.resolve<FedifyContextFactory>(
706-
'fedifyContextFactory',
707-
);
708-
await fedifyContextFactory.registerContext(fedifyContext, next);
709-
});
710698
// This needs to go before the middleware which loads the site
711699
// Because the site doesn't always exist - this is how it's created
712700
app.get(
@@ -735,6 +723,25 @@ app.use(
735723
),
736724
);
737725

726+
app.use(async (ctx, next) => {
727+
const globaldb = ctx.get('globaldb');
728+
const logger = ctx.get('logger');
729+
const site = ctx.get('site');
730+
const account = ctx.get('account');
731+
732+
const fedifyContext = globalFedify.createContext(ctx.req.raw as Request, {
733+
globaldb,
734+
logger,
735+
site,
736+
account,
737+
});
738+
739+
const fedifyContextFactory = container.resolve<FedifyContextFactory>(
740+
'fedifyContextFactory',
741+
);
742+
await fedifyContextFactory.registerContext(fedifyContext, next);
743+
});
744+
738745
/** Custom API routes */
739746

740747
const routeRegistry = new RouteRegistry();
@@ -851,6 +858,8 @@ app.use(
851858
return {
852859
globaldb: ctx.get('globaldb'),
853860
logger: ctx.get('logger'),
861+
site: ctx.get('site'),
862+
account: ctx.get('account'),
854863
};
855864
},
856865
),

src/dispatchers.ts

Lines changed: 25 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import {
2626
} from '@fedify/fedify';
2727
import * as Sentry from '@sentry/node';
2828

29-
import type { KnexAccountRepository } from '@/account/account.repository.knex';
3029
import type { AccountService } from '@/account/account.service';
3130
import type { FollowersService } from '@/activitypub/followers.service';
3231
import type { ContextData } from '@/app';
@@ -43,40 +42,34 @@ import type { KnexPostRepository } from '@/post/post.repository.knex';
4342
import type { PostService } from '@/post/post.service';
4443
import type { SiteService } from '@/site/site.service';
4544

46-
export const actorDispatcher = (
47-
siteService: SiteService,
48-
accountService: AccountService,
49-
) =>
45+
export const actorDispatcher = () =>
5046
async function actorDispatcher(
5147
ctx: RequestContext<ContextData>,
5248
identifier: string,
5349
) {
54-
const site = await siteService.getSiteByHost(ctx.host);
55-
if (site === null) return null;
56-
57-
const account = await accountService.getDefaultAccountForSite(site);
50+
const account = ctx.data.account!;
5851

5952
const person = new Person({
60-
id: new URL(account.ap_id),
53+
id: new URL(account.apId),
6154
name: account.name,
6255
summary: account.bio,
6356
preferredUsername: account.username,
64-
icon: account.avatar_url
57+
icon: account.avatarUrl
6558
? new Image({
66-
url: new URL(account.avatar_url),
59+
url: new URL(account.avatarUrl),
6760
})
6861
: null,
69-
image: account.banner_image_url
62+
image: account.bannerImageUrl
7063
? new Image({
71-
url: new URL(account.banner_image_url),
64+
url: new URL(account.bannerImageUrl),
7265
})
7366
: null,
74-
inbox: new URL(account.ap_inbox_url),
75-
outbox: new URL(account.ap_outbox_url),
76-
following: new URL(account.ap_following_url),
77-
followers: new URL(account.ap_followers_url),
78-
liked: new URL(account.ap_liked_url),
79-
url: new URL(account.url || account.ap_id),
67+
inbox: account.apInbox,
68+
outbox: account.apOutbox,
69+
following: account.apFollowing,
70+
followers: account.apFollowers,
71+
liked: account.apLiked,
72+
url: account.url || account.apId,
8073
publicKeys: (await ctx.getActorKeyPairs(identifier)).map(
8174
(key) => key.cryptographicKey,
8275
),
@@ -85,16 +78,13 @@ export const actorDispatcher = (
8578
return person;
8679
};
8780

88-
export const keypairDispatcher = (
89-
siteService: SiteService,
90-
accountService: AccountService,
91-
) =>
81+
export const keypairDispatcher = (accountService: AccountService) =>
9282
async function keypairDispatcher(
9383
ctx: Context<ContextData>,
9484
identifier: string,
9585
) {
96-
const site = await siteService.getSiteByHost(ctx.host);
97-
if (site === null) return [];
86+
const site = ctx.data.site!;
87+
if (!site) return [];
9888

9989
const account = await accountService.getDefaultAccountForSite(site);
10090

@@ -188,7 +178,6 @@ export function createAcceptHandler(accountService: AccountService) {
188178
export async function handleAnnouncedCreate(
189179
ctx: Context<ContextData>,
190180
announce: Announce,
191-
siteService: SiteService,
192181
accountService: AccountService,
193182
postService: PostService,
194183
) {
@@ -204,11 +193,7 @@ export async function handleAnnouncedCreate(
204193
return;
205194
}
206195

207-
const site = await siteService.getSiteByHost(ctx.host);
208-
209-
if (!site) {
210-
throw new Error(`Site not found for host: ${ctx.host}`);
211-
}
196+
const site = ctx.data.site!;
212197

213198
// Validate that the group is followed
214199
if (
@@ -478,7 +463,6 @@ export const createUndoHandler = (
478463
};
479464

480465
export function createAnnounceHandler(
481-
siteService: SiteService,
482466
accountService: AccountService,
483467
postService: PostService,
484468
postRepository: KnexPostRepository,
@@ -512,7 +496,6 @@ export function createAnnounceHandler(
512496
return handleAnnouncedCreate(
513497
ctx,
514498
announce,
515-
siteService,
516499
accountService,
517500
postService,
518501
);
@@ -588,12 +571,6 @@ export function createAnnounceHandler(
588571

589572
ctx.data.globaldb.set([announce.id.href], announceJson);
590573

591-
const site = await siteService.getSiteByHost(ctx.host);
592-
593-
if (!site) {
594-
throw new Error(`Site not found for host: ${ctx.host}`);
595-
}
596-
597574
// This will save the account if it doesn't already exist
598575
const senderAccount = await accountService.getByApId(sender.id);
599576

@@ -774,21 +751,12 @@ export async function inboxErrorHandler(
774751
});
775752
}
776753

777-
export function createFollowersDispatcher(
778-
siteService: SiteService,
779-
accountRepository: KnexAccountRepository,
780-
followersService: FollowersService,
781-
) {
754+
export function createFollowersDispatcher(followersService: FollowersService) {
782755
return async function dispatchFollowers(
783756
ctx: Context<ContextData>,
784757
_handle: string,
785758
) {
786-
const site = await siteService.getSiteByHost(ctx.host);
787-
if (!site) {
788-
throw new Error(`Site not found for host: ${ctx.host}`);
789-
}
790-
791-
const account = await accountRepository.getBySite(site);
759+
const account = ctx.data.account!;
792760

793761
const followers = await followersService.getFollowers(account.id);
794762

@@ -798,10 +766,7 @@ export function createFollowersDispatcher(
798766
};
799767
}
800768

801-
export function createFollowingDispatcher(
802-
siteService: SiteService,
803-
accountService: AccountService,
804-
) {
769+
export function createFollowingDispatcher(accountService: AccountService) {
805770
return async function dispatchFollowing(
806771
ctx: RequestContext<ContextData>,
807772
_handle: string,
@@ -812,16 +777,8 @@ export function createFollowingDispatcher(
812777
const offset = Number.parseInt(cursor ?? '0', 10);
813778
let nextCursor: string | null = null;
814779

815-
const host = ctx.request.headers.get('host')!;
816-
const site = await siteService.getSiteByHost(host);
817-
818-
if (!site) {
819-
throw new Error(`Site not found for host: ${host}`);
820-
}
821-
822780
// @TODO: Get account by provided handle instead of default account?
823-
const siteDefaultAccount =
824-
await accountService.getDefaultAccountForSite(site);
781+
const siteDefaultAccount = ctx.data.account!;
825782

826783
const results = await accountService.getFollowingAccounts(
827784
siteDefaultAccount,
@@ -849,43 +806,27 @@ export function createFollowingDispatcher(
849806
};
850807
}
851808

852-
export function createFollowersCounter(
853-
siteService: SiteService,
854-
accountService: AccountService,
855-
) {
809+
export function createFollowersCounter(accountService: AccountService) {
856810
return async function countFollowers(
857811
ctx: RequestContext<ContextData>,
858812
_handle: string,
859813
) {
860-
const site = await siteService.getSiteByHost(ctx.host);
861-
if (!site) {
862-
throw new Error(`Site not found for host: ${ctx.host}`);
863-
}
864-
865814
// @TODO: Get account by provided handle instead of default account?
866-
const siteDefaultAccount = await accountService.getAccountForSite(site);
815+
const siteDefaultAccount = ctx.data.account!;
867816

868817
return await accountService.getFollowerAccountsCount(
869818
siteDefaultAccount.id,
870819
);
871820
};
872821
}
873822

874-
export function createFollowingCounter(
875-
siteService: SiteService,
876-
accountService: AccountService,
877-
) {
823+
export function createFollowingCounter(accountService: AccountService) {
878824
return async function countFollowing(
879825
ctx: RequestContext<ContextData>,
880826
_handle: string,
881827
) {
882-
const site = await siteService.getSiteByHost(ctx.host);
883-
if (!site) {
884-
throw new Error(`Site not found for host: ${ctx.host}`);
885-
}
886-
887828
// @TODO: Get account by provided handle instead of default account?
888-
const siteDefaultAccount = await accountService.getAccountForSite(site);
829+
const siteDefaultAccount = ctx.data.account!;
889830

890831
return await accountService.getFollowingAccountsCount(
891832
siteDefaultAccount.id,

src/helpers/activitypub/activity.unit.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,10 @@ describe('Build activity', () => {
333333
customFields: null,
334334
apId: new URL('https://example.com/user/testuser'),
335335
apFollowers: new URL('https://example.com/user/testuser/followers'),
336+
apFollowing: new URL('https://example.com/user/testuser/following'),
336337
apInbox: new URL('https://example.com/user/testuser/inbox'),
338+
apOutbox: new URL('https://example.com/user/testuser/outbox'),
339+
apLiked: new URL('https://example.com/user/testuser/liked'),
337340
isInternal: false,
338341
});
339342

@@ -349,7 +352,10 @@ describe('Build activity', () => {
349352
customFields: null,
350353
apId: new URL('https://example.com/user/author'),
351354
apFollowers: new URL('https://example.com/user/author/followers'),
355+
apFollowing: new URL('https://example.com/user/author/following'),
352356
apInbox: new URL('https://example.com/user/author/inbox'),
357+
apOutbox: new URL('https://example.com/user/author/outbox'),
358+
apLiked: new URL('https://example.com/user/author/liked'),
353359
isInternal: false,
354360
});
355361

src/helpers/fedify.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,7 @@ export function createFedifyCtxForHost(
1818
return fedify.createContext(hostUrl, {
1919
globaldb: ctxData.globaldb,
2020
logger: ctxData.logger,
21+
site: ctxData.site,
22+
account: ctxData.account,
2123
});
2224
}

0 commit comments

Comments
 (0)