Skip to content

Instantly share code, notes, and snippets.

@DonovanDMC
Created August 12, 2022 08:09
Show Gist options
  • Save DonovanDMC/69a073a01b63bcb769b4c0b9af3a3353 to your computer and use it in GitHub Desktop.
Save DonovanDMC/69a073a01b63bcb769b4c0b9af3a3353 to your computer and use it in GitHub Desktop.
class Snowflake {
static readonly BITS = {
EPOCH: 41,
MACHINE_ID: 10,
SEQUENCE: 12,
UNUSED: 1
};
static readonly EPOCH = Date.parse("2022-01-01T00:00:00.000Z");
static readonly MACHINE_ID = 0;
static readonly MAX_MACHINE_ID = Math.pow(2, Snowflake.BITS.MACHINE_ID);
static readonly MAX_SEQUENCE = Math.pow(2, Snowflake.BITS.SEQUENCE);
static SEQUENCE = 0;
private static binaryToId(bin: string): string {
let dec = "";
while (bin.length > 50) {
const high = parseInt(bin.slice(0, -32), 2);
const low = parseInt((high % 10).toString(2) + bin.slice(-32), 2);
dec = (low % 10).toString() + dec;
bin =
Math.floor(high / 10).toString(2) +
Math.floor(low / 10)
.toString(2)
.padStart(32, "0");
}
let b = parseInt(bin, 2);
while (b > 0) {
dec = (b % 10).toString() + dec;
b = Math.floor(b / 10);
}
return dec;
}
private static idToBinary(id: string) {
let bin = "";
let high = Number(id.slice(0, -10)) || 0;
let low = Number(id.slice(-10));
while (low > 0 || high > 0) {
bin = String(low & 1) + bin;
low = Math.floor(low / 2);
if (high > 0) {
low += 5e9 * (high % 2);
high = Math.floor(high / 2);
}
}
return bin;
}
static decode(id: string) {
const bin = this.idToBinary(id).toString().padStart(64, "0").split("");
return {
timestamp: parseInt(bin.splice(0, Snowflake.BITS.EPOCH).join(""), 2) + this.EPOCH,
machineId: parseInt(bin.splice(0, Snowflake.BITS.MACHINE_ID).join(""), 2),
sequence: parseInt(bin.splice(0, Snowflake.BITS.SEQUENCE).join(""), 2),
unused: parseInt(bin.splice(0, Snowflake.BITS.UNUSED).join(""), 2)
};
}
static generate(timestamp = Date.now()): string {
const bin = `${(timestamp - this.EPOCH).toString(2).padStart(Snowflake.BITS.EPOCH, "0")}${this.MACHINE_ID.toString(2).padStart(Snowflake.BITS.MACHINE_ID, "0")}${(this.SEQUENCE++).toString(2).padStart(Snowflake.BITS.SEQUENCE, "0")}${"0".repeat(Snowflake.BITS.UNUSED)}`;
if (this.SEQUENCE >= (this.MAX_SEQUENCE - 1)) this.SEQUENCE = 0;
return this.binaryToId(bin);
}
static getSequence() { return Number(this.SEQUENCE); /* make uneditable */ }
}
export default Snowflake;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment