use cuid2 with timestamp

This commit is contained in:
Namekuji 2023-05-28 20:24:48 -04:00
parent 0741df711a
commit 399b0e96dc
6 changed files with 53 additions and 38 deletions

View file

@ -85,20 +85,16 @@ redis:
# ┌───────────────┐ # ┌───────────────┐
#───┘ ID generation └─────────────────────────────────────────── #───┘ ID generation └───────────────────────────────────────────
# You can select the ID generation method. # No need to uncomment in most cases, but you may want to change
# You don't usually need to change this setting, but you can # these settings if you plan to run a large and/or distributed server.
# change it according to your preferences.
# Available methods: # cuid: {
# aid ... Short, Millisecond accuracy # # Min 16, Max 24
# meid ... Similar to ObjectID, Millisecond accuracy # length: 16,
# ulid ... Millisecond accuracy # # Set this to a unique string across workers (e.g., machine's hostname)
# objectid ... This is left for backward compatibility # # if your workers are running in multiple hosts.
# fingerprint: "my-fingerperint",
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE # }
# ID SETTINGS AFTER THAT!
id: 'aid'
# ┌─────────────────────┐ # ┌─────────────────────┐
#───┘ Other configuration └───────────────────────────────────── #───┘ Other configuration └─────────────────────────────────────

View file

@ -1,7 +1,9 @@
import test from "ava"; import test from "ava";
import { sum } from "../index.js"; import { convertId, IdConvertType } from "../built/index.js";
test("sum from native", (t) => { test("convert to mastodon id", (t) => {
t.is(sum(1, 2), 3); t.is(convertId("9gf61ehcxv", IdConvertType.MastodonId), "960365976481219");
t.is(convertId("9fbr9z0wbrjqyd3u", IdConvertType.MastodonId), "3954607381600562394");
t.is(convertId("9fbs680oyviiqrol9md73p8g", IdConvertType.MastodonId), "3494513243013053824")
}); });

View file

@ -32,6 +32,7 @@
"@koa/cors": "3.4.3", "@koa/cors": "3.4.3",
"@koa/multer": "3.0.0", "@koa/multer": "3.0.0",
"@koa/router": "9.0.1", "@koa/router": "9.0.1",
"@paralleldrive/cuid2": "2.2.0",
"@peertube/http-signature": "1.7.0", "@peertube/http-signature": "1.7.0",
"@redocly/openapi-core": "1.0.0-beta.120", "@redocly/openapi-core": "1.0.0-beta.120",
"@sinonjs/fake-timers": "9.1.2", "@sinonjs/fake-timers": "9.1.2",

View file

@ -54,7 +54,10 @@ export type Source = {
onlyQueueProcessor?: boolean; onlyQueueProcessor?: boolean;
id: string; cuid?: {
length?: number;
fingerprint?: string;
};
outgoingAddressFamily?: "ipv4" | "ipv6" | "dual"; outgoingAddressFamily?: "ipv4" | "ipv6" | "dual";

View file

@ -1,27 +1,27 @@
import { ulid } from "ulid"; import { init, createId } from "@paralleldrive/cuid2";
import { genAid } from "./id/aid.js";
import { genMeid } from "./id/meid.js";
import { genMeidg } from "./id/meidg.js";
import { genObjectId } from "./id/object-id.js";
import config from "@/config/index.js"; import config from "@/config/index.js";
const metohd = config.id.toLowerCase(); const TIME2000 = 946684800000;
const TIMESTAMP_LENGTH = 8;
const length =
Math.min(Math.max(config.cuid?.length ?? 16, 16), 24) - TIMESTAMP_LENGTH;
const fingerprint = `${config.cuid?.fingerprint ?? ""}${createId()}`;
const genCuid2 = init({ length, fingerprint });
/**
* The generated ID results in the form of `[8 chars timestamp] + [cuid2]`.
* The minimum and maximum lengths are 16 and 24, respectively.
* With the length of 16, namely 8 for cuid2, roughly 1427399 IDs are needed
* in the same millisecond to reach 50% chance of collision.
*
* Ref: https://github.com/paralleldrive/cuid2#parameterized-length
*/
export function genId(date?: Date): string { export function genId(date?: Date): string {
if (!date || date > new Date()) date = new Date(); const now = (date ?? new Date()).getTime();
const time = Math.max(now - TIME2000, 0);
const timestamp = time.toString(36).padStart(TIMESTAMP_LENGTH, "0");
switch (metohd) { return `${timestamp}${genCuid2()}`;
case "aid":
return genAid(date);
case "meid":
return genMeid(date);
case "meidg":
return genMeidg(date);
case "ulid":
return ulid(date.getTime());
case "objectid":
return genObjectId(date);
default:
throw new Error("unrecognized id generation method");
}
} }

View file

@ -104,6 +104,9 @@ importers:
'@koa/router': '@koa/router':
specifier: 9.0.1 specifier: 9.0.1
version: 9.0.1 version: 9.0.1
'@paralleldrive/cuid2':
specifier: 2.2.0
version: 2.2.0
'@peertube/http-signature': '@peertube/http-signature':
specifier: 1.7.0 specifier: 1.7.0
version: 1.7.0 version: 1.7.0
@ -2277,6 +2280,10 @@ packages:
hasBin: true hasBin: true
dev: false dev: false
/@noble/hashes@1.3.0:
resolution: {integrity: sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==}
dev: false
/@nodelib/fs.scandir@2.1.5: /@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@ -2330,6 +2337,12 @@ packages:
through: 2.3.4 through: 2.3.4
dev: false dev: false
/@paralleldrive/cuid2@2.2.0:
resolution: {integrity: sha512-CVQDpPIUHrUGGLdrMGz1NmqZvqmsB2j2rCIQEu1EvxWjlFh4fhvEGmgR409cY20/67/WlJsggenq0no3p3kYsw==}
dependencies:
'@noble/hashes': 1.3.0
dev: false
/@peertube/http-signature@1.7.0: /@peertube/http-signature@1.7.0:
resolution: {integrity: sha512-aGQIwo6/sWtyyqhVK4e1MtxYz4N1X8CNt6SOtCc+Wnczs5S5ONaLHDDR8LYaGn0MgOwvGgXyuZ5sJIfd7iyoUw==} resolution: {integrity: sha512-aGQIwo6/sWtyyqhVK4e1MtxYz4N1X8CNt6SOtCc+Wnczs5S5ONaLHDDR8LYaGn0MgOwvGgXyuZ5sJIfd7iyoUw==}
engines: {node: '>=0.10'} engines: {node: '>=0.10'}