1 | const ALPHABET = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
|
2 |
|
3 | const getRandomValues = window.crypto && window.crypto.getRandomValues &&
|
4 | window.crypto.getRandomValues.bind(window.crypto);
|
5 |
|
6 | export default class KeyGenerator {
|
7 | constructor() {
|
8 | this._lastUniqueKeyTime = 0;
|
9 | this._lastRandomValues = [];
|
10 | }
|
11 |
|
12 | generateUniqueKey(now) {
|
13 | now = now || Date.now();
|
14 | const chars = new Array(20);
|
15 | let prefix = now;
|
16 | for (let i = 7; i >= 0; i--) {
|
17 | chars[i] = ALPHABET.charAt(prefix & 0x3f);
|
18 | prefix = Math.floor(prefix / 64);
|
19 | }
|
20 | if (now === this._lastUniqueKeyTime) {
|
21 | let i = 11;
|
22 | while (i >= 0 && this._lastRandomValues[i] === 63) {
|
23 | this._lastRandomValues[i] = 0;
|
24 | i -= 1;
|
25 | }
|
26 | if (i === -1) {
|
27 | throw new Error('Internal assertion failure: ran out of unique IDs for this millisecond');
|
28 | }
|
29 | this._lastRandomValues[i] += 1;
|
30 | } else {
|
31 | this._lastUniqueKeyTime = now;
|
32 | if (getRandomValues) {
|
33 | const array = new Uint8Array(12);
|
34 | getRandomValues(array);
|
35 | for (let i = 0; i < 12; i++) {
|
36 |
|
37 | this._lastRandomValues[i] = array[i] & (i ? 0x3f : 0x0f);
|
38 | }
|
39 | } else {
|
40 | for (let i = 0; i < 12; i++) {
|
41 |
|
42 | this._lastRandomValues[i] = Math.floor(Math.random() * (i ? 64 : 16));
|
43 | }
|
44 | }
|
45 | }
|
46 | for (let i = 0; i < 12; i++) {
|
47 | chars[i + 8] = ALPHABET[this._lastRandomValues[i]];
|
48 | }
|
49 | return chars.join('');
|
50 | }
|
51 | }
|