Last active
December 20, 2019 20:25
-
-
Save manchuck/096118a8085a03e26d4f8ee27e8ac344 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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