-
Notifications
You must be signed in to change notification settings - Fork 5
/
id.js
90 lines (77 loc) · 2.17 KB
/
id.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
* Copyright (c) 2016 Rafał Michalski <[email protected]>
*/
"use strict";
/*
from https://docs.mongodb.com/manual/reference/method/ObjectId/
The 12-byte id value consists of:
- 4-byte value representing the seconds since the Unix epoch (most significant byte first)
- 3-byte machine identifier
- 2-byte process id, and
- 3-byte counter, starting with a random value.
*/
const crypto = require('crypto');
const os = require('os');
const isBuffer = Buffer.isBuffer;
const now = Date.now;
const machineId = crypto.createHash('md5').update(os.hostname()).digest();
const buffer = Buffer.alloc(12);
machineId.copy(buffer, 4, 0, 3);
buffer.writeUInt16BE(process.pid & 0xffff, 7);
var counter = crypto.randomBytes(3).readUIntBE(0, 3);
/**
* Generates fresh unique id.
*
* genIdent([encoding])
* genIdent(buffer[, offset])
*
* @param {string|Buffer} [encoding] or buffer
* @param {number} [offset] optional buffer offset
* @return {string|Buffer}
**/
exports.genIdent = function(encoding, offset) {
var time = (now()/1000)>>>0;
buffer.writeUInt32BE(time, 0, true);
buffer.writeUIntBE(counter++, 9, 3, true);
counter &= 0xffffff;
if (isBuffer(encoding)) {
buffer.copy(encoding, offset>>>0, 0, 12);
return encoding;
}
else return encoding === 'buffer' ? Buffer.from(buffer) : buffer.toString(encoding||'hex');
};
const IDMATCH = /^[0-9a-f]{24}$/;
/**
* Tests for unique id type.
*
* @param {string|Buffer} value
* @return {bool}
**/
exports.isIdent = function(value) {
return (isBuffer(value) && value.length === 12) || ('string' === typeof value && IDMATCH.test(value));
};
const timeBuf = Buffer.alloc(4);
/**
* Extracts seconds from unique id.
*
* @param {string|Buffer} value
* @param {number} [offset]
* @return {number}
**/
exports.getSeconds = function(value, offset) {
if ('string' === typeof value) {
var encoding, len = value.length;
if (len === 16) {
encoding = 'base64';
}
else if (len === 24) {
encoding = 'hex';
}
else throw new TypeError("invalid string value");
timeBuf.write(value, 0, 4, encoding);
value = timeBuf;
offset = 0;
}
else offset >>>= 0;
return value.readUInt32BE(offset, true);
};