Merge tag '13.11.1' into merge-upstream
This commit is contained in:
		| @@ -45,7 +45,8 @@ export class CustomEmojiService { | ||||
| 			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) => { | ||||
| 				if (!Array.isArray(value)) return undefined; | ||||
| 				// 原因不明だが配列以外が入ってくることがあるため | ||||
| 				if (!Array.isArray(JSON.parse(value))) return undefined; | ||||
| 				return new Map(JSON.parse(value).map((x: Emoji) => [x.name, x])); | ||||
| 			}, // TODO: Date型の変換 | ||||
| 		}); | ||||
|   | ||||
| @@ -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), | ||||
|   | ||||
| @@ -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'); | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -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); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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), | ||||
| 	}; | ||||
| } | ||||
|   | ||||
| @@ -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)), | ||||
| 	}; | ||||
| } | ||||
|   | ||||
| @@ -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), | ||||
| 	}; | ||||
| } | ||||
|   | ||||
							
								
								
									
										14
									
								
								packages/backend/src/misc/id/ulid.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								packages/backend/src/misc/id/ulid.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -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) }; | ||||
| } | ||||
| @@ -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 }) | ||||
|   | ||||
							
								
								
									
										44
									
								
								packages/backend/test/unit/misc/id.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								packages/backend/test/unit/misc/id.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -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()); | ||||
|     }); | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user
	 riku6460
					riku6460