sliftutils 0.59.0 → 0.61.0
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/index.d.ts +18 -0
- package/misc/openrouter.ts +1 -1
- package/package.json +1 -1
- package/render-utils/colors.d.ts +6 -0
- package/render-utils/colors.tsx +6 -8
- package/storage/IStorage.d.ts +1 -0
- package/storage/IStorage.ts +2 -0
- package/storage/StorageObservable.d.ts +3 -0
- package/storage/StorageObservable.ts +10 -1
- package/storage/TransactionStorage.d.ts +4 -0
- package/storage/TransactionStorage.ts +80 -9
package/index.d.ts
CHANGED
|
@@ -483,6 +483,16 @@ declare module "sliftutils/render-utils/asyncObservable" {
|
|
|
483
483
|
|
|
484
484
|
}
|
|
485
485
|
|
|
486
|
+
declare module "sliftutils/render-utils/colors" {
|
|
487
|
+
export declare const redButton: string;
|
|
488
|
+
export declare const yellowButton: string;
|
|
489
|
+
export declare const greenButton: string;
|
|
490
|
+
export declare const errorMessage: string;
|
|
491
|
+
export declare const warnMessage: string;
|
|
492
|
+
export declare const AnchorClass: string;
|
|
493
|
+
|
|
494
|
+
}
|
|
495
|
+
|
|
486
496
|
declare module "sliftutils/render-utils/mobxTyped" {
|
|
487
497
|
export declare function configureMobxNextFrameScheduler(): void;
|
|
488
498
|
|
|
@@ -786,6 +796,7 @@ declare module "sliftutils/storage/IStorage" {
|
|
|
786
796
|
lastModified: number;
|
|
787
797
|
}>;
|
|
788
798
|
reset(): Promise<void>;
|
|
799
|
+
watchResync?: (callback: () => void) => void;
|
|
789
800
|
};
|
|
790
801
|
export type IStorageRaw = {
|
|
791
802
|
get(key: string): Promise<Buffer | undefined>;
|
|
@@ -904,6 +915,9 @@ declare module "sliftutils/storage/StorageObservable" {
|
|
|
904
915
|
synced: {
|
|
905
916
|
keySeqNum: number;
|
|
906
917
|
};
|
|
918
|
+
resynced: {
|
|
919
|
+
seqNum: number;
|
|
920
|
+
};
|
|
907
921
|
constructor(storage: IStorage<T>);
|
|
908
922
|
get(key: string): T | undefined;
|
|
909
923
|
set(key: string, value: T): void;
|
|
@@ -942,11 +956,14 @@ declare module "sliftutils/storage/TransactionStorage" {
|
|
|
942
956
|
private debugName;
|
|
943
957
|
private writeDelay;
|
|
944
958
|
cache: Map<string, TransactionEntry>;
|
|
959
|
+
private diskFiles;
|
|
945
960
|
private currentChunk;
|
|
946
961
|
private entryCount;
|
|
947
962
|
private static allStorage;
|
|
948
963
|
constructor(rawStorage: IStorageRaw, debugName: string, writeDelay?: number);
|
|
949
964
|
static compressAll(): Promise<void>;
|
|
965
|
+
private resyncCallbacks;
|
|
966
|
+
watchResync(callback: () => void): void;
|
|
950
967
|
private init;
|
|
951
968
|
private getCurrentChunk;
|
|
952
969
|
private onAddToChunk;
|
|
@@ -963,6 +980,7 @@ declare module "sliftutils/storage/TransactionStorage" {
|
|
|
963
980
|
pushAppend(entry: TransactionEntry): Promise<void>;
|
|
964
981
|
private updatePendingAppends;
|
|
965
982
|
getKeys(): Promise<string[]>;
|
|
983
|
+
checkDisk(): Promise<void>;
|
|
966
984
|
private loadAllTransactions;
|
|
967
985
|
private parseTransactionFile;
|
|
968
986
|
private applyTransactionEntries;
|
package/misc/openrouter.ts
CHANGED
package/package.json
CHANGED
package/render-utils/colors.tsx
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { css } from "typesafecss";
|
|
2
2
|
|
|
3
|
-
export const redButton = css.hsl(0, 75, 50).bord(1, "hsl(0, 75%, 75%)").background("hsl(0, 75%, 75%)", "hover");
|
|
4
|
-
export const yellowButton = css.hsl(50, 90, 50).bord(1, "hsl(40, 75%, 75%)").color("hsl(0, 0%, 16%)!important").background("hsl(40, 75%, 75%)", "hover");
|
|
5
|
-
export const greenButton = css.hsl(110, 65, 45).bord(1, { h: 110, s: 65, l: 75 }).background("hsl(110, 65%, 90%)", "hover");
|
|
3
|
+
export const redButton = css.hsl(0, 75, 50).bord(1, "hsl(0, 75%, 75%)").background("hsl(0, 75%, 75%)", "hover") as string;
|
|
4
|
+
export const yellowButton = css.hsl(50, 90, 50).bord(1, "hsl(40, 75%, 75%)").color("hsl(0, 0%, 16%)!important").background("hsl(40, 75%, 75%)", "hover") as string;
|
|
5
|
+
export const greenButton = css.hsl(110, 65, 45).bord(1, { h: 110, s: 65, l: 75 }).background("hsl(110, 65%, 90%)", "hover") as string;
|
|
6
6
|
|
|
7
7
|
export const errorMessage = css.hsl(0, 75, 50).color("white")
|
|
8
8
|
.padding("4px 6px", "soft")
|
|
9
|
-
.whiteSpace("pre-wrap").display("inline-block", "soft")
|
|
10
|
-
;
|
|
9
|
+
.whiteSpace("pre-wrap").display("inline-block", "soft") as string;
|
|
11
10
|
export const warnMessage = css.hsl(50, 75, 50).color("hsl(0, 0%, 7%)", "important", "soft")
|
|
12
11
|
.padding("4px 6px", "soft")
|
|
13
|
-
.whiteSpace("pre-wrap").display("inline-block", "soft")
|
|
14
|
-
;
|
|
12
|
+
.whiteSpace("pre-wrap").display("inline-block", "soft") as string;
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
export const AnchorClass = (
|
|
18
|
-
css.textDecoration("none").color("hsl(210, 75%, 65%)").opacity(0.8, "hover")
|
|
16
|
+
css.textDecoration("none").color("hsl(210, 75%, 65%)").opacity(0.8, "hover") as string
|
|
19
17
|
);
|
package/storage/IStorage.d.ts
CHANGED
package/storage/IStorage.ts
CHANGED
|
@@ -22,6 +22,8 @@ export type IStorage<T> = {
|
|
|
22
22
|
lastModified: number;
|
|
23
23
|
}>;
|
|
24
24
|
reset(): Promise<void>;
|
|
25
|
+
// Allows watching for when the storage detects and underlying changes, and resyncs all of it's data (which might
|
|
26
|
+
watchResync?: (callback: () => void) => void;
|
|
25
27
|
};
|
|
26
28
|
// NOTE: In the file system some characters are disallowed, and some characters do special things
|
|
27
29
|
// (/ makes a folder). And there are even more rules, such as lengths per folder, etc, etc.
|
|
@@ -11,9 +11,16 @@ export class StorageSync<T> implements IStorageSync<T> {
|
|
|
11
11
|
keySeqNum: 0,
|
|
12
12
|
}, undefined, { deep: false });
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
resynced = observable({ seqNum: 0 });
|
|
15
|
+
|
|
16
|
+
constructor(public storage: IStorage<T>) {
|
|
17
|
+
storage.watchResync?.(() => {
|
|
18
|
+
this.resynced.seqNum++;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
15
21
|
|
|
16
22
|
public get(key: string): T | undefined {
|
|
23
|
+
this.resynced.seqNum;
|
|
17
24
|
if (!this.cached.has(key)) {
|
|
18
25
|
this.cached.set(key, undefined);
|
|
19
26
|
void this.getPromise(key);
|
|
@@ -41,12 +48,14 @@ export class StorageSync<T> implements IStorageSync<T> {
|
|
|
41
48
|
}
|
|
42
49
|
private loadedKeys = false;
|
|
43
50
|
public getKeys(): string[] {
|
|
51
|
+
this.resynced.seqNum;
|
|
44
52
|
void this.getKeysPromise();
|
|
45
53
|
this.synced.keySeqNum;
|
|
46
54
|
return Array.from(this.keys);
|
|
47
55
|
}
|
|
48
56
|
|
|
49
57
|
public getInfo(key: string): { size: number; lastModified: number } | undefined {
|
|
58
|
+
this.resynced.seqNum;
|
|
50
59
|
if (!this.infoCached.has(key)) {
|
|
51
60
|
this.infoCached.set(key, { size: 0, lastModified: 0 });
|
|
52
61
|
void this.storage.getInfo(key).then(info => {
|
|
@@ -12,11 +12,14 @@ export declare class TransactionStorage implements IStorage<Buffer> {
|
|
|
12
12
|
private debugName;
|
|
13
13
|
private writeDelay;
|
|
14
14
|
cache: Map<string, TransactionEntry>;
|
|
15
|
+
private diskFiles;
|
|
15
16
|
private currentChunk;
|
|
16
17
|
private entryCount;
|
|
17
18
|
private static allStorage;
|
|
18
19
|
constructor(rawStorage: IStorageRaw, debugName: string, writeDelay?: number);
|
|
19
20
|
static compressAll(): Promise<void>;
|
|
21
|
+
private resyncCallbacks;
|
|
22
|
+
watchResync(callback: () => void): void;
|
|
20
23
|
private init;
|
|
21
24
|
private getCurrentChunk;
|
|
22
25
|
private onAddToChunk;
|
|
@@ -33,6 +36,7 @@ export declare class TransactionStorage implements IStorage<Buffer> {
|
|
|
33
36
|
pushAppend(entry: TransactionEntry): Promise<void>;
|
|
34
37
|
private updatePendingAppends;
|
|
35
38
|
getKeys(): Promise<string[]>;
|
|
39
|
+
checkDisk(): Promise<void>;
|
|
36
40
|
private loadAllTransactions;
|
|
37
41
|
private parseTransactionFile;
|
|
38
42
|
private applyTransactionEntries;
|
|
@@ -6,6 +6,7 @@ import { formatNumber, formatTime } from "socket-function/src/formatting/format"
|
|
|
6
6
|
import { setPending } from "./PendingManager";
|
|
7
7
|
import { isInBuild } from "../misc/environment";
|
|
8
8
|
import { isNode } from "typesafecss";
|
|
9
|
+
import { runInfinitePoll } from "socket-function/src/batching";
|
|
9
10
|
|
|
10
11
|
/*
|
|
11
12
|
// Spec:
|
|
@@ -39,6 +40,7 @@ UPDATE now we use chunks, because append is too slow.
|
|
|
39
40
|
IMPORTANT! If there are multiple writers, we clobber writes from other writers when we compress
|
|
40
41
|
*/
|
|
41
42
|
|
|
43
|
+
const DISK_CHECK_INTERVAL = timeInMinute * 5;
|
|
42
44
|
|
|
43
45
|
const FILE_CHUNK_SIZE = 1024 * 1024;
|
|
44
46
|
const FILE_MAX_LIFETIME = timeInMinute * 30;
|
|
@@ -76,6 +78,7 @@ function getNextChunkPath(): string {
|
|
|
76
78
|
|
|
77
79
|
export class TransactionStorage implements IStorage<Buffer> {
|
|
78
80
|
public cache: Map<string, TransactionEntry> = new Map();
|
|
81
|
+
private diskFiles: Set<string> = new Set();
|
|
79
82
|
private currentChunk: {
|
|
80
83
|
path: string;
|
|
81
84
|
size: number;
|
|
@@ -91,6 +94,8 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
91
94
|
private writeDelay = WRITE_DELAY
|
|
92
95
|
) {
|
|
93
96
|
TransactionStorage.allStorage.push(this);
|
|
97
|
+
// VERY useful for debugging.
|
|
98
|
+
(globalThis as any)[`transactionStorage-${this.debugName}`] = this;
|
|
94
99
|
}
|
|
95
100
|
// Helps get rid of parse errors which constantly log. Also, uses less space
|
|
96
101
|
public static async compressAll() {
|
|
@@ -101,6 +106,11 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
101
106
|
});
|
|
102
107
|
}
|
|
103
108
|
|
|
109
|
+
private resyncCallbacks: (() => void)[] = [];
|
|
110
|
+
public watchResync(callback: () => void): void {
|
|
111
|
+
this.resyncCallbacks.push(callback);
|
|
112
|
+
}
|
|
113
|
+
|
|
104
114
|
private init: Promise<unknown> | undefined = this.loadAllTransactions();
|
|
105
115
|
|
|
106
116
|
private getCurrentChunk(): string {
|
|
@@ -113,6 +123,7 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
113
123
|
size: 0,
|
|
114
124
|
timeCreated: Date.now()
|
|
115
125
|
};
|
|
126
|
+
this.diskFiles.add(this.currentChunk.path);
|
|
116
127
|
}
|
|
117
128
|
return this.currentChunk.path;
|
|
118
129
|
}
|
|
@@ -239,14 +250,35 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
239
250
|
return Array.from(this.cache.keys());
|
|
240
251
|
}
|
|
241
252
|
|
|
253
|
+
public async checkDisk(): Promise<void> {
|
|
254
|
+
if (this.init) await this.init;
|
|
255
|
+
const anyChanges = async () => {
|
|
256
|
+
let keys = await this.rawStorage.getKeys();
|
|
257
|
+
let diskFiles = keys.filter(key => key.endsWith(CHUNK_EXT));
|
|
258
|
+
let hasNew = diskFiles.some(file => !this.diskFiles.has(file));
|
|
259
|
+
return hasNew;
|
|
260
|
+
};
|
|
261
|
+
if (!await anyChanges()) return;
|
|
262
|
+
|
|
263
|
+
await fileLockSection(async () => {
|
|
264
|
+
if (!await anyChanges()) return;
|
|
265
|
+
await this.loadAllTransactions();
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
242
269
|
|
|
243
270
|
// NOTE: This is either called in init (which blocks all other calls), or inside of the global file lock, so it is safe to load.
|
|
244
271
|
private async loadAllTransactions(): Promise<string[]> {
|
|
245
272
|
if (isInBuild()) return [];
|
|
246
273
|
|
|
274
|
+
if (this.init) {
|
|
275
|
+
runInfinitePoll(DISK_CHECK_INTERVAL, () => this.checkDisk());
|
|
276
|
+
}
|
|
277
|
+
|
|
247
278
|
let time = Date.now();
|
|
248
279
|
const keys = await this.rawStorage.getKeys();
|
|
249
280
|
const transactionFiles = keys.filter(key => key.endsWith(CHUNK_EXT));
|
|
281
|
+
this.diskFiles = new Set(transactionFiles);
|
|
250
282
|
|
|
251
283
|
let entryList: TransactionEntry[][] = [];
|
|
252
284
|
for (let file of transactionFiles) {
|
|
@@ -330,25 +362,62 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
330
362
|
}
|
|
331
363
|
pendingWriteTimes.set(entry.key, entry.time);
|
|
332
364
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
365
|
+
let latest = new Map<string, TransactionEntry>();
|
|
366
|
+
for (const entry of entries) {
|
|
367
|
+
let pendingTime = pendingWriteTimes.get(entry.key);
|
|
368
|
+
if (pendingTime && pendingTime > entry.time) {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
let prev = latest.get(entry.key);
|
|
372
|
+
if (prev && prev.time > entry.time) {
|
|
339
373
|
continue;
|
|
340
374
|
}
|
|
375
|
+
latest.set(entry.key, entry);
|
|
376
|
+
}
|
|
341
377
|
|
|
378
|
+
let anyChanged = false;
|
|
379
|
+
for (let entry of latest.values()) {
|
|
342
380
|
if (entry.value === undefined) {
|
|
381
|
+
if (!this.cache.has(entry.key)) continue;
|
|
382
|
+
anyChanged = true;
|
|
343
383
|
this.cache.delete(entry.key);
|
|
344
384
|
} else {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
385
|
+
if (!anyChanged) {
|
|
386
|
+
let prev = this.cache.get(entry.key);
|
|
387
|
+
if (!prev || prev.isZipped !== entry.isZipped) {
|
|
388
|
+
anyChanged = true;
|
|
389
|
+
} else {
|
|
390
|
+
if (!prev.value) {
|
|
391
|
+
if (entry.value) {
|
|
392
|
+
anyChanged = true;
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
if (!entry.value) {
|
|
396
|
+
anyChanged = true;
|
|
397
|
+
} else {
|
|
398
|
+
// Both values, so... it might not have changed
|
|
399
|
+
if (!prev.value.equals(entry.value)) {
|
|
400
|
+
anyChanged = true;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
348
405
|
}
|
|
349
406
|
this.cache.set(entry.key, entry);
|
|
350
407
|
}
|
|
351
408
|
}
|
|
409
|
+
|
|
410
|
+
if (anyChanged) {
|
|
411
|
+
for (const callback of this.resyncCallbacks) {
|
|
412
|
+
try {
|
|
413
|
+
callback();
|
|
414
|
+
} catch (e) {
|
|
415
|
+
setImmediate(() => {
|
|
416
|
+
throw e;
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
352
421
|
}
|
|
353
422
|
|
|
354
423
|
private readTransactionEntry(buffer: Buffer, offset: number): {
|
|
@@ -511,6 +580,7 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
511
580
|
// the other generations, which is annoying).
|
|
512
581
|
for (const file of existingDiskEntries) {
|
|
513
582
|
await this.rawStorage.remove(file);
|
|
583
|
+
this.diskFiles.delete(file);
|
|
514
584
|
}
|
|
515
585
|
} finally {
|
|
516
586
|
this.compressing = false;
|
|
@@ -528,6 +598,7 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
528
598
|
|
|
529
599
|
this.pendingAppends = [];
|
|
530
600
|
this.cache.clear();
|
|
601
|
+
this.diskFiles.clear();
|
|
531
602
|
this.currentChunk = undefined;
|
|
532
603
|
this.entryCount = 0;
|
|
533
604
|
});
|