@peerbit/react 0.0.33 → 0.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -0
- package/{lib/esm → dist/src}/lockstorage.d.ts +1 -0
- package/dist/src/lockstorage.d.ts.map +1 -0
- package/{lib/esm → dist/src}/lockstorage.js +2 -5
- package/dist/src/lockstorage.js.map +1 -0
- package/{lib/esm → dist/src}/useMount.d.ts +1 -0
- package/dist/src/useMount.d.ts.map +1 -0
- package/dist/src/useMount.js.map +1 -0
- package/{lib/esm → dist/src}/usePeer.d.ts +7 -3
- package/dist/src/usePeer.d.ts.map +1 -0
- package/{lib/esm → dist/src}/usePeer.js +25 -20
- package/dist/src/usePeer.js.map +1 -0
- package/{lib/esm → dist/src}/utils.d.ts +2 -4
- package/dist/src/utils.d.ts.map +1 -0
- package/{lib/esm → dist/src}/utils.js +17 -69
- package/dist/src/utils.js.map +1 -0
- package/package.json +59 -56
- package/src/index.ts +4 -14
- package/src/lockstorage.ts +224 -233
- package/src/useMount.ts +15 -0
- package/src/usePeer.tsx +406 -419
- package/src/utils.ts +99 -168
- package/README.md +0 -24
- package/lib/esm/__tests__/lockstorage.test.d.ts +0 -1
- package/lib/esm/__tests__/lockstorage.test.js +0 -237
- package/lib/esm/__tests__/lockstorage.test.js.map +0 -1
- package/lib/esm/__tests__/singletonLock.test.d.ts +0 -1
- package/lib/esm/__tests__/singletonLock.test.js +0 -71
- package/lib/esm/__tests__/singletonLock.test.js.map +0 -1
- package/lib/esm/__tests__/useQuery.dom.test.d.ts +0 -1
- package/lib/esm/__tests__/useQuery.dom.test.js +0 -433
- package/lib/esm/__tests__/useQuery.dom.test.js.map +0 -1
- package/lib/esm/__tests__/utils.test.d.ts +0 -1
- package/lib/esm/__tests__/utils.test.js +0 -66
- package/lib/esm/__tests__/utils.test.js.map +0 -1
- package/lib/esm/index.d.ts +0 -8
- package/lib/esm/index.js +0 -9
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/lockstorage.js.map +0 -1
- package/lib/esm/useCount.d.ts +0 -11
- package/lib/esm/useCount.js +0 -43
- package/lib/esm/useCount.js.map +0 -1
- package/lib/esm/useLocal.d.ts +0 -20
- package/lib/esm/useLocal.js +0 -73
- package/lib/esm/useLocal.js.map +0 -1
- package/lib/esm/useMount.js.map +0 -1
- package/lib/esm/useOnline.d.ts +0 -11
- package/lib/esm/useOnline.js +0 -65
- package/lib/esm/useOnline.js.map +0 -1
- package/lib/esm/usePeer.js.map +0 -1
- package/lib/esm/useProgram.d.ts +0 -16
- package/lib/esm/useProgram.js +0 -114
- package/lib/esm/useProgram.js.map +0 -1
- package/lib/esm/useQuery.d.ts +0 -49
- package/lib/esm/useQuery.js +0 -418
- package/lib/esm/useQuery.js.map +0 -1
- package/lib/esm/utils.js.map +0 -1
- package/src/__tests__/lockstorage.test.ts +0 -285
- package/src/__tests__/singletonLock.test.ts +0 -85
- package/src/__tests__/useQuery.dom.test.ts +0 -518
- package/src/__tests__/utils.test.ts +0 -90
- package/src/useCount.tsx +0 -63
- package/src/useLocal.tsx +0 -125
- package/src/useMount.tsx +0 -15
- package/src/useOnline.tsx +0 -85
- package/src/useProgram.tsx +0 -148
- package/src/useQuery.tsx +0 -548
- /package/{lib/esm → dist/src}/useMount.js +0 -0
package/src/utils.ts
CHANGED
|
@@ -1,198 +1,129 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Ed25519Keypair,
|
|
3
|
-
import { FastMutex } from "./lockstorage.js";
|
|
4
|
-
import { v4 as uuid } from "uuid";
|
|
1
|
+
import { deserialize, serialize } from "@dao-xyz/borsh";
|
|
2
|
+
import { Ed25519Keypair, fromBase64, toBase64 } from "@peerbit/crypto";
|
|
5
3
|
import sodium from "libsodium-wrappers";
|
|
4
|
+
import { v4 as uuid } from "uuid";
|
|
5
|
+
import { FastMutex } from "./lockstorage.ts";
|
|
6
6
|
|
|
7
7
|
const CLIENT_ID_STORAGE_KEY = "CLIENT_ID";
|
|
8
|
+
const ID_COUNTER_KEY = "idc/";
|
|
9
|
+
|
|
10
|
+
const getKeyId = (prefix: string, id: number) => `${prefix}/${id}`;
|
|
11
|
+
|
|
8
12
|
export const cookiesWhereClearedJustNow = () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const lastPersistedAt = localStorage.getItem("lastPersistedAt");
|
|
14
|
+
if (lastPersistedAt) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
localStorage.setItem("lastPersistedAt", Date.now().toString());
|
|
18
|
+
return true;
|
|
15
19
|
};
|
|
16
20
|
|
|
17
21
|
export const getClientId = (type: "session" | "local") => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
22
|
+
const storage = type === "session" ? sessionStorage : localStorage;
|
|
23
|
+
const idFromStorage = storage.getItem(CLIENT_ID_STORAGE_KEY);
|
|
24
|
+
if (idFromStorage) {
|
|
25
|
+
return idFromStorage;
|
|
26
|
+
}
|
|
27
|
+
const id = uuid();
|
|
28
|
+
storage.setItem(CLIENT_ID_STORAGE_KEY, id);
|
|
29
|
+
return id;
|
|
27
30
|
};
|
|
28
31
|
|
|
29
|
-
const ID_COUNTER_KEY = "idc/";
|
|
30
|
-
|
|
31
|
-
const getKeyId = (prefix: string, id: number) => prefix + "/" + id;
|
|
32
|
-
|
|
33
32
|
export const releaseKey = (path: string, lock: FastMutex) => {
|
|
34
|
-
|
|
33
|
+
lock.release(path);
|
|
35
34
|
};
|
|
36
35
|
|
|
37
36
|
export const getFreeKeypair = async (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
id = "",
|
|
38
|
+
lock: FastMutex,
|
|
39
|
+
lockCondition: () => boolean = () => true,
|
|
40
|
+
options?: {
|
|
41
|
+
releaseLockIfSameId?: boolean;
|
|
42
|
+
releaseFirstLock?: boolean;
|
|
43
|
+
},
|
|
45
44
|
) => {
|
|
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
|
-
localStorage.setItem(
|
|
78
|
-
idCounterKey,
|
|
79
|
-
JSON.stringify(Math.max(idCounter, i + 1))
|
|
80
|
-
);
|
|
81
|
-
await lock.release(idCounterKey);
|
|
82
|
-
return {
|
|
83
|
-
index: i,
|
|
84
|
-
path: key,
|
|
85
|
-
key: await getKeypair(key),
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
throw new Error("Failed to resolve key");
|
|
45
|
+
await sodium.ready;
|
|
46
|
+
const idCounterKey = ID_COUNTER_KEY + id;
|
|
47
|
+
await lock.lock(idCounterKey, () => true);
|
|
48
|
+
let idCounter = JSON.parse(localStorage.getItem(idCounterKey) || "0");
|
|
49
|
+
for (let i = 0; i < 10000; i++) {
|
|
50
|
+
const key = getKeyId(id, i);
|
|
51
|
+
const lockedInfo = lock.getLockedInfo(key);
|
|
52
|
+
if (lockedInfo) {
|
|
53
|
+
if (
|
|
54
|
+
(lockedInfo === lock.clientId && options?.releaseLockIfSameId) ||
|
|
55
|
+
options?.releaseFirstLock
|
|
56
|
+
) {
|
|
57
|
+
await lock.release(key);
|
|
58
|
+
} else {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await lock.lock(key, lockCondition);
|
|
64
|
+
localStorage.setItem(
|
|
65
|
+
idCounterKey,
|
|
66
|
+
JSON.stringify(Math.max(idCounter, i + 1)),
|
|
67
|
+
);
|
|
68
|
+
await lock.release(idCounterKey);
|
|
69
|
+
return {
|
|
70
|
+
index: i,
|
|
71
|
+
path: key,
|
|
72
|
+
key: await getKeypair(key),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
throw new Error("Failed to resolve key");
|
|
89
76
|
};
|
|
90
77
|
|
|
91
|
-
export const getAllKeyPairs = async (id
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
78
|
+
export const getAllKeyPairs = async (id = "") => {
|
|
79
|
+
const idCounterKey = ID_COUNTER_KEY + id;
|
|
80
|
+
const counter = JSON.parse(localStorage.getItem(idCounterKey) || "0");
|
|
81
|
+
const ret: Ed25519Keypair[] = [];
|
|
82
|
+
for (let i = 0; i < counter; i++) {
|
|
83
|
+
const key = getKeyId(id, i);
|
|
84
|
+
const kp = loadKeypair(key);
|
|
85
|
+
if (kp) {
|
|
86
|
+
ret.push(kp);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return ret;
|
|
103
90
|
};
|
|
104
91
|
|
|
105
|
-
let _getKeypair: Promise<
|
|
92
|
+
let _getKeypair: Promise<Ed25519Keypair> | undefined;
|
|
106
93
|
|
|
107
94
|
export const getKeypair = async (keyName: string): Promise<Ed25519Keypair> => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
95
|
+
await _getKeypair;
|
|
96
|
+
const fn = async () => {
|
|
97
|
+
let keypair = loadKeypair(keyName);
|
|
98
|
+
if (keypair) {
|
|
99
|
+
return keypair;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
keypair = await Ed25519Keypair.create();
|
|
103
|
+
saveKeypair(keyName, keypair);
|
|
104
|
+
return keypair;
|
|
105
|
+
};
|
|
106
|
+
_getKeypair = fn();
|
|
107
|
+
return _getKeypair;
|
|
121
108
|
};
|
|
122
109
|
|
|
123
110
|
const saveKeypair = (path: string, key: Ed25519Keypair) => {
|
|
124
|
-
|
|
125
|
-
|
|
111
|
+
const str = toBase64(serialize(key));
|
|
112
|
+
localStorage.setItem(`_keys/${path}`, str);
|
|
126
113
|
};
|
|
127
114
|
|
|
128
115
|
const loadKeypair = (path: string) => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
116
|
+
const item = localStorage.getItem(`_keys/${path}`);
|
|
117
|
+
if (!item) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
return deserialize(fromBase64(item), Ed25519Keypair);
|
|
134
121
|
};
|
|
135
122
|
|
|
136
123
|
export const inIframe = () => {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
124
|
+
try {
|
|
125
|
+
return window.self !== window.top;
|
|
126
|
+
} catch {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
142
129
|
};
|
|
143
|
-
|
|
144
|
-
export function debounceLeadingTrailing<
|
|
145
|
-
T extends (this: any, ...args: any[]) => void,
|
|
146
|
-
>(
|
|
147
|
-
func: T,
|
|
148
|
-
delay: number
|
|
149
|
-
): ((this: ThisParameterType<T>, ...args: Parameters<T>) => void) & {
|
|
150
|
-
cancel: () => void;
|
|
151
|
-
} {
|
|
152
|
-
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
153
|
-
let lastArgs: Parameters<T> | null = null;
|
|
154
|
-
let lastThis: any;
|
|
155
|
-
let pendingTrailing = false;
|
|
156
|
-
|
|
157
|
-
const debounced = function (
|
|
158
|
-
this: ThisParameterType<T>,
|
|
159
|
-
...args: Parameters<T>
|
|
160
|
-
) {
|
|
161
|
-
if (!timeoutId) {
|
|
162
|
-
// Leading call: no timer means this is the first call in this period.
|
|
163
|
-
func.apply(this, args);
|
|
164
|
-
} else {
|
|
165
|
-
// Subsequent calls during the delay mark that a trailing call is needed.
|
|
166
|
-
pendingTrailing = true;
|
|
167
|
-
}
|
|
168
|
-
// Always update with the most recent context and arguments.
|
|
169
|
-
lastArgs = args;
|
|
170
|
-
lastThis = this;
|
|
171
|
-
|
|
172
|
-
// Reset the timer.
|
|
173
|
-
if (timeoutId) {
|
|
174
|
-
clearTimeout(timeoutId);
|
|
175
|
-
}
|
|
176
|
-
timeoutId = setTimeout(() => {
|
|
177
|
-
timeoutId = null;
|
|
178
|
-
// If there were any calls during the delay, call the function on the trailing edge.
|
|
179
|
-
if (pendingTrailing && lastArgs) {
|
|
180
|
-
func.apply(lastThis, lastArgs);
|
|
181
|
-
}
|
|
182
|
-
// Reset the trailing flag after the trailing call.
|
|
183
|
-
pendingTrailing = false;
|
|
184
|
-
}, delay);
|
|
185
|
-
} as ((this: ThisParameterType<T>, ...args: Parameters<T>) => void) & {
|
|
186
|
-
cancel: () => void;
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
debounced.cancel = () => {
|
|
190
|
-
if (timeoutId) {
|
|
191
|
-
clearTimeout(timeoutId);
|
|
192
|
-
timeoutId = null;
|
|
193
|
-
}
|
|
194
|
-
pendingTrailing = false;
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
return debounced;
|
|
198
|
-
}
|
package/README.md
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# @peerbit/react utils
|
|
2
|
-
|
|
3
|
-
This package includes hooks and utilities used across the examples.
|
|
4
|
-
|
|
5
|
-
## Tests
|
|
6
|
-
|
|
7
|
-
- Unit tests run with Mocha against the compiled ESM output.
|
|
8
|
-
- There is an opt-in reproduction test for a previously observed persistent lock issue.
|
|
9
|
-
|
|
10
|
-
Run all tests:
|
|
11
|
-
|
|
12
|
-
```sh
|
|
13
|
-
yarn test
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Run only the persistent-lock repro (intentionally fails):
|
|
17
|
-
|
|
18
|
-
```sh
|
|
19
|
-
yarn test:repro-lock
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Notes:
|
|
23
|
-
- The repro is gated via `REPRO_LOCK_FAIL=1` and is excluded from normal `yarn test` and CI.
|
|
24
|
-
- It simulates sequential sessions sharing a persisted localStorage directory and expects the second session to fail acquiring the singleton lock.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
ISC License (ISC)
|
|
3
|
-
Copyright (c) 2016, Wes Cruver <chieffancypants@gmail.com>
|
|
4
|
-
|
|
5
|
-
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
6
|
-
with or without fee is hereby granted, provided that the above copyright notice
|
|
7
|
-
and this permission notice appear in all copies.
|
|
8
|
-
|
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
11
|
-
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
13
|
-
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
14
|
-
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
15
|
-
THIS SOFTWARE.
|
|
16
|
-
*/
|
|
17
|
-
import { FastMutex } from "../lockstorage.js";
|
|
18
|
-
import sinon from "sinon";
|
|
19
|
-
import nodelocalstorage from "node-localstorage";
|
|
20
|
-
import { expect } from "chai";
|
|
21
|
-
import { delay } from "@peerbit/time";
|
|
22
|
-
import { beforeAll, afterAll, beforeEach, afterEach, describe, it, } from "vitest";
|
|
23
|
-
describe("FastMutex", () => {
|
|
24
|
-
let sandbox;
|
|
25
|
-
beforeAll(() => {
|
|
26
|
-
var LocalStorage = nodelocalstorage.LocalStorage;
|
|
27
|
-
var localStorage = new LocalStorage("./tmp/FastMutex");
|
|
28
|
-
localStorage.clear();
|
|
29
|
-
globalThis.localStorage = localStorage;
|
|
30
|
-
});
|
|
31
|
-
afterAll(() => {
|
|
32
|
-
globalThis.localStorage.clear();
|
|
33
|
-
});
|
|
34
|
-
beforeEach(() => {
|
|
35
|
-
sandbox = sinon.createSandbox();
|
|
36
|
-
localStorage.clear();
|
|
37
|
-
});
|
|
38
|
-
afterEach(() => {
|
|
39
|
-
sandbox.restore();
|
|
40
|
-
localStorage.clear();
|
|
41
|
-
expect(localStorage.length).to.eq(0);
|
|
42
|
-
});
|
|
43
|
-
it("should immediately establish a lock when there is no contention", async () => {
|
|
44
|
-
const fm1 = new FastMutex({ localStorage: localStorage });
|
|
45
|
-
expect(fm1.isLocked("clientId")).to.be.false;
|
|
46
|
-
const stats = await fm1.lock("clientId");
|
|
47
|
-
expect(fm1.isLocked("clientId")).to.be.true;
|
|
48
|
-
});
|
|
49
|
-
it("When another client has a lock (Y is not 0), it should restart to acquire a lock at a later time", function () {
|
|
50
|
-
const fm1 = new FastMutex({
|
|
51
|
-
xPrefix: "xPrefix_",
|
|
52
|
-
yPrefix: "yPrefix_",
|
|
53
|
-
localStorage: localStorage,
|
|
54
|
-
});
|
|
55
|
-
const key = "clientId";
|
|
56
|
-
fm1.setItem(`yPrefix_${key}`, "someOtherMutexId");
|
|
57
|
-
setTimeout(() => {
|
|
58
|
-
localStorage.removeItem(`yPrefix_${key}`);
|
|
59
|
-
}, 20);
|
|
60
|
-
return fm1.lock(key).then(() => {
|
|
61
|
-
expect(fm1.getLockedInfo(key)).to.exist;
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
it("when contending for a lock and ultimately losing, it should restart", () => {
|
|
65
|
-
const key = "somekey";
|
|
66
|
-
const fm = new FastMutex({
|
|
67
|
-
localStorage: localStorage,
|
|
68
|
-
clientId: "uniqueId",
|
|
69
|
-
});
|
|
70
|
-
const stub = sandbox.stub(fm, "getItem");
|
|
71
|
-
// Set up scenario for lock contention where we lost Y
|
|
72
|
-
stub.onCall(0).returns(null); // getItem Y
|
|
73
|
-
stub.onCall(1).returns("lockcontention"); // getItem X
|
|
74
|
-
stub.onCall(2).returns("youLostTheLock"); // getItem Y
|
|
75
|
-
// fastmutex should have restarted, so let's free up the lock:
|
|
76
|
-
stub.onCall(3).returns(null);
|
|
77
|
-
stub.onCall(4).returns("uniqueId");
|
|
78
|
-
return fm.lock(key).then((stats) => {
|
|
79
|
-
expect(stats.restartCount).to.eq(1);
|
|
80
|
-
expect(stats.locksLost).to.eq(1);
|
|
81
|
-
expect(stats.contentionCount).to.eq(1);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
it("When contending for a lock and ultimately winning, it should not restart", () => {
|
|
85
|
-
const key = "somekey";
|
|
86
|
-
const fm = new FastMutex({
|
|
87
|
-
localStorage: localStorage,
|
|
88
|
-
clientId: "uniqueId",
|
|
89
|
-
});
|
|
90
|
-
const stub = sandbox.stub(fm, "getItem");
|
|
91
|
-
// Set up scenario for lock contention where we lost Y
|
|
92
|
-
stub.onCall(0).returns(null); // getItem Y
|
|
93
|
-
stub.onCall(1).returns("lockContention");
|
|
94
|
-
stub.onCall(2).returns("uniqueId");
|
|
95
|
-
const spy = sandbox.spy(fm, "lock");
|
|
96
|
-
return fm.lock(key).then((stats) => {
|
|
97
|
-
expect(stats.restartCount).to.eq(0);
|
|
98
|
-
expect(stats.locksLost).to.eq(0);
|
|
99
|
-
expect(stats.contentionCount).to.eq(1);
|
|
100
|
-
expect(spy.callCount).to.eq(1);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
// This is just to ensure that the internals of FastMutex have prefixes on the
|
|
104
|
-
// X and Y locks such that two different FM clients can acquire locks on
|
|
105
|
-
// different keys concurrently without clashing.
|
|
106
|
-
it("should not clash with other fastMutex locks", async () => {
|
|
107
|
-
const yPrefix = "yLock";
|
|
108
|
-
const xPrefix = "xLock";
|
|
109
|
-
const opts = { localStorage, yPrefix, xPrefix };
|
|
110
|
-
const fm1 = new FastMutex(opts);
|
|
111
|
-
const fm2 = new FastMutex(opts);
|
|
112
|
-
let lock1Acquired = false;
|
|
113
|
-
let lock2Acquired = false;
|
|
114
|
-
/* eslint-disable jest/valid-expect-in-promise */
|
|
115
|
-
const lock1Promise = fm1.lock("lock1").then((stats) => {
|
|
116
|
-
lock1Acquired = true;
|
|
117
|
-
expect(localStorage.getItem(yPrefix + "lock1")).to.exist;
|
|
118
|
-
return stats;
|
|
119
|
-
});
|
|
120
|
-
/* eslint-disable jest/valid-expect-in-promise */
|
|
121
|
-
const lock2Promise = fm2.lock("lock2").then((stats) => {
|
|
122
|
-
lock2Acquired = true;
|
|
123
|
-
expect(localStorage.getItem(yPrefix + "lock2")).to.exist;
|
|
124
|
-
return stats;
|
|
125
|
-
});
|
|
126
|
-
await Promise.all([lock1Promise, lock2Promise]).then(() => {
|
|
127
|
-
expect(lock1Acquired).to.be.true;
|
|
128
|
-
expect(lock2Acquired).to.be.true;
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
it("release() should remove the y lock in localStorage", () => {
|
|
132
|
-
const key = "somekey";
|
|
133
|
-
const fm1 = new FastMutex({
|
|
134
|
-
localStorage: localStorage,
|
|
135
|
-
clientId: "releaseTestId",
|
|
136
|
-
yPrefix: "yLock",
|
|
137
|
-
});
|
|
138
|
-
return fm1
|
|
139
|
-
.lock(key)
|
|
140
|
-
.then(() => {
|
|
141
|
-
expect(fm1.getItem("yLock" + key)).to.eq("releaseTestId");
|
|
142
|
-
return fm1.release(key);
|
|
143
|
-
})
|
|
144
|
-
.then(() => {
|
|
145
|
-
expect(fm1.getItem("yLock" + key)).to.be.undefined;
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
// this is essentially just a better way to test that two locks cannot get
|
|
149
|
-
// an exclusive lock until the other releases. It's a bit more accurate
|
|
150
|
-
// than the test above ("release should remove the y lock in localstorage")
|
|
151
|
-
it("two clients should never get locks at the same time", function () {
|
|
152
|
-
const fm1 = new FastMutex({ localStorage: localStorage });
|
|
153
|
-
const fm2 = new FastMutex({ localStorage: localStorage });
|
|
154
|
-
let fm1LockReleased = false;
|
|
155
|
-
const lockHoldTime = 10;
|
|
156
|
-
return fm1
|
|
157
|
-
.lock("clientId")
|
|
158
|
-
.then(() => {
|
|
159
|
-
// before the lock is released, try to establish another lock:
|
|
160
|
-
var lock2Promise = fm2.lock("clientId");
|
|
161
|
-
expect(fm1LockReleased).to.be.false;
|
|
162
|
-
// in a few milliseconds, release the lock
|
|
163
|
-
setTimeout(() => {
|
|
164
|
-
fm1.release("clientId");
|
|
165
|
-
fm1LockReleased = true;
|
|
166
|
-
}, lockHoldTime);
|
|
167
|
-
return lock2Promise;
|
|
168
|
-
})
|
|
169
|
-
.then((lock2) => {
|
|
170
|
-
// this will only execute once the other lock was released
|
|
171
|
-
expect(fm1LockReleased).to.be.true;
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
it("should throw if lock is never acquired after set time period", async () => {
|
|
175
|
-
const fm1 = new FastMutex({ localStorage: localStorage, timeout: 50 });
|
|
176
|
-
const fm2 = new FastMutex({ localStorage: localStorage, timeout: 50 });
|
|
177
|
-
await fm1.lock("timeoutTest");
|
|
178
|
-
const start = Date.now();
|
|
179
|
-
let threw = false;
|
|
180
|
-
try {
|
|
181
|
-
await fm2.lock("timeoutTest");
|
|
182
|
-
}
|
|
183
|
-
catch (e) {
|
|
184
|
-
threw = true;
|
|
185
|
-
}
|
|
186
|
-
const elapsed = Date.now() - start;
|
|
187
|
-
expect(threw).to.be.true;
|
|
188
|
-
expect(elapsed).to.be.greaterThan(0);
|
|
189
|
-
});
|
|
190
|
-
it("should ignore expired locks", async () => {
|
|
191
|
-
const fm1 = new FastMutex({
|
|
192
|
-
localStorage: localStorage,
|
|
193
|
-
timeout: 5000,
|
|
194
|
-
yPrefix: "yLock",
|
|
195
|
-
clientId: "timeoutClient",
|
|
196
|
-
});
|
|
197
|
-
const expiredRecord = {
|
|
198
|
-
expiresAt: new Date().getTime() - 5000,
|
|
199
|
-
value: "oldclient",
|
|
200
|
-
};
|
|
201
|
-
localStorage.setItem("yLocktimeoutTest", JSON.stringify(expiredRecord));
|
|
202
|
-
expect(JSON.parse(localStorage.getItem("yLocktimeoutTest")).value).to.eq("oldclient");
|
|
203
|
-
await fm1.lock("timeoutTest"); // should not throw
|
|
204
|
-
});
|
|
205
|
-
it("should reset the client stats after lock is released", async () => {
|
|
206
|
-
// without resetting the stats, the acquireStart will always be set, and
|
|
207
|
-
// after `timeout` ms, will be unable to acquire a lock anymore
|
|
208
|
-
const fm1 = new FastMutex({ localStorage: localStorage, timeout: 50 });
|
|
209
|
-
let keepLock = true;
|
|
210
|
-
let keepLockFn = () => keepLock;
|
|
211
|
-
await fm1.lock("resetStats", keepLockFn);
|
|
212
|
-
expect(fm1.isLocked("resetStats")).to.be.true;
|
|
213
|
-
keepLock = false;
|
|
214
|
-
await delay(100); // await timeout
|
|
215
|
-
expect(fm1.isLocked("resetStats")).to.be.false;
|
|
216
|
-
const p = fm1.lock("resetStats").then(() => fm1.release("resetStats"));
|
|
217
|
-
await p; // should not throw
|
|
218
|
-
});
|
|
219
|
-
it("can keep lock with callback function", async () => {
|
|
220
|
-
const fm1 = new FastMutex({ localStorage: localStorage, timeout: 50 });
|
|
221
|
-
await fm1.lock("x");
|
|
222
|
-
await fm1.release("x");
|
|
223
|
-
expect(fm1.isLocked("x")).to.be.false;
|
|
224
|
-
await fm1.lock("x").then(() => fm1.release("x"));
|
|
225
|
-
});
|
|
226
|
-
it("should reset the client stats if the lock has expired", async () => {
|
|
227
|
-
// in the event a lock cannot be acquired within `timeout`, acquireStart
|
|
228
|
-
// will never be reset, and a subsequent call (after the `timeout`) would
|
|
229
|
-
// immediately fail
|
|
230
|
-
const fm1 = new FastMutex({ localStorage: localStorage, timeout: 50 });
|
|
231
|
-
await fm1.lock("resetStats");
|
|
232
|
-
// try to acquire a lock after `timeout`:
|
|
233
|
-
await delay(75); // a small buffer over timeout to avoid flakiness
|
|
234
|
-
await fm1.lock("resetStats"); // should not throw
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
//# sourceMappingURL=lockstorage.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lockstorage.test.js","sourceRoot":"","sources":["../../../src/__tests__/lockstorage.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { expect } from "chai";
|
|
2
|
-
import nodelocalstorage from "node-localstorage";
|
|
3
|
-
import { FastMutex } from "../lockstorage.js";
|
|
4
|
-
import { beforeAll, beforeEach, afterEach, describe, it } from "vitest";
|
|
5
|
-
describe("FastMutex singleton semantics", () => {
|
|
6
|
-
let localStorage;
|
|
7
|
-
beforeAll(() => {
|
|
8
|
-
const LocalStorage = nodelocalstorage.LocalStorage;
|
|
9
|
-
localStorage = new LocalStorage("./tmp/FastMutex-singleton");
|
|
10
|
-
globalThis.localStorage = localStorage;
|
|
11
|
-
});
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
localStorage.clear();
|
|
14
|
-
});
|
|
15
|
-
afterEach(() => {
|
|
16
|
-
localStorage.clear();
|
|
17
|
-
expect(localStorage.length).to.eq(0);
|
|
18
|
-
});
|
|
19
|
-
it("allows same-session to reacquire the singleton lock when replaceIfSameClient is true", async () => {
|
|
20
|
-
const key = "localId-singleton";
|
|
21
|
-
const fm1 = new FastMutex({
|
|
22
|
-
localStorage,
|
|
23
|
-
clientId: "session-1",
|
|
24
|
-
timeout: 200,
|
|
25
|
-
});
|
|
26
|
-
// First acquire and keep the lock alive
|
|
27
|
-
await fm1.lock(key, () => true);
|
|
28
|
-
expect(fm1.isLocked(key)).to.be.true;
|
|
29
|
-
// Reacquire from the same client with replaceIfSameClient
|
|
30
|
-
const start = Date.now();
|
|
31
|
-
await fm1.lock(key, () => true, { replaceIfSameClient: true });
|
|
32
|
-
const elapsed = Date.now() - start;
|
|
33
|
-
// Should not time out and should be very fast
|
|
34
|
-
expect(elapsed).to.be.lessThan(100);
|
|
35
|
-
expect(fm1.isLocked(key)).to.be.true;
|
|
36
|
-
fm1.release(key);
|
|
37
|
-
expect(fm1.isLocked(key)).to.be.false;
|
|
38
|
-
});
|
|
39
|
-
it("blocks a different session while held, then allows after release", async () => {
|
|
40
|
-
const key = "localId-singleton";
|
|
41
|
-
const fm1 = new FastMutex({
|
|
42
|
-
localStorage,
|
|
43
|
-
clientId: "session-1",
|
|
44
|
-
timeout: 500,
|
|
45
|
-
});
|
|
46
|
-
const fm2 = new FastMutex({
|
|
47
|
-
localStorage,
|
|
48
|
-
clientId: "session-2",
|
|
49
|
-
timeout: 100, // short timeout to trigger failure while held
|
|
50
|
-
});
|
|
51
|
-
await fm1.lock(key, () => true);
|
|
52
|
-
expect(fm1.isLocked(key)).to.be.true;
|
|
53
|
-
// Attempt to acquire from a different client should fail within timeout
|
|
54
|
-
let failed = false;
|
|
55
|
-
try {
|
|
56
|
-
await fm2.lock(key, () => true);
|
|
57
|
-
}
|
|
58
|
-
catch (e) {
|
|
59
|
-
failed = true;
|
|
60
|
-
}
|
|
61
|
-
expect(failed).to.be.true;
|
|
62
|
-
// After release, the second client should be able to acquire
|
|
63
|
-
fm1.release(key);
|
|
64
|
-
expect(fm1.isLocked(key)).to.be.false;
|
|
65
|
-
await fm2.lock(key, () => true);
|
|
66
|
-
expect(fm2.isLocked(key)).to.be.true;
|
|
67
|
-
fm2.release(key);
|
|
68
|
-
expect(fm2.isLocked(key)).to.be.false;
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
//# sourceMappingURL=singletonLock.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"singletonLock.test.js","sourceRoot":"","sources":["../../../src/__tests__/singletonLock.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|