@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/lockstorage.ts
CHANGED
|
@@ -14,260 +14,251 @@ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
|
14
14
|
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
15
15
|
THIS SOFTWARE.
|
|
16
16
|
*/
|
|
17
|
-
|
|
18
17
|
import debugFn from "debug";
|
|
19
18
|
import { v4 as uuid } from "uuid";
|
|
19
|
+
|
|
20
20
|
const debug = debugFn("FastMutex");
|
|
21
21
|
|
|
22
22
|
export class FastMutex {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
clientId: string;
|
|
24
|
+
xPrefix: string;
|
|
25
|
+
yPrefix: string;
|
|
26
|
+
timeout: number;
|
|
27
|
+
localStorage: any;
|
|
28
|
+
intervals: Map<string, any>;
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
constructor({
|
|
31
|
+
clientId = uuid(),
|
|
32
|
+
xPrefix = "_MUTEX_LOCK_X_",
|
|
33
|
+
yPrefix = "_MUTEX_LOCK_Y_",
|
|
34
|
+
timeout = 5000,
|
|
35
|
+
localStorage = undefined as any,
|
|
36
|
+
} = {}) {
|
|
37
|
+
this.clientId = clientId;
|
|
38
|
+
this.xPrefix = xPrefix;
|
|
39
|
+
this.yPrefix = yPrefix;
|
|
40
|
+
this.timeout = timeout;
|
|
41
|
+
this.intervals = new Map();
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
this.localStorage = localStorage || window.localStorage;
|
|
44
|
+
}
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
46
|
+
lock(
|
|
47
|
+
key: string,
|
|
48
|
+
keepLocked?: () => boolean,
|
|
49
|
+
options?: { replaceIfSameClient?: boolean },
|
|
50
|
+
): Promise<{
|
|
51
|
+
restartCount: number;
|
|
52
|
+
contentionCount: number;
|
|
53
|
+
locksLost: number;
|
|
54
|
+
}> {
|
|
55
|
+
debug(
|
|
56
|
+
'Attempting to acquire Lock on "%s" using FastMutex instance "%s"',
|
|
57
|
+
key,
|
|
58
|
+
this.clientId,
|
|
59
|
+
);
|
|
60
|
+
const x = this.xPrefix + key;
|
|
61
|
+
const y = this.yPrefix + key;
|
|
62
|
+
let acquireStart = Date.now();
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
let restartCount = 0;
|
|
65
|
+
let contentionCount = 0;
|
|
66
|
+
let locksLost = 0;
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
}
|
|
68
|
+
const acquireLock = (key: string) => {
|
|
69
|
+
// If the option is set and the same client already holds both keys,
|
|
70
|
+
// update the expiry and resolve immediately.
|
|
71
|
+
if (options?.replaceIfSameClient) {
|
|
72
|
+
const currentX = this.getItem(x);
|
|
73
|
+
const currentY = this.getItem(y);
|
|
74
|
+
if (currentX === this.clientId && currentY === this.clientId) {
|
|
75
|
+
// Update expiry so that the lock is effectively "replaced"
|
|
76
|
+
this.setItem(x, this.clientId, keepLocked);
|
|
77
|
+
this.setItem(y, this.clientId, keepLocked);
|
|
78
|
+
debug(
|
|
79
|
+
'FastMutex client "%s" replaced its own lock on "%s".',
|
|
80
|
+
this.clientId,
|
|
81
|
+
key,
|
|
82
|
+
);
|
|
83
|
+
return resolve({
|
|
84
|
+
restartCount,
|
|
85
|
+
contentionCount,
|
|
86
|
+
locksLost,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
93
90
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return reject(
|
|
111
|
-
new Error(
|
|
112
|
-
`Lock could not be acquired within ${this.timeout}ms`
|
|
113
|
-
)
|
|
114
|
-
);
|
|
115
|
-
}
|
|
91
|
+
// Check for overall retries/timeouts.
|
|
92
|
+
if (restartCount > 1000 || contentionCount > 1000 || locksLost > 1000) {
|
|
93
|
+
return reject("Failed to resolve lock");
|
|
94
|
+
}
|
|
95
|
+
const elapsedTime = Date.now() - acquireStart;
|
|
96
|
+
if (elapsedTime >= this.timeout) {
|
|
97
|
+
debug(
|
|
98
|
+
'Lock on "%s" could not be acquired within %sms by FastMutex client "%s"',
|
|
99
|
+
key,
|
|
100
|
+
this.timeout,
|
|
101
|
+
this.clientId,
|
|
102
|
+
);
|
|
103
|
+
return reject(
|
|
104
|
+
new Error(`Lock could not be acquired within ${this.timeout}ms`),
|
|
105
|
+
);
|
|
106
|
+
}
|
|
116
107
|
|
|
117
|
-
|
|
118
|
-
|
|
108
|
+
// First, set key X.
|
|
109
|
+
this.setItem(x, this.clientId, keepLocked);
|
|
119
110
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
111
|
+
// Check if key Y exists (another client may be acquiring the lock)
|
|
112
|
+
let lsY = this.getItem(y);
|
|
113
|
+
if (lsY) {
|
|
114
|
+
debug("Lock exists on Y (%s), restarting...", lsY);
|
|
115
|
+
restartCount++;
|
|
116
|
+
setTimeout(() => acquireLock(key), 10);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
128
119
|
|
|
129
|
-
|
|
130
|
-
|
|
120
|
+
// Request the inner lock by setting Y.
|
|
121
|
+
this.setItem(y, this.clientId, keepLocked);
|
|
131
122
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
123
|
+
// Re-check X; if it was changed, we have contention.
|
|
124
|
+
let lsX = this.getItem(x);
|
|
125
|
+
if (lsX !== this.clientId) {
|
|
126
|
+
contentionCount++;
|
|
127
|
+
debug('Lock contention detected. X="%s"', lsX);
|
|
128
|
+
setTimeout(() => {
|
|
129
|
+
lsY = this.getItem(y);
|
|
130
|
+
if (lsY === this.clientId) {
|
|
131
|
+
debug(
|
|
132
|
+
'FastMutex client "%s" won the lock contention on "%s"',
|
|
133
|
+
this.clientId,
|
|
134
|
+
key,
|
|
135
|
+
);
|
|
136
|
+
resolve({
|
|
137
|
+
restartCount,
|
|
138
|
+
contentionCount,
|
|
139
|
+
locksLost,
|
|
140
|
+
});
|
|
141
|
+
} else {
|
|
142
|
+
restartCount++;
|
|
143
|
+
locksLost++;
|
|
144
|
+
debug(
|
|
145
|
+
'FastMutex client "%s" lost the lock contention on "%s" to another process (%s). Restarting...',
|
|
146
|
+
this.clientId,
|
|
147
|
+
key,
|
|
148
|
+
lsY,
|
|
149
|
+
);
|
|
150
|
+
setTimeout(() => acquireLock(key), 10);
|
|
151
|
+
}
|
|
152
|
+
}, 50);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
164
155
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
156
|
+
// No contention: lock is acquired.
|
|
157
|
+
debug(
|
|
158
|
+
'FastMutex client "%s" acquired a lock on "%s" with no contention',
|
|
159
|
+
this.clientId,
|
|
160
|
+
key,
|
|
161
|
+
);
|
|
162
|
+
resolve({ restartCount, contentionCount, locksLost });
|
|
163
|
+
};
|
|
173
164
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
165
|
+
acquireLock(key);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
177
168
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
169
|
+
isLocked(key: string) {
|
|
170
|
+
const x = this.xPrefix + key;
|
|
171
|
+
const y = this.yPrefix + key;
|
|
172
|
+
return !!this.getItem(x) || !!this.getItem(y);
|
|
173
|
+
}
|
|
183
174
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
175
|
+
getLockedInfo(key: string): string | undefined {
|
|
176
|
+
const x = this.xPrefix + key;
|
|
177
|
+
const y = this.yPrefix + key;
|
|
178
|
+
return this.getItem(x) || this.getItem(y);
|
|
179
|
+
}
|
|
189
180
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
181
|
+
release(key: string) {
|
|
182
|
+
debug(
|
|
183
|
+
'FastMutex client "%s" is releasing lock on "%s"',
|
|
184
|
+
this.clientId,
|
|
185
|
+
key,
|
|
186
|
+
);
|
|
187
|
+
let ps = [this.yPrefix + key, this.xPrefix + key];
|
|
188
|
+
for (const p of ps) {
|
|
189
|
+
clearInterval(this.intervals.get(p));
|
|
190
|
+
this.intervals.delete(p);
|
|
191
|
+
this.localStorage.removeItem(p);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
203
194
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
195
|
+
/**
|
|
196
|
+
* Helper function to wrap all values in an object that includes the time (so
|
|
197
|
+
* that we can expire it in the future) and json.stringify's it
|
|
198
|
+
*/
|
|
199
|
+
setItem(key: string, value: any, keepLocked?: () => boolean) {
|
|
200
|
+
if (!keepLocked) {
|
|
201
|
+
return this.localStorage.setItem(
|
|
202
|
+
key,
|
|
203
|
+
JSON.stringify({
|
|
204
|
+
expiresAt: new Date().getTime() + this.timeout,
|
|
205
|
+
value,
|
|
206
|
+
}),
|
|
207
|
+
);
|
|
208
|
+
} else {
|
|
209
|
+
let getExpiry = () => +new Date() + this.timeout;
|
|
210
|
+
const ret = this.localStorage.setItem(
|
|
211
|
+
key,
|
|
212
|
+
JSON.stringify({
|
|
213
|
+
expiresAt: getExpiry(),
|
|
214
|
+
value,
|
|
215
|
+
}),
|
|
216
|
+
);
|
|
217
|
+
const interval = setInterval(() => {
|
|
218
|
+
if (!keepLocked()) {
|
|
219
|
+
this.localStorage.setItem(
|
|
220
|
+
// TODO, release directly?
|
|
221
|
+
key,
|
|
222
|
+
JSON.stringify({
|
|
223
|
+
expiresAt: 0,
|
|
224
|
+
value,
|
|
225
|
+
}),
|
|
226
|
+
);
|
|
227
|
+
} else {
|
|
228
|
+
this.localStorage.setItem(
|
|
229
|
+
key,
|
|
230
|
+
JSON.stringify({
|
|
231
|
+
expiresAt: getExpiry(), // bump expiry
|
|
232
|
+
value,
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}, this.timeout);
|
|
237
|
+
this.intervals.set(key, interval);
|
|
238
|
+
return ret;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
250
241
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
242
|
+
/**
|
|
243
|
+
* Helper function to parse JSON encoded values set in localStorage
|
|
244
|
+
*/
|
|
245
|
+
getItem(key: string): string | undefined {
|
|
246
|
+
const item = this.localStorage.getItem(key);
|
|
247
|
+
if (!item) return;
|
|
257
248
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
249
|
+
const parsed = JSON.parse(item);
|
|
250
|
+
if (new Date().getTime() - parsed.expiresAt >= this.timeout) {
|
|
251
|
+
debug(
|
|
252
|
+
'FastMutex client "%s" removed an expired record on "%s"',
|
|
253
|
+
this.clientId,
|
|
254
|
+
key,
|
|
255
|
+
);
|
|
256
|
+
this.localStorage.removeItem(key);
|
|
257
|
+
clearInterval(this.intervals.get(key));
|
|
258
|
+
this.intervals.delete(key);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
270
261
|
|
|
271
|
-
|
|
272
|
-
|
|
262
|
+
return JSON.parse(item).value;
|
|
263
|
+
}
|
|
273
264
|
}
|
package/src/useMount.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type EffectCallback, useEffect, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
export const useMount = (effect: EffectCallback) => {
|
|
4
|
+
const mounted = useRef(false);
|
|
5
|
+
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
if (!mounted.current) {
|
|
8
|
+
effect();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
mounted.current = true;
|
|
12
|
+
|
|
13
|
+
return () => {};
|
|
14
|
+
}, [mounted.current]);
|
|
15
|
+
};
|