diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2023-04-09 10:29:36 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-04-09 10:29:36 +0900 |
| commit | 8b1362ab03c273f44cbbbb3c9f900301d82aeabd (patch) | |
| tree | 61fda1a1b44776e8d3a4a17511f2d510b6d9791b /packages/backend | |
| parent | Merge pull request #10506 from misskey-dev/develop (diff) | |
| parent | fix(backend): 連合しているインスタンスについて予期せず配... (diff) | |
| download | misskey-8b1362ab03c273f44cbbbb3c9f900301d82aeabd.tar.gz misskey-8b1362ab03c273f44cbbbb3c9f900301d82aeabd.tar.bz2 misskey-8b1362ab03c273f44cbbbb3c9f900301d82aeabd.zip | |
Merge pull request #10543 from misskey-dev/develop
Release: 13.11.1
Diffstat (limited to '')
| -rw-r--r-- | packages/backend/src/core/CustomEmojiService.ts | 6 | ||||
| -rw-r--r-- | packages/backend/src/core/FederatedInstanceService.ts | 1 | ||||
| -rw-r--r-- | packages/backend/src/core/IdService.ts | 14 | ||||
| -rw-r--r-- | packages/backend/src/core/activitypub/ApDeliverManagerService.ts | 2 | ||||
| -rw-r--r-- | packages/backend/src/misc/cache.ts | 4 | ||||
| -rw-r--r-- | packages/backend/src/misc/id/aid.ts | 2 | ||||
| -rw-r--r-- | packages/backend/src/misc/id/meid.ts | 9 | ||||
| -rw-r--r-- | packages/backend/src/misc/id/meidg.ts | 7 | ||||
| -rw-r--r-- | packages/backend/src/misc/id/object-id.ts | 9 | ||||
| -rw-r--r-- | packages/backend/src/misc/id/ulid.ts | 14 | ||||
| -rw-r--r-- | packages/backend/src/server/api/endpoints/channels/timeline.ts | 18 | ||||
| -rw-r--r-- | packages/backend/test/unit/misc/id.ts | 44 |
12 files changed, 113 insertions, 17 deletions
diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts index 604a94707f..dc365986fe 100644 --- a/packages/backend/src/core/CustomEmojiService.ts +++ b/packages/backend/src/core/CustomEmojiService.ts @@ -44,7 +44,11 @@ export class CustomEmojiService { memoryCacheLifetime: 1000 * 60 * 3, // 3m fetcher: () => this.emojisRepository.find({ where: { host: IsNull() } }).then(emojis => new Map(emojis.map(emoji => [emoji.name, emoji]))), toRedisConverter: (value) => JSON.stringify(value.values()), - fromRedisConverter: (value) => new Map(JSON.parse(value).map((x: Emoji) => [x.name, x])), // TODO: Date型の変換 + fromRedisConverter: (value) => { + // 原因不明だが配列以外が入ってくることがあるため + if (!Array.isArray(JSON.parse(value))) return undefined; + return new Map(JSON.parse(value).map((x: Emoji) => [x.name, x])); + }, // TODO: Date型の変換 }); } diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts index 1d0c87280f..56660ae0d0 100644 --- a/packages/backend/src/core/FederatedInstanceService.ts +++ b/packages/backend/src/core/FederatedInstanceService.ts @@ -29,6 +29,7 @@ export class FederatedInstanceService { toRedisConverter: (value) => JSON.stringify(value), fromRedisConverter: (value) => { const parsed = JSON.parse(value); + if (parsed == null) return null; return { ...parsed, firstRetrievedAt: new Date(parsed.firstRetrievedAt), diff --git a/packages/backend/src/core/IdService.ts b/packages/backend/src/core/IdService.ts index 94084ad84f..8aa6ccfc4e 100644 --- a/packages/backend/src/core/IdService.ts +++ b/packages/backend/src/core/IdService.ts @@ -3,10 +3,11 @@ import { ulid } from 'ulid'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import { genAid, parseAid } from '@/misc/id/aid.js'; -import { genMeid } from '@/misc/id/meid.js'; -import { genMeidg } from '@/misc/id/meidg.js'; +import { genMeid, parseMeid } from '@/misc/id/meid.js'; +import { genMeidg, parseMeidg } from '@/misc/id/meidg.js'; import { genObjectId } from '@/misc/id/object-id.js'; import { bindThis } from '@/decorators.js'; +import { parseUlid } from '@/misc/id/ulid.js'; @Injectable() export class IdService { @@ -37,11 +38,10 @@ export class IdService { public parse(id: string): { date: Date; } { switch (this.method) { case 'aid': return parseAid(id); - // TODO - //case 'meid': - //case 'meidg': - //case 'ulid': - //case 'objectid': + case 'objectid': + case 'meid': return parseMeid(id); + case 'meidg': return parseMeidg(id); + case 'ulid': return parseUlid(id); default: throw new Error('unrecognized id generation method'); } } diff --git a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts index 70a6d32fe2..62a2a33a19 100644 --- a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts +++ b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts @@ -186,7 +186,7 @@ class DeliverManager { for (const following of followers) { const inbox = following.followerSharedInbox ?? following.followerInbox; - inboxes.set(inbox, following.followerSharedInbox === null); + inboxes.set(inbox, following.followerSharedInbox != null); } } diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index d35414acf7..a4abd4f878 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -8,7 +8,7 @@ export class RedisKVCache<T> { private memoryCache: MemoryKVCache<T>; private fetcher: (key: string) => Promise<T>; private toRedisConverter: (value: T) => string; - private fromRedisConverter: (value: string) => T; + private fromRedisConverter: (value: string) => T | undefined; // undefined means no cache constructor(redisClient: RedisKVCache<T>['redisClient'], name: RedisKVCache<T>['name'], opts: { lifetime: RedisKVCache<T>['lifetime']; @@ -92,7 +92,7 @@ export class RedisSingleCache<T> { private memoryCache: MemorySingleCache<T>; private fetcher: () => Promise<T>; private toRedisConverter: (value: T) => string; - private fromRedisConverter: (value: string) => T; + private fromRedisConverter: (value: string) => T | undefined; // undefined means no cache constructor(redisClient: RedisSingleCache<T>['redisClient'], name: RedisSingleCache<T>['name'], opts: { lifetime: RedisSingleCache<T>['lifetime']; diff --git a/packages/backend/src/misc/id/aid.ts b/packages/backend/src/misc/id/aid.ts index 93a9929aa7..9e206ee98f 100644 --- a/packages/backend/src/misc/id/aid.ts +++ b/packages/backend/src/misc/id/aid.ts @@ -3,6 +3,8 @@ import * as crypto from 'node:crypto'; +export const aidRegExp = /^[0-9a-z]{10}$/; + const TIME2000 = 946684800000; let counter = crypto.randomBytes(2).readUInt16LE(0); diff --git a/packages/backend/src/misc/id/meid.ts b/packages/backend/src/misc/id/meid.ts index 30bbdf1698..337416b059 100644 --- a/packages/backend/src/misc/id/meid.ts +++ b/packages/backend/src/misc/id/meid.ts @@ -1,5 +1,8 @@ const CHARS = '0123456789abcdef'; +// same as object-id +export const meidRegExp = /^[0-9a-f]{24}$/; + function getTime(time: number) { if (time < 0) time = 0; if (time === 0) { @@ -24,3 +27,9 @@ function getRandom() { export function genMeid(date: Date): string { return getTime(date.getTime()) + getRandom(); } + +export function parseMeid(id: string): { date: Date; } { + return { + date: new Date(parseInt(id.slice(0, 12), 16) - 0x800000000000), + }; +} diff --git a/packages/backend/src/misc/id/meidg.ts b/packages/backend/src/misc/id/meidg.ts index d4aaaea1ba..19d0bc1fd2 100644 --- a/packages/backend/src/misc/id/meidg.ts +++ b/packages/backend/src/misc/id/meidg.ts @@ -3,6 +3,7 @@ const CHARS = '0123456789abcdef'; // 4bit Fixed hex value 'g' // 44bit UNIX Time ms in Hex // 48bit Random value in Hex +export const meidgRegExp = /^g[0-9a-f]{23}$/; function getTime(time: number) { if (time < 0) time = 0; @@ -26,3 +27,9 @@ function getRandom() { export function genMeidg(date: Date): string { return 'g' + getTime(date.getTime()) + getRandom(); } + +export function parseMeidg(id: string): { date: Date; } { + return { + date: new Date(parseInt(id.slice(1, 12), 16)), + }; +} diff --git a/packages/backend/src/misc/id/object-id.ts b/packages/backend/src/misc/id/object-id.ts index 392ea43301..aec3447bd7 100644 --- a/packages/backend/src/misc/id/object-id.ts +++ b/packages/backend/src/misc/id/object-id.ts @@ -1,5 +1,8 @@ const CHARS = '0123456789abcdef'; +// same as meid +export const objectIdRegExp = /^[0-9a-f]{24}$/; + function getTime(time: number) { if (time < 0) time = 0; if (time === 0) { @@ -24,3 +27,9 @@ function getRandom() { export function genObjectId(date: Date): string { return getTime(date.getTime()) + getRandom(); } + +export function parseObjectId(id: string): { date: Date; } { + return { + date: new Date(parseInt(id.slice(0, 8), 16) * 1000), + }; +} diff --git a/packages/backend/src/misc/id/ulid.ts b/packages/backend/src/misc/id/ulid.ts new file mode 100644 index 0000000000..e8aa752890 --- /dev/null +++ b/packages/backend/src/misc/id/ulid.ts @@ -0,0 +1,14 @@ +// Crockford's Base32 +// https://github.com/ulid/spec#encoding +const CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; + +export const ulidRegExp = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/; + +export function parseUlid(id: string): { date: Date; } { + const timestamp = id.slice(0, 10); + let time = 0; + for (let i = 0; i < 10; i++) { + time = time * 32 + CHARS.indexOf(timestamp[i]); + } + return { date: new Date(time) }; +} diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts index 2556557b24..2491d14235 100644 --- a/packages/backend/src/server/api/endpoints/channels/timeline.ts +++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts @@ -75,13 +75,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { let timeline: Note[] = []; - const noteIdsRes = await this.redisClient.xrevrange( - `channelTimeline:${channel.id}`, - ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : '+', - '-', - 'COUNT', ps.limit + 1); // untilIdに指定したものも含まれるため+1 + const limit = ps.limit + (ps.untilId ? 1 : 0); // untilIdに指定したものも含まれるため+1 + let noteIdsRes: [string, string[]][] = []; + + if (!ps.sinceId && !ps.sinceDate) { + noteIdsRes = await this.redisClient.xrevrange( + `channelTimeline:${channel.id}`, + ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', + '-', + 'COUNT', limit); + } - if (noteIdsRes.length === 0) { + // redis から取得していないとき・取得数が足りないとき + if (noteIdsRes.length < limit) { //#region Construct query const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.channelId = :channelId', { channelId: channel.id }) diff --git a/packages/backend/test/unit/misc/id.ts b/packages/backend/test/unit/misc/id.ts new file mode 100644 index 0000000000..ecd0e60a31 --- /dev/null +++ b/packages/backend/test/unit/misc/id.ts @@ -0,0 +1,44 @@ +import { aidRegExp, genAid, parseAid } from '@/misc/id/aid.js'; +import { genMeid, meidRegExp, parseMeid } from '@/misc/id/meid.js'; +import { genMeidg, meidgRegExp, parseMeidg } from '@/misc/id/meidg.js'; +import { genObjectId, objectIdRegExp, parseObjectId } from '@/misc/id/object-id.js'; +import { ulidRegExp, parseUlid } from '@/misc/id/ulid.js'; +import { ulid } from 'ulid'; +import { describe, test, expect } from '@jest/globals'; + +describe('misc:id', () => { + test('aid', () => { + const date = new Date(); + const gotAid = genAid(date); + expect(gotAid).toMatch(aidRegExp); + expect(parseAid(gotAid).date.getTime()).toBe(date.getTime()); + }); + + test('meid', () => { + const date = new Date(); + const gotMeid = genMeid(date); + expect(gotMeid).toMatch(meidRegExp); + expect(parseMeid(gotMeid).date.getTime()).toBe(date.getTime()); + }); + + test('meidg', () => { + const date = new Date(); + const gotMeidg = genMeidg(date); + expect(gotMeidg).toMatch(meidgRegExp); + expect(parseMeidg(gotMeidg).date.getTime()).toBe(date.getTime()); + }); + + test('objectid', () => { + const date = new Date(); + const gotObjectId = genObjectId(date); + expect(gotObjectId).toMatch(objectIdRegExp); + expect(Math.floor(parseObjectId(gotObjectId).date.getTime() / 1000)).toBe(Math.floor(date.getTime() / 1000)); + }); + + test('ulid', () => { + const date = new Date(); + const gotUlid = ulid(date.getTime()); + expect(gotUlid).toMatch(ulidRegExp); + expect(parseUlid(gotUlid).date.getTime()).toBe(date.getTime()); + }); +}); |