/*
* Author: Vlad Seryakov vseryakov@gmail.com
* backendjs 2018
*/
const crypto = require('crypto');
const lib = require(__dirname + '/../lib');
/**
* Unique Id (UUID v4) without any special characters and in lower case
* @param {string} [prefix] - prepend with prefix
* @return {string}
* @memberof module:lib
* @method uuid
*/
lib.uuid = function(prefix)
{
return (prefix || "") + crypto.randomUUID().replace(/[-]/g, '').toLowerCase();
}
/**
* Short unique id within a microsecond or local epoch
* @param {string} [prefix] - prepend with prefix
* @param {object} [options] - same options as for {@link module:lib.getHashid}
* @param {int} [options.epoch] - local epoch type via {@link module:lib.localEpoch}, default is milliseconds, `m` for microseconds, `s` for seconds
* @return {string} generated hash
* @memberof module:lib
* @method suuid
*/
lib.suuid = function(prefix, options)
{
var hashid = this.getHashid(options);
var c = options?.epoch ? lib.localEpoch(options?.epoch) : lib.clock();
var s = hashid.encode(c, hashid._counter);
return prefix ? prefix + s : s;
}
/**
* Generate a SnowFlake unique id as 64-bit number
* Format: time - 41 bit, node - 10 bit, counter - 12 bit
* @param {object} [options]
* @param {int} [options.now] - time, if not given local epoch clock is used in microseconds
* @param {int} [options.epoch] - local epoch type via {@link module:lib.localEpoch}, default is milliseconds, `m` for microseconds, `s` for seconds
* @param {int} [options.node] - node id, limited to max 1024
* @param {int} [options.radix] - default is 10, use any value between 2 - 36 for other numeric encoding
* @memberof module:lib
* @method sfuuid
*/
lib.sfuuid = function(options)
{
var node = options?.node || lib.sfuuidNode;
if (node === undefined) {
var intf = lib.networkInterfaces()[0];
if (intf) lib.sfuuidNode = node = lib.murmurHash3(intf.mac);
}
var now = options?.now || lib.localEpoch(options?.epoch);
var n = BigInt(now) << 22n | (BigInt(node % 1024) << 12n) | BigInt(lib.sfuuidCounter++ % 4096);
return n.toString(options?.radix || 10);
}
lib.sfuuidCounter = lib.randomShort();
/**
* Parse an SFUUID numeric id into its original components.
*
* Splits the id into bit fields:
* - `now`: 64 bits starting at bit 22
* - `node`: 10 bits starting at bit 12
* - `counter`: 12 bits starting at bit 0
*
* @function lib.sfuuidParse
* @param {string|number|bigint} id
* SFUUID value to parse. Can be a BigInt, a decimal string, or a number
* (numbers may lose precision for large ids).
*
* @returns {Object} rc
* @returns {bigint} rc.id Parsed id as a BigInt (only set if parsing succeeded).
* @returns {number} rc.now Extracted `now` component (only set if parsing succeeded).
* @returns {number} rc.node Extracted `node` component (only set if parsing succeeded).
* @returns {number} rc.counter Extracted `counter` component (only set if parsing succeeded).
*/
lib.sfuuidParse = function(id)
{
const _map = { now: [22n, 64n], node: [12n, 10n], counter: [0n, 12n] };
const rc = {};
try {
id = rc.id = BigInt(id);
for (const p in _map) {
rc[p] = Number((id & (((1n << _map[p][1]) - 1n) << _map[p][0])) >> _map[p][0]);
}
} catch (e) {}
return rc;
}