/*
* 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();
}
/**
* Generate a 22 chars slug from an UUID
* @param {object} [options]
* @param {string} [options.alphabet] - chars allowed in hashids, default is lib.uriSafe
* @param {string} [options.prefix] - repend with prefix
* @return {string}
* @memberof module:lib
* @method slug
*/
lib.slug = function(options)
{
var bits = "0000" + BigInt("0x" + lib.uuid()).toString(2);
var bytes = [];
for (let i = 0; i < bits.length; i += 6) bytes.push(bits.substr(i, 6));
const alphabet = options?.alphabet || lib.uriSafe;
return (options?.prefix || "") + bytes.map((x) => alphabet[parseInt(x, 2) % alphabet.length]).join("");
}
/**
* 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 id into original components: now, node, counter
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;
}