68 lines
2.1 KiB
TypeScript
68 lines
2.1 KiB
TypeScript
export class SnowflakeGenerator {
|
|
private epoch: bigint;
|
|
private workerId: bigint;
|
|
private processId: bigint;
|
|
private sequence: bigint;
|
|
private lastTimestamp: bigint;
|
|
|
|
constructor(workerId: bigint = 1n, processId: bigint = 1n, epoch: bigint = 1766617200000n) {
|
|
// dec 1 2025 (creation of this)
|
|
this.epoch = epoch;
|
|
this.workerId = workerId;
|
|
this.processId = processId;
|
|
this.sequence = 0n;
|
|
this.lastTimestamp = -1n;
|
|
}
|
|
|
|
private getCurrentTimestamp(): bigint {
|
|
return BigInt(Date.now());
|
|
}
|
|
|
|
private waitForNextMillisecond(lastTimestamp: bigint): bigint {
|
|
let timestamp = this.getCurrentTimestamp();
|
|
while (timestamp <= lastTimestamp) {
|
|
timestamp = this.getCurrentTimestamp();
|
|
}
|
|
return timestamp;
|
|
}
|
|
|
|
public generateSnowflake(): number {
|
|
const timestamp = this.getCurrentTimestamp() - this.epoch;
|
|
|
|
if (timestamp === this.lastTimestamp) {
|
|
this.sequence += 1n;
|
|
if (this.sequence > 4095n) { // max sequence value (12 bits)
|
|
// Wait for the next millisecond if we've reached the max sequence value
|
|
const newTimestamp = this.waitForNextMillisecond(this.lastTimestamp);
|
|
this.sequence = 0n;
|
|
return Number.parseInt(String(this.createSnowflake(newTimestamp)));
|
|
}
|
|
} else {
|
|
this.sequence = 0n;
|
|
}
|
|
|
|
this.lastTimestamp = timestamp;
|
|
return Number.parseInt(String(this.createSnowflake(timestamp)));
|
|
}
|
|
|
|
private createSnowflake(timestamp: bigint): bigint {
|
|
return (timestamp << 22n) | (BigInt(this.workerId) << 18n) | (BigInt(this.processId) << 12n) | BigInt(this.sequence);
|
|
}
|
|
|
|
public decodeSnowflake(id: bigint | number) {
|
|
const snowflake = BigInt(id);
|
|
|
|
const sequence = snowflake & (1n << 6n) - 1n;
|
|
const processId = (snowflake >> 6n) & ((1n << 6n) - 1n);
|
|
const workerId = (snowflake >> 12n) & ((1n << 10n) - 1n);
|
|
const timestamp = (snowflake >> 22n) + this.epoch;
|
|
|
|
return {
|
|
timestamp, // bigint (ms since Unix epoch)
|
|
date: new Date(Number(timestamp)),
|
|
workerId,
|
|
processId,
|
|
sequence,
|
|
};
|
|
}
|
|
} |