fix(server): IdService.parseを全てのidタイプに対応させるように (#10533)

* wip fix-id

* ✌️

* fix import
This commit is contained in:
tamaina 2023-04-09 04:41:06 +09:00 committed by GitHub
parent 7a33c5d2ee
commit d76220cc80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 92 additions and 7 deletions

View file

@ -3,10 +3,11 @@ import { ulid } from 'ulid';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { genAid, parseAid } from '@/misc/id/aid.js'; import { genAid, parseAid } from '@/misc/id/aid.js';
import { genMeid } from '@/misc/id/meid.js'; import { genMeid, parseMeid } from '@/misc/id/meid.js';
import { genMeidg } from '@/misc/id/meidg.js'; import { genMeidg, parseMeidg } from '@/misc/id/meidg.js';
import { genObjectId } from '@/misc/id/object-id.js'; import { genObjectId } from '@/misc/id/object-id.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { parseUlid } from '@/misc/id/ulid.js';
@Injectable() @Injectable()
export class IdService { export class IdService {
@ -37,11 +38,10 @@ export class IdService {
public parse(id: string): { date: Date; } { public parse(id: string): { date: Date; } {
switch (this.method) { switch (this.method) {
case 'aid': return parseAid(id); case 'aid': return parseAid(id);
// TODO case 'objectid':
//case 'meid': case 'meid': return parseMeid(id);
//case 'meidg': case 'meidg': return parseMeidg(id);
//case 'ulid': case 'ulid': return parseUlid(id);
//case 'objectid':
default: throw new Error('unrecognized id generation method'); default: throw new Error('unrecognized id generation method');
} }
} }

View file

@ -3,6 +3,8 @@
import * as crypto from 'node:crypto'; import * as crypto from 'node:crypto';
export const aidRegExp = /^[0-9a-z]{10}$/;
const TIME2000 = 946684800000; const TIME2000 = 946684800000;
let counter = crypto.randomBytes(2).readUInt16LE(0); let counter = crypto.randomBytes(2).readUInt16LE(0);

View file

@ -1,5 +1,8 @@
const CHARS = '0123456789abcdef'; const CHARS = '0123456789abcdef';
// same as object-id
export const meidRegExp = /^[0-9a-f]{24}$/;
function getTime(time: number) { function getTime(time: number) {
if (time < 0) time = 0; if (time < 0) time = 0;
if (time === 0) { if (time === 0) {
@ -24,3 +27,9 @@ function getRandom() {
export function genMeid(date: Date): string { export function genMeid(date: Date): string {
return getTime(date.getTime()) + getRandom(); return getTime(date.getTime()) + getRandom();
} }
export function parseMeid(id: string): { date: Date; } {
return {
date: new Date(parseInt(id.slice(0, 12), 16) - 0x800000000000),
};
}

View file

@ -3,6 +3,7 @@ const CHARS = '0123456789abcdef';
// 4bit Fixed hex value 'g' // 4bit Fixed hex value 'g'
// 44bit UNIX Time ms in Hex // 44bit UNIX Time ms in Hex
// 48bit Random value in Hex // 48bit Random value in Hex
export const meidgRegExp = /^g[0-9a-f]{23}$/;
function getTime(time: number) { function getTime(time: number) {
if (time < 0) time = 0; if (time < 0) time = 0;
@ -26,3 +27,9 @@ function getRandom() {
export function genMeidg(date: Date): string { export function genMeidg(date: Date): string {
return 'g' + getTime(date.getTime()) + getRandom(); return 'g' + getTime(date.getTime()) + getRandom();
} }
export function parseMeidg(id: string): { date: Date; } {
return {
date: new Date(parseInt(id.slice(1, 12), 16)),
};
}

View file

@ -1,5 +1,8 @@
const CHARS = '0123456789abcdef'; const CHARS = '0123456789abcdef';
// same as meid
export const objectIdRegExp = /^[0-9a-f]{24}$/;
function getTime(time: number) { function getTime(time: number) {
if (time < 0) time = 0; if (time < 0) time = 0;
if (time === 0) { if (time === 0) {
@ -24,3 +27,9 @@ function getRandom() {
export function genObjectId(date: Date): string { export function genObjectId(date: Date): string {
return getTime(date.getTime()) + getRandom(); return getTime(date.getTime()) + getRandom();
} }
export function parseObjectId(id: string): { date: Date; } {
return {
date: new Date(parseInt(id.slice(0, 8), 16) * 1000),
};
}

View 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) };
}

View 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());
});
});