Compare commits

...

4 commits

Author SHA1 Message Date
6123df0ebd
server: catch unresolvable featured notes
Instead of throwing all featured notes away, just remove that specific one.

closes #407
2024-10-18 17:39:28 +02:00
4aae4a5ffb
server: properly parse pinned post types 2024-10-18 17:28:38 +02:00
9d288c0613
translate comments 2024-10-18 17:26:13 +02:00
bc841ec965
server: enable Happy Eyeballs IPv4/v6 selection
Whoever thought it was a good idea to have this disabled by default...
2024-10-14 15:24:11 +02:00
3 changed files with 16 additions and 8 deletions

View file

@ -1,4 +1,5 @@
import cluster from 'node:cluster';
import net from 'node:net';
import Xev from 'xev';
import Logger from '@/services/logger.js';
@ -25,6 +26,8 @@ export async function boot(): Promise<void> {
process.title = `Foundkey (${process.env.mode})`;
}
net.setDefaultAutoSelectFamily(true);
if (cluster.isPrimary || envOption.disableClustering) {
await masterMain();

View file

@ -319,9 +319,14 @@ export async function resolveNote(value: string | IObject, resolver: Resolver):
throw new StatusError('cannot resolve local note', 400, 'cannot resolve local note');
}
// リモートサーバーからフェッチしてきて登録
// ここでuriの代わりに添付されてきたNote Objectが指定されていると、サーバーフェッチを経ずにートが生成されるが
// 添付されてきたNote Objectは偽装されている可能性があるため、常にuriを指定してサーバーフェッチを行う。
/*
If the Note Object attached is specified here instead of uri
after fetching from a remote server and registering, the note is
generated without going through server fetch, but the attached
Note Object may be spoofed, so always specify uri for server
Therefore, server fetching is always performed by specifying uri.
*/
return await createNote(uri, resolver, true);
} finally {
unlock();

View file

@ -27,7 +27,7 @@ import { db } from '@/db/postgre.js';
import { fromHtml } from '@/mfm/from-html.js';
import { Resolver } from '@/remote/activitypub/resolver.js';
import { apLogger } from '../logger.js';
import { isCollectionOrOrderedCollection, isCollection, IActor, getApId, getOneApHrefNullable, IObject, isPropertyValue, getApType, isActor } from '../type.js';
import { isCollectionOrOrderedCollection, isCollection, IActor, getApId, getOneApHrefNullable, IObject, isPropertyValue, getApType, isActor, isPost } from '../type.js';
import { extractApHashtags, extractEmojis } from './tag.js';
import { resolveNote } from './note.js';
import { resolveImage } from './image.js';
@ -459,17 +459,17 @@ async function updateFeatured(userId: User['id'], resolver: Resolver) {
const unresolvedItems = isCollection(collection) ? collection.items : collection.orderedItems;
const items = await Promise.all(toArray(unresolvedItems).map(x => resolver.resolve(x)));
// Resolve and regist Notes
// Resolve and register Notes
const limit = promiseLimit<Note | null>(2);
const featuredNotes = await Promise.all(items
.filter(item => getApType(item) === 'Note') // TODO: Noteでなくてもいいかも
.filter(item => isPost(item))
.slice(0, 5)
.map(item => limit(() => resolveNote(item, resolver))));
.map(item => limit(() => resolveNote(item, resolver).catch(() => null))));
await db.transaction(async transactionalEntityManager => {
await transactionalEntityManager.delete(UserNotePining, { userId: user.id });
// とりあえずidを別の時間で生成して順番を維持
// TODO: For now, generate the id at a different time and maintain the order.
let td = 0;
for (const note of featuredNotes.filter(note => note != null)) {
td -= 1000;