add Actor cache to webfinger

pull/335/head
Sven Sauleau 2023-02-23 14:25:24 +00:00
rodzic dd8662ba57
commit a876ef9ad2
10 zmienionych plików z 30 dodań i 23 usunięć

Wyświetl plik

@ -18,17 +18,17 @@ export async function getAccount(domain: string, accountId: string, db: Database
} else if (handle.domain !== null) {
// Retrieve the statuses of a remote actor
const acct = `${handle.localPart}@${handle.domain}`
return getRemoteAccount(handle, acct)
return getRemoteAccount(handle, acct, db)
} else {
return null
}
}
async function getRemoteAccount(handle: Handle, acct: string): Promise<MastodonAccount | null> {
async function getRemoteAccount(handle: Handle, acct: string, db: D1Database): Promise<MastodonAccount | null> {
// TODO: using webfinger isn't the optimal implementation. We could cache
// the object in D1 and directly query the remote API, indicated by the actor's
// url field. For now, let's keep it simple.
const actor = await queryAcct(handle.domain!, acct)
const actor = await queryAcct(handle.domain!, db, acct)
if (actor === null) {
return null
}

Wyświetl plik

@ -19,7 +19,7 @@ import type { APObject } from 'wildebeest/backend/src/activitypub/objects'
import type { Actor } from 'wildebeest/backend/src/activitypub/actors'
import { type Database } from 'wildebeest/backend/src/database'
export async function getMentions(input: string, instanceDomain: string): Promise<Array<Actor>> {
export async function getMentions(input: string, instanceDomain: string, db: Database): Promise<Array<Actor>> {
const mentions: Array<Actor> = []
for (let i = 0, len = input.length; i < len; i++) {
@ -34,7 +34,7 @@ export async function getMentions(input: string, instanceDomain: string): Promis
const handle = parseHandle(buffer)
const domain = handle.domain ? handle.domain : instanceDomain
const acct = `${handle.localPart}@${domain}`
const targetActor = await queryAcct(domain!, acct)
const targetActor = await queryAcct(domain!, db, acct)
if (targetActor === null) {
console.warn(`actor ${acct} not found`)
continue

Wyświetl plik

@ -11,12 +11,12 @@ const headers = {
accept: 'application/jrd+json',
}
export async function queryAcct(domain: string, acct: string): Promise<Actor | null> {
export async function queryAcct(domain: string, db: D1Database, acct: string): Promise<Actor | null> {
const url = await queryAcctLink(domain, acct)
if (url === null) {
return null
}
return actors.get(url)
return actors.getAndCache(url, db)
}
export async function queryAcctLink(domain: string, acct: string): Promise<URL | null> {

Wyświetl plik

@ -976,24 +976,24 @@ describe('Mastodon APIs', () => {
{
rel: 'self',
type: 'application/activity+json',
href: 'https://social.com/sven',
href: `https://${domain}/ap/users/actor`,
},
],
})
)
}
if (request.url === 'https://social.com/sven') {
if (request.url === `https://${domain}/ap/users/actor`) {
return new Response(
JSON.stringify({
id: `https://${domain}/ap/users/actor`,
type: 'Person',
inbox: 'https://example.com/inbox',
inbox: `https://${domain}/ap/users/actor/inbox`,
})
)
}
if (request.url === 'https://example.com/inbox') {
if (request.url === `https://${domain}/ap/users/actor/inbox`) {
assert.equal(request.method, 'POST')
receivedActivity = await request.json()
return new Response('')
@ -1040,7 +1040,7 @@ describe('Mastodon APIs', () => {
const connectedActor = actor
const req = new Request('https://example.com', { method: 'POST' })
const req = new Request('https://' + domain, { method: 'POST' })
const res = await accounts_unfollow.handleRequest(req, db, 'actor@' + domain, connectedActor, userKEK)
assert.equal(res.status, 200)
assertCORS(res)

Wyświetl plik

@ -202,6 +202,7 @@ describe('Mastodon APIs', () => {
return new Response(
JSON.stringify({
id: 'https://social.com/users/sven',
type: 'Person',
inbox: 'https://social.com/sven/inbox',
})
)
@ -404,6 +405,7 @@ describe('Mastodon APIs', () => {
})
test('get mentions from status', async () => {
const db = await makeDB()
globalThis.fetch = async (input: RequestInfo) => {
if (input.toString() === 'https://instance.horse/.well-known/webfinger?resource=acct%3Asven%40instance.horse') {
return new Response(
@ -467,6 +469,7 @@ describe('Mastodon APIs', () => {
return new Response(
JSON.stringify({
id: 'https://instance.horse/users/sven',
type: 'Person',
})
)
}
@ -474,6 +477,7 @@ describe('Mastodon APIs', () => {
return new Response(
JSON.stringify({
id: 'https://cloudflare.com/users/sven',
type: 'Person',
})
)
}
@ -481,6 +485,7 @@ describe('Mastodon APIs', () => {
return new Response(
JSON.stringify({
id: 'https://cloudflare.com/users/a',
type: 'Person',
})
)
}
@ -488,6 +493,7 @@ describe('Mastodon APIs', () => {
return new Response(
JSON.stringify({
id: 'https://cloudflare.com/users/b',
type: 'Person',
})
)
}
@ -496,42 +502,42 @@ describe('Mastodon APIs', () => {
}
{
const mentions = await getMentions('test status', domain)
const mentions = await getMentions('test status', domain, db)
assert.equal(mentions.length, 0)
}
{
const mentions = await getMentions('no-json@actor.com', domain)
const mentions = await getMentions('no-json@actor.com', domain, db)
assert.equal(mentions.length, 0)
}
{
const mentions = await getMentions('@sven@instance.horse test status', domain)
const mentions = await getMentions('@sven@instance.horse test status', domain, db)
assert.equal(mentions.length, 1)
assert.equal(mentions[0].id.toString(), 'https://instance.horse/users/sven')
}
{
const mentions = await getMentions('@sven test status', domain)
const mentions = await getMentions('@sven test status', domain, db)
assert.equal(mentions.length, 1)
assert.equal(mentions[0].id.toString(), 'https://' + domain + '/users/sven')
}
{
const mentions = await getMentions('@a @b', domain)
const mentions = await getMentions('@a @b', domain, db)
assert.equal(mentions.length, 2)
assert.equal(mentions[0].id.toString(), 'https://' + domain + '/users/a')
assert.equal(mentions[1].id.toString(), 'https://' + domain + '/users/b')
}
{
const mentions = await getMentions('<p>@sven</p>', domain)
const mentions = await getMentions('<p>@sven</p>', domain, db)
assert.equal(mentions.length, 1)
assert.equal(mentions[0].id.toString(), 'https://' + domain + '/users/sven')
}
{
const mentions = await getMentions('<p>@unknown</p>', domain)
const mentions = await getMentions('<p>@unknown</p>', domain, db)
assert.equal(mentions.length, 0)
}
})

Wyświetl plik

@ -31,6 +31,7 @@ describe('Wildebeest', () => {
return new Response(
JSON.stringify({
id: 'https://social.com/someone',
type: 'Person',
})
)
}

Wyświetl plik

@ -35,7 +35,7 @@ export async function handleRequest(
}
const acct = `${handle.localPart}@${handle.domain}`
const targetActor = await webfinger.queryAcct(handle.domain!, acct)
const targetActor = await webfinger.queryAcct(handle.domain!, db, acct)
if (targetActor === null) {
return new Response('', { status: 404 })
}

Wyświetl plik

@ -112,7 +112,7 @@ export async function handleRequest(
const hashtags = getHashtags(body.status)
const mentions = await getMentions(body.status, domain)
const mentions = await getMentions(body.status, domain, db)
if (mentions.length > 0) {
extraProperties.tag = mentions.map(newMention)
}

Wyświetl plik

@ -50,7 +50,7 @@ export async function handleRequest(db: Database, request: Request): Promise<Res
if (useWebFinger && query.domain !== null) {
const acct = `${query.localPart}@${query.domain}`
const res = await queryAcct(query.domain, acct)
const res = await queryAcct(query.domain, db, acct)
if (res !== null) {
out.accounts.push(await loadExternalMastodonAccount(acct, res))
}

Wyświetl plik

@ -24,7 +24,7 @@ export async function handleRequestPost(db: Database, request: Request, connecte
console.warn("account migration within an instance isn't supported")
return new Response('', { status: 400 })
}
const actor = await queryAcct(handle.domain, acct)
const actor = await queryAcct(handle.domain, db, acct)
if (actor === null) {
return errors.resourceNotFound('actor', acct)
}