sliftutils 1.1.4 → 1.2.1

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 CHANGED
@@ -296,6 +296,7 @@ declare module "sliftutils/misc/zip" {
296
296
  import { MaybePromise } from "socket-function/src/types";
297
297
  export declare class Zip {
298
298
  static gzip(buffer: Buffer, level?: number): Promise<Buffer>;
299
+ static gzipSync(buffer: Buffer, level?: number): Buffer;
299
300
  static gunzip(buffer: Buffer): MaybePromise<Buffer>;
300
301
  static gunzipAsyncBase(buffer: Buffer): Promise<Buffer>;
301
302
  static gunzipUntracked(buffer: Buffer): Promise<Buffer>;
@@ -690,6 +691,11 @@ declare module "sliftutils/render-utils/asyncObservable" {
690
691
 
691
692
  }
692
693
 
694
+ declare module "sliftutils/render-utils/autoMeasure" {
695
+ export declare function runAutoMeasure(): void;
696
+
697
+ }
698
+
693
699
  declare module "sliftutils/render-utils/colors" {
694
700
  export declare const redButton: string;
695
701
  export declare const yellowButton: string;
@@ -1121,6 +1127,9 @@ declare module "sliftutils/storage/PrivateFileSystemStorage" {
1121
1127
 
1122
1128
  declare module "sliftutils/storage/StorageObservable" {
1123
1129
  import { IStorage, IStorageSync } from "./IStorage";
1130
+ export declare const storagePendingAccesses: {
1131
+ value: number;
1132
+ };
1124
1133
  export declare class StorageSync<T> implements IStorageSync<T> {
1125
1134
  storage: IStorage<T>;
1126
1135
  private config?;
@@ -1160,6 +1169,13 @@ declare module "sliftutils/storage/StorageObservable" {
1160
1169
  reloadKey(key: string): void;
1161
1170
  reset(): Promise<void>;
1162
1171
  }
1172
+ export declare function waitUntilNextLoad(): Promise<void>;
1173
+
1174
+ }
1175
+
1176
+ declare module "sliftutils/storage/StorageObservableAsync" {
1177
+ /** Reruns the code until all StorageSyncs accessed have loaded their values. Not efficient,although will usually be O(values accessed), just due to how loading works (it won't be quadratic). */
1178
+ export declare function rerunCodeUntilAllLoaded<T>(code: () => T): Promise<T>;
1163
1179
 
1164
1180
  }
1165
1181
 
package/misc/zip.d.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  import { MaybePromise } from "socket-function/src/types";
4
4
  export declare class Zip {
5
5
  static gzip(buffer: Buffer, level?: number): Promise<Buffer>;
6
+ static gzipSync(buffer: Buffer, level?: number): Buffer;
6
7
  static gunzip(buffer: Buffer): MaybePromise<Buffer>;
7
8
  static gunzipAsyncBase(buffer: Buffer): Promise<Buffer>;
8
9
  static gunzipUntracked(buffer: Buffer): Promise<Buffer>;
package/misc/zip.ts CHANGED
@@ -24,6 +24,13 @@ export class Zip {
24
24
  return await doStream(new CompressionStream("gzip"), buffer);
25
25
  }
26
26
  }
27
+ @measureFnc
28
+ public static gzipSync(buffer: Buffer, level?: number): Buffer {
29
+ if (isNode()) {
30
+ return Buffer.from(zlib.gzipSync(buffer, { level }));
31
+ }
32
+ return Buffer.from(pako.deflate(buffer));
33
+ }
27
34
  public static gunzip(buffer: Buffer): MaybePromise<Buffer> {
28
35
  // Switch to the synchronous version if the buffer is small. This is a lot faster in Node.js and clientside.
29
36
  // - On tests of random small amounts of data, this seems to be up to 7X faster (on node). However, on non-random data, on the actual data we're using, it seems to be almost 50 times faster. So... definitely worth it...
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sliftutils",
3
- "version": "1.1.4",
3
+ "version": "1.2.1",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -0,0 +1 @@
1
+ export declare function runAutoMeasure(): void;
@@ -0,0 +1,43 @@
1
+ import { runInfinitePoll } from "socket-function/src/batching";
2
+ import { timeInSecond } from "socket-function/src/misc";
3
+ import { startMeasure, logMeasureTable } from "socket-function/src/profiling/measure";
4
+
5
+ export function runAutoMeasure() {
6
+ let measureObj = startMeasure();
7
+
8
+ function logProfileMeasuresTimingsNow(force = false) {
9
+ let profile = measureObj.finish();
10
+ measureObj = startMeasure();
11
+ logMeasureTable(profile, {
12
+ name: `watchdog at ${new Date().toLocaleString()}`,
13
+ // NOTE: Much higher min log times, now that we are combining logs.
14
+ minTimeToLog: force ? 0 : 250,
15
+ thresholdInTable: 0,
16
+ setTitle: true
17
+ });
18
+ logMeasureTable(profile, {
19
+ name: `watchdog at ${new Date().toLocaleString()}`,
20
+ mergeDepth: 1,
21
+ minTimeToLog: force ? 0 : 250,
22
+ });
23
+ }
24
+ function logNow() {
25
+ logProfileMeasuresTimingsNow(true);
26
+ }
27
+ (globalThis as any).logProfileMeasuresNow = logNow;
28
+ (globalThis as any).logAll = logNow;
29
+ (globalThis as any).logNow = logNow;
30
+
31
+ (globalThis as any).logUnfiltered = function logUnfiltered(depth = 2) {
32
+ let profile = measureObj.finish();
33
+ measureObj = startMeasure();
34
+ logMeasureTable(profile, {
35
+ name: `all logs at ${new Date().toLocaleString()}`,
36
+ mergeDepth: depth,
37
+ minTimeToLog: 0,
38
+ maxTableEntries: 10000000,
39
+ thresholdInTable: 0
40
+ });
41
+ };
42
+ runInfinitePoll(timeInSecond * 60, logProfileMeasuresTimingsNow);
43
+ }
@@ -1,4 +1,7 @@
1
1
  import { IStorage, IStorageSync } from "./IStorage";
2
+ export declare const storagePendingAccesses: {
3
+ value: number;
4
+ };
2
5
  export declare class StorageSync<T> implements IStorageSync<T> {
3
6
  storage: IStorage<T>;
4
7
  private config?;
@@ -38,3 +41,4 @@ export declare class StorageSync<T> implements IStorageSync<T> {
38
41
  reloadKey(key: string): void;
39
42
  reset(): Promise<void>;
40
43
  }
44
+ export declare function waitUntilNextLoad(): Promise<void>;
@@ -1,8 +1,11 @@
1
1
  import { observable } from "mobx";
2
2
  import { deepFreezeObject, freezeObject, isDefined } from "../misc/types";
3
3
  import { IStorage, IStorageSync } from "./IStorage";
4
+ import { PromiseObj } from "socket-function/src/misc";
4
5
 
5
- // NOTE: At around 500K values (depending on their size to some degree), this will take about 2 minutes to load. But once it does it will be fast. So... keep that in mind. I recommend not exceeding 100K
6
+ export const storagePendingAccesses = { value: 0 };
7
+
8
+ // NOTE: At around 500K values (depending on their size to some degree), this will take about 2 minutes to load. But once it does it will be fast. So... keep that in mind. I recommend not exceeding 100K.
6
9
  export class StorageSync<T> implements IStorageSync<T> {
7
10
  cached = observable.map<string, T | undefined>(undefined, { deep: false });
8
11
  infoCached = observable.map<string, { size: number; lastModified: number } | undefined>(undefined, { deep: false });
@@ -85,6 +88,7 @@ export class StorageSync<T> implements IStorageSync<T> {
85
88
  public async getPromise(key: string): Promise<T | undefined> {
86
89
  let value = this.cached.get(key);
87
90
  if (value === undefined) {
91
+ storagePendingAccesses.value++;
88
92
  value = await this.storage.get(key);
89
93
  if (value !== undefined && this.cached.get(key) === undefined) {
90
94
  if (this.config?.freeze === "shallow") {
@@ -94,15 +98,19 @@ export class StorageSync<T> implements IStorageSync<T> {
94
98
  }
95
99
  this.cached.set(key, value);
96
100
  }
101
+ triggerLoad();
97
102
  }
98
103
  return value;
99
104
  }
100
105
  private pendingGetKeys: Promise<string[]> | undefined;
101
106
  public async getKeysPromise(): Promise<string[]> {
107
+ if (this.loadedKeys) {
108
+ return Array.from(this.keys);
109
+ }
110
+ storagePendingAccesses.value++;
102
111
  if (this.pendingGetKeys) {
103
112
  return this.pendingGetKeys;
104
113
  }
105
- if (this.loadedKeys) return Array.from(this.keys);
106
114
  this.loadedKeys = true;
107
115
  this.pendingGetKeys = this.storage.getKeys();
108
116
  void this.pendingGetKeys.finally(() => {
@@ -113,6 +121,7 @@ export class StorageSync<T> implements IStorageSync<T> {
113
121
  this.keys = new Set(keys);
114
122
  this.synced.keySeqNum++;
115
123
  }
124
+ triggerLoad();
116
125
  return Array.from(this.keys);
117
126
  }
118
127
 
@@ -140,4 +149,20 @@ export class StorageSync<T> implements IStorageSync<T> {
140
149
  this.synced.keySeqNum++;
141
150
  await this.storage.reset();
142
151
  }
152
+ }
153
+
154
+ let waitUntilNextLoadWatchers: PromiseObj<void>[] = [];
155
+ export function waitUntilNextLoad(): Promise<void> {
156
+ let promise = new PromiseObj<void>();
157
+ waitUntilNextLoadWatchers.push(promise);
158
+ return promise.promise;
159
+ }
160
+ function triggerLoad() {
161
+ let watchers = waitUntilNextLoadWatchers;
162
+ waitUntilNextLoadWatchers = [];
163
+ void Promise.resolve().finally(() => {
164
+ for (let watcher of watchers) {
165
+ watcher.resolve();
166
+ }
167
+ });
143
168
  }
@@ -0,0 +1,2 @@
1
+ /** Reruns the code until all StorageSyncs accessed have loaded their values. Not efficient,although will usually be O(values accessed), just due to how loading works (it won't be quadratic). */
2
+ export declare function rerunCodeUntilAllLoaded<T>(code: () => T): Promise<T>;
@@ -0,0 +1,20 @@
1
+ import { storagePendingAccesses, waitUntilNextLoad } from "./StorageObservable";
2
+
3
+ /** Reruns the code until all StorageSyncs accessed have loaded their values. Not efficient,although will usually be O(values accessed), just due to how loading works (it won't be quadratic). */
4
+ export async function rerunCodeUntilAllLoaded<T>(code: () => T): Promise<T> {
5
+ while (true) {
6
+ let beforeAccesses = storagePendingAccesses.value;
7
+ try {
8
+ let result = await code();
9
+ if (storagePendingAccesses.value === beforeAccesses) {
10
+ return result;
11
+ }
12
+ } catch (error) {
13
+ if (storagePendingAccesses.value === beforeAccesses) {
14
+ throw error;
15
+ }
16
+ }
17
+ console.log(`Rerunning synchronous check as loading starting while evaluating code. Function name`, code);
18
+ await waitUntilNextLoad();
19
+ }
20
+ }