snowflake-uuid
Version:
Twitter's Snowflake generator implementation for NodeJS
94 lines (93 loc) • 3.35 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.Worker = void 0;
class Worker {
#epoch;
#workerId;
#workerIdBits;
#maxWorkerId;
#datacenterId;
#datacenterIdBits;
#maxDatacenterId;
#sequence;
#sequenceBits;
#workerIdShift;
#datacenterIdShift;
#timestampLeftShift;
#sequenceMask;
#lastTimestamp = -1n;
constructor(workerId = 0n, datacenterId = 0n, options) {
this.#epoch = BigInt(options?.epoch ?? 1609459200000);
this.#workerId = BigInt(workerId);
this.#workerIdBits = BigInt(options?.workerIdBits ?? 5);
this.#maxWorkerId = -1n ^ (-1n << this.#workerIdBits);
if (this.#workerId < 0 || this.#workerId > this.#maxWorkerId) {
throw new Error('With ' +
this.#workerIdBits.toString() +
" bits, worker id can't be greater than " +
this.#maxWorkerId.toString() +
' or less than 0');
}
this.#datacenterId = BigInt(datacenterId);
this.#datacenterIdBits = BigInt(options?.datacenterIdBits ?? 5);
this.#maxDatacenterId = -1n ^ (-1n << this.#datacenterIdBits);
if (this.#datacenterId > this.#maxDatacenterId || this.#datacenterId < 0) {
throw new Error('With ' +
this.#datacenterIdBits.toString() +
" bits, datacenter id can't be greater than " +
this.#maxDatacenterId.toString() +
' or less than 0');
}
this.#sequence = BigInt(options?.sequence ?? 0);
this.#sequenceBits = BigInt(options?.sequenceBits ?? 12);
this.#sequenceMask = -1n ^ (-1n << this.#sequenceBits);
this.#workerIdShift = this.#sequenceBits;
this.#datacenterIdShift = this.#sequenceBits + this.#workerIdBits;
this.#timestampLeftShift = this.#sequenceBits + this.#workerIdBits + this.#datacenterIdBits;
}
get workerId() {
return this.#workerId;
}
get datacenterId() {
return this.#datacenterId;
}
get currentSequence() {
return this.#sequence;
}
get lastTimestamp() {
return this.#lastTimestamp;
}
nextId() {
let timestamp = Worker.now();
if (timestamp < this.#lastTimestamp) {
throw new Error("Clock moved backwards. Can't generate new ID for " +
(this.#lastTimestamp - timestamp).toString() +
'milliseconds.');
}
if (timestamp === this.#lastTimestamp) {
this.#sequence = (this.#sequence + 1n) & this.#sequenceMask;
if (this.#sequence === 0n) {
timestamp = this.tilNextMillis(this.#lastTimestamp);
}
}
else {
this.#sequence = 0n;
}
this.#lastTimestamp = timestamp;
return (((timestamp - this.#epoch) << this.#timestampLeftShift) |
(this.#datacenterId << this.#datacenterIdShift) |
(this.#workerId << this.#workerIdShift) |
this.#sequence);
}
tilNextMillis(lastTimestamp) {
let timestamp;
do {
timestamp = Worker.now();
} while (timestamp <= lastTimestamp);
return timestamp;
}
static now() {
return BigInt(Date.now());
}
}
exports.Worker = Worker;