Skip to content

Instantly share code, notes, and snippets.

@manchuck
Last active December 20, 2019 20:25
Show Gist options
  • Save manchuck/096118a8085a03e26d4f8ee27e8ac344 to your computer and use it in GitHub Desktop.
Save manchuck/096118a8085a03e26d4f8ee27e8ac344 to your computer and use it in GitHub Desktop.
/**
* @fileOverview Generate an Id
*/
const _ = require('lodash');
const {Hashids} = require('hashids');
const hashids = new Hashids(
'',
null,
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-',
);
const NODE_ID_BITS = 10;
const SEQUENCE_BITS = 12;
const MAX_UINT32 = 0xFFFFFFFF;
const CUSTOM_EPOCH = 1514725199000;
const maxNodeID = Math.pow(2, NODE_ID_BITS) - 1;
const maxSequence = Math.pow(2, SEQUENCE_BITS) - 1;
let currentTimestamp = new Date().getTime() - CUSTOM_EPOCH;
let lastTimestamp = currentTimestamp;
let sequence = 0;
let nodeBuf;
const timeBuf = Buffer.alloc(8);
/**
* Create a nodeId buffer
*
* Read in the mac addresses into a buffer
*
* @type {(function(): Buffer) & MemoizedFunction}
*/
const createNodeId = _.memoize(() => {
nodeBuf = Buffer.alloc(2);
const interfaces = require('os').networkInterfaces();
const tmpNodeId = _.reduce(
interfaces,
(result, value, key) => {
const mac = _.get(value, '0.mac').replace(/:/gm, '');
// Remove lo
if (mac === '000000000000') {
return result;
}
result = Buffer.concat([
result,
Buffer.from(mac),
]);
return result;
},
Buffer.alloc(NODE_ID_BITS),
);
let nodeId = tmpNodeId.readUInt32LE(0);
nodeId = nodeId & maxNodeID;
nodeBuf.writeUInt16LE(nodeId, 0);
});
/**
* (-.-) zzZZ
*
* @return {Promise<undefined>}
*/
const sleep = () => {
return new Promise((resolve) => setTimeout(resolve, 1000));
};
/**
* Sets the time stamp to the time buffer
*
* @param {Number} currentTimestamp
*/
const addTimeStampToBuffer =(currentTimestamp) => {
// split the 64 bit timestamp
const big = ~~(currentTimestamp / MAX_UINT32);
const low = (currentTimestamp % MAX_UINT32) - big;
timeBuf.writeUInt32BE(big, 0);
timeBuf.writeUInt32BE(low, 4);
};
addTimeStampToBuffer(currentTimestamp);
nodeBuf = createNodeId();
/**
* Generates an id
* @return {Promise<*>}
*/
module.exports = async () => {
sequence = (currentTimestamp === lastTimestamp)
? (sequence + 1) & maxSequence
: 0;
// Sequence Exhausted, wait till next millisecond.
if (sequence === 0) {
await sleep();
currentTimestamp = new Date().getTime() - CUSTOM_EPOCH;
addTimeStampToBuffer(currentTimestamp)
}
lastTimestamp = currentTimestamp;
const seqBuf = Buffer.alloc(2);
seqBuf.writeUInt16BE(sequence);
const idBuffer = Buffer.concat([seqBuf, nodeBuf, timeBuf]);
return hashids.encodeHex(idBuffer.toString('hex'));
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment