jiren 1.5.5 → 1.6.5
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/README.md +123 -313
- package/components/cache.ts +1 -1
- package/components/client-node-native.ts +602 -159
- package/components/client.ts +51 -29
- package/components/metrics.ts +1 -4
- package/components/native-node.ts +48 -3
- package/components/native.ts +29 -0
- package/components/persistent-worker.ts +73 -0
- package/components/subprocess-worker.ts +65 -0
- package/components/types.ts +2 -0
- package/components/worker-pool.ts +169 -0
- package/components/worker.ts +39 -23
- package/dist/components/cache.d.ts +76 -0
- package/dist/components/cache.d.ts.map +1 -0
- package/dist/components/cache.js +439 -0
- package/dist/components/cache.js.map +1 -0
- package/dist/components/client-node-native.d.ts +134 -0
- package/dist/components/client-node-native.d.ts.map +1 -0
- package/dist/components/client-node-native.js +811 -0
- package/dist/components/client-node-native.js.map +1 -0
- package/dist/components/metrics.d.ts +104 -0
- package/dist/components/metrics.d.ts.map +1 -0
- package/dist/components/metrics.js +296 -0
- package/dist/components/metrics.js.map +1 -0
- package/dist/components/native-node.d.ts +67 -0
- package/dist/components/native-node.d.ts.map +1 -0
- package/dist/components/native-node.js +137 -0
- package/dist/components/native-node.js.map +1 -0
- package/dist/components/types.d.ts +252 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/components/types.js +5 -0
- package/dist/components/types.js.map +1 -0
- package/dist/index-node.d.ts +10 -0
- package/dist/index-node.d.ts.map +1 -0
- package/dist/index-node.js +12 -0
- package/dist/index-node.js.map +1 -0
- package/dist/types/index.d.ts +63 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/index-node.ts +6 -6
- package/index.ts +4 -3
- package/lib/libhttpclient.dylib +0 -0
- package/package.json +15 -8
- package/types/index.ts +0 -68
package/components/worker.ts
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { parentPort } from "worker_threads";
|
|
2
2
|
import { CString, type Pointer } from "bun:ffi";
|
|
3
3
|
import { lib } from "./native";
|
|
4
|
-
import type { RequestOptions } from "
|
|
4
|
+
import type { RequestOptions } from "./types";
|
|
5
5
|
|
|
6
|
-
//
|
|
7
|
-
|
|
6
|
+
// LAZY INITIALIZATION: Don't create client until first request
|
|
7
|
+
// This avoids race conditions with library loading
|
|
8
|
+
let ptr: Pointer | null = null;
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
function ensureClient(): Pointer {
|
|
11
|
+
if (!ptr) {
|
|
12
|
+
ptr = lib.symbols.zclient_new();
|
|
13
|
+
if (!ptr) {
|
|
14
|
+
throw new Error("Failed to create native client instance in worker");
|
|
15
|
+
}
|
|
16
|
+
// Enable benchmark mode for consistent performance
|
|
17
|
+
lib.symbols.zclient_set_benchmark_mode(ptr, true);
|
|
18
|
+
}
|
|
19
|
+
return ptr;
|
|
11
20
|
}
|
|
12
21
|
|
|
13
22
|
// Handle cleanup
|
|
@@ -37,20 +46,27 @@ if (parentPort) {
|
|
|
37
46
|
}
|
|
38
47
|
|
|
39
48
|
if (msg.type === "prefetch") {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
49
|
+
try {
|
|
50
|
+
const client = ensureClient();
|
|
51
|
+
const urls = msg.url as unknown as string[];
|
|
52
|
+
for (const url of urls) {
|
|
53
|
+
const urlBuffer = Buffer.from(url + "\0");
|
|
54
|
+
lib.symbols.zclient_prefetch(client, urlBuffer);
|
|
55
|
+
}
|
|
56
|
+
parentPort?.postMessage({ type: "prefetch_done" });
|
|
57
|
+
} catch (err: any) {
|
|
58
|
+
parentPort?.postMessage({
|
|
59
|
+
type: "prefetch_done",
|
|
60
|
+
error: err.message,
|
|
61
|
+
});
|
|
45
62
|
}
|
|
46
|
-
parentPort?.postMessage({ type: "prefetch_done" });
|
|
47
63
|
return;
|
|
48
64
|
}
|
|
49
65
|
|
|
50
66
|
const { id, url, options } = msg;
|
|
51
67
|
|
|
52
68
|
try {
|
|
53
|
-
|
|
69
|
+
const client = ensureClient();
|
|
54
70
|
|
|
55
71
|
const method = options.method || "GET";
|
|
56
72
|
const methodBuffer = Buffer.from(method + "\0");
|
|
@@ -78,8 +94,9 @@ if (parentPort) {
|
|
|
78
94
|
const maxRedirects = options.maxRedirects ?? 5;
|
|
79
95
|
const antibot = options.antibot ?? false;
|
|
80
96
|
|
|
81
|
-
|
|
82
|
-
|
|
97
|
+
// Use the full request API for complete response
|
|
98
|
+
const respPtr = lib.symbols.zclient_request_full(
|
|
99
|
+
client,
|
|
83
100
|
methodBuffer,
|
|
84
101
|
urlBuffer,
|
|
85
102
|
headersBuffer,
|
|
@@ -88,16 +105,15 @@ if (parentPort) {
|
|
|
88
105
|
antibot
|
|
89
106
|
);
|
|
90
107
|
|
|
91
|
-
// Parse Response
|
|
92
108
|
if (!respPtr) throw new Error("Native request failed");
|
|
93
109
|
|
|
94
|
-
const status = lib.symbols.
|
|
95
|
-
const bodyLen = Number(lib.symbols.
|
|
96
|
-
const bodyPtr = lib.symbols.
|
|
110
|
+
const status = lib.symbols.zfull_response_status(respPtr);
|
|
111
|
+
const bodyLen = Number(lib.symbols.zfull_response_body_len(respPtr));
|
|
112
|
+
const bodyPtr = lib.symbols.zfull_response_body(respPtr);
|
|
97
113
|
const headersLen = Number(
|
|
98
|
-
lib.symbols.
|
|
114
|
+
lib.symbols.zfull_response_headers_len(respPtr)
|
|
99
115
|
);
|
|
100
|
-
const
|
|
116
|
+
const headersRawPtr = lib.symbols.zfull_response_headers(respPtr);
|
|
101
117
|
|
|
102
118
|
let bodyString = "";
|
|
103
119
|
if (bodyLen > 0 && bodyPtr) {
|
|
@@ -105,8 +121,8 @@ if (parentPort) {
|
|
|
105
121
|
}
|
|
106
122
|
|
|
107
123
|
const headers: Record<string, string> = {};
|
|
108
|
-
if (headersLen > 0 &&
|
|
109
|
-
const headersStr = new CString(
|
|
124
|
+
if (headersLen > 0 && headersRawPtr) {
|
|
125
|
+
const headersStr = new CString(headersRawPtr).toString();
|
|
110
126
|
const lines = headersStr.split("\r\n");
|
|
111
127
|
for (const line of lines) {
|
|
112
128
|
if (!line) continue;
|
|
@@ -119,7 +135,7 @@ if (parentPort) {
|
|
|
119
135
|
}
|
|
120
136
|
}
|
|
121
137
|
|
|
122
|
-
lib.symbols.
|
|
138
|
+
lib.symbols.zclient_response_full_free(respPtr);
|
|
123
139
|
|
|
124
140
|
parentPort?.postMessage({
|
|
125
141
|
id,
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { JirenResponse } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Two-Tier Response Cache
|
|
4
|
+
*
|
|
5
|
+
* L1: In-Memory LRU Cache (~0.001ms access) - hot data
|
|
6
|
+
* L2: Disk Cache with gzip (~5ms access) - persistence
|
|
7
|
+
*
|
|
8
|
+
* Read path: L1 → L2 → Network
|
|
9
|
+
* Write path: L1 + L2 (write-through)
|
|
10
|
+
*/
|
|
11
|
+
export declare class ResponseCache {
|
|
12
|
+
private l1;
|
|
13
|
+
private cacheDir;
|
|
14
|
+
private maxDiskSize;
|
|
15
|
+
constructor(l1Capacity?: number, cacheDir?: string, maxDiskSize?: number);
|
|
16
|
+
/**
|
|
17
|
+
* Generate cache key from URL and options
|
|
18
|
+
*/
|
|
19
|
+
private generateKey;
|
|
20
|
+
/**
|
|
21
|
+
* Get cache file path (compressed .gz file)
|
|
22
|
+
*/
|
|
23
|
+
private getCacheFilePath;
|
|
24
|
+
/**
|
|
25
|
+
* Preload L2 disk cache entry into L1 memory cache.
|
|
26
|
+
* Call this during initialization to ensure first request hits L1.
|
|
27
|
+
* @param url - Base URL to preload
|
|
28
|
+
* @param path - Optional path
|
|
29
|
+
* @param options - Optional request options
|
|
30
|
+
* @returns true if entry was preloaded, false if not found/expired
|
|
31
|
+
*/
|
|
32
|
+
preloadL1(url: string, path?: string, options?: any): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Get cached response - checks L1 first, then L2
|
|
35
|
+
*/
|
|
36
|
+
get(url: string, path?: string, options?: any): JirenResponse | null;
|
|
37
|
+
/**
|
|
38
|
+
* Get from L2 disk cache
|
|
39
|
+
*/
|
|
40
|
+
private getFromDisk;
|
|
41
|
+
/**
|
|
42
|
+
* Store response in both L1 and L2 (write-through)
|
|
43
|
+
*/
|
|
44
|
+
set(url: string, response: JirenResponse, ttl: number, path?: string, options?: any): void;
|
|
45
|
+
/**
|
|
46
|
+
* Write to L2 disk cache
|
|
47
|
+
*/
|
|
48
|
+
private setToDisk;
|
|
49
|
+
/**
|
|
50
|
+
* Clear cache for a specific URL or all
|
|
51
|
+
*/
|
|
52
|
+
clear(url?: string): void;
|
|
53
|
+
/**
|
|
54
|
+
* Clear all L2 disk cache files
|
|
55
|
+
*/
|
|
56
|
+
private clearAllDisk;
|
|
57
|
+
/**
|
|
58
|
+
* Get combined cache statistics
|
|
59
|
+
*/
|
|
60
|
+
stats(): {
|
|
61
|
+
l1: {
|
|
62
|
+
size: number;
|
|
63
|
+
capacity: number;
|
|
64
|
+
hits: number;
|
|
65
|
+
misses: number;
|
|
66
|
+
hitRate: string;
|
|
67
|
+
};
|
|
68
|
+
l2: {
|
|
69
|
+
size: number;
|
|
70
|
+
maxSize: number;
|
|
71
|
+
cacheDir: string;
|
|
72
|
+
totalSizeKB: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../components/cache.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,YAAY,CAAC;AAqOnE;;;;;;;;GAQG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAS;gBAEhB,UAAU,SAAM,EAAE,QAAQ,SAAiB,EAAE,WAAW,SAAM;IAW1E;;OAEG;IACH,OAAO,CAAC,WAAW;IAUnB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;;;;;;OAOG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,GAAG,OAAO;IAkB7D;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,GAAG,aAAa,GAAG,IAAI;IAoBpE;;OAEG;IACH,OAAO,CAAC,WAAW;IAkDnB;;OAEG;IACH,GAAG,CACD,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,GAAG,GACZ,IAAI;IAgBP;;OAEG;YACW,SAAS;IAuDvB;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAezB;;OAEG;IACH,OAAO,CAAC,YAAY;IAapB;;OAEG;IACH,KAAK;;;;;;;;;;;;;;;CA6BN"}
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, readdirSync, statSync, } from "fs";
|
|
2
|
+
import { gzipSync, gunzipSync } from "zlib";
|
|
3
|
+
import { createHash } from "crypto";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
/**
|
|
6
|
+
* Reconstruct body methods from raw data
|
|
7
|
+
*/
|
|
8
|
+
function reconstructBody(bodyData, isText) {
|
|
9
|
+
let buffer;
|
|
10
|
+
if (isText) {
|
|
11
|
+
// Text data stored directly
|
|
12
|
+
const encoder = new TextEncoder();
|
|
13
|
+
buffer = encoder.encode(bodyData).buffer;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
// Binary data stored as base64
|
|
17
|
+
const binaryString = atob(bodyData);
|
|
18
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
19
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
20
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
21
|
+
}
|
|
22
|
+
buffer = bytes.buffer;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
bodyUsed: false,
|
|
26
|
+
text: async () => {
|
|
27
|
+
if (isText)
|
|
28
|
+
return bodyData;
|
|
29
|
+
const decoder = new TextDecoder();
|
|
30
|
+
return decoder.decode(buffer);
|
|
31
|
+
},
|
|
32
|
+
json: async () => {
|
|
33
|
+
const text = isText ? bodyData : new TextDecoder().decode(buffer);
|
|
34
|
+
return JSON.parse(text);
|
|
35
|
+
},
|
|
36
|
+
arrayBuffer: async () => buffer,
|
|
37
|
+
blob: async () => new Blob([buffer]),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* L1 In-Memory LRU Cache
|
|
42
|
+
* Provides ~0.001ms access time (vs ~5ms for disk)
|
|
43
|
+
*/
|
|
44
|
+
class L1MemoryCache {
|
|
45
|
+
capacity;
|
|
46
|
+
cache = new Map();
|
|
47
|
+
head = null; // Most recently used
|
|
48
|
+
tail = null; // Least recently used
|
|
49
|
+
// Stats
|
|
50
|
+
hits = 0;
|
|
51
|
+
misses = 0;
|
|
52
|
+
constructor(capacity = 100) {
|
|
53
|
+
this.capacity = capacity;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get from L1 cache (O(1) lookup + LRU update)
|
|
57
|
+
*/
|
|
58
|
+
get(key) {
|
|
59
|
+
const node = this.cache.get(key);
|
|
60
|
+
if (!node) {
|
|
61
|
+
this.misses++;
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
// Check if expired
|
|
65
|
+
const now = Date.now();
|
|
66
|
+
if (now - node.entry.timestamp > node.entry.ttl) {
|
|
67
|
+
this.delete(key);
|
|
68
|
+
this.misses++;
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
// Move to front (most recently used)
|
|
72
|
+
this.moveToFront(node);
|
|
73
|
+
this.hits++;
|
|
74
|
+
return node.entry;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Set in L1 cache with LRU eviction
|
|
78
|
+
*/
|
|
79
|
+
set(key, entry) {
|
|
80
|
+
// If key exists, update and move to front
|
|
81
|
+
const existing = this.cache.get(key);
|
|
82
|
+
if (existing) {
|
|
83
|
+
existing.entry = entry;
|
|
84
|
+
this.moveToFront(existing);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Create new node
|
|
88
|
+
const node = {
|
|
89
|
+
key,
|
|
90
|
+
entry,
|
|
91
|
+
prev: null,
|
|
92
|
+
next: this.head,
|
|
93
|
+
};
|
|
94
|
+
// Add to front
|
|
95
|
+
if (this.head) {
|
|
96
|
+
this.head.prev = node;
|
|
97
|
+
}
|
|
98
|
+
this.head = node;
|
|
99
|
+
if (!this.tail) {
|
|
100
|
+
this.tail = node;
|
|
101
|
+
}
|
|
102
|
+
this.cache.set(key, node);
|
|
103
|
+
// Evict LRU if over capacity
|
|
104
|
+
if (this.cache.size > this.capacity) {
|
|
105
|
+
this.evictLRU();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Delete from L1 cache
|
|
110
|
+
*/
|
|
111
|
+
delete(key) {
|
|
112
|
+
const node = this.cache.get(key);
|
|
113
|
+
if (!node)
|
|
114
|
+
return;
|
|
115
|
+
this.removeNode(node);
|
|
116
|
+
this.cache.delete(key);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Clear all L1 cache
|
|
120
|
+
*/
|
|
121
|
+
clear() {
|
|
122
|
+
this.cache.clear();
|
|
123
|
+
this.head = null;
|
|
124
|
+
this.tail = null;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get L1 cache stats
|
|
128
|
+
*/
|
|
129
|
+
stats() {
|
|
130
|
+
return {
|
|
131
|
+
size: this.cache.size,
|
|
132
|
+
capacity: this.capacity,
|
|
133
|
+
hits: this.hits,
|
|
134
|
+
misses: this.misses,
|
|
135
|
+
hitRate: this.hits + this.misses > 0
|
|
136
|
+
? ((this.hits / (this.hits + this.misses)) * 100).toFixed(2) + "%"
|
|
137
|
+
: "0%",
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
moveToFront(node) {
|
|
141
|
+
if (node === this.head)
|
|
142
|
+
return; // Already at front
|
|
143
|
+
this.removeNode(node);
|
|
144
|
+
// Add to front
|
|
145
|
+
node.prev = null;
|
|
146
|
+
node.next = this.head;
|
|
147
|
+
if (this.head) {
|
|
148
|
+
this.head.prev = node;
|
|
149
|
+
}
|
|
150
|
+
this.head = node;
|
|
151
|
+
if (!this.tail) {
|
|
152
|
+
this.tail = node;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
removeNode(node) {
|
|
156
|
+
if (node.prev) {
|
|
157
|
+
node.prev.next = node.next;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
this.head = node.next;
|
|
161
|
+
}
|
|
162
|
+
if (node.next) {
|
|
163
|
+
node.next.prev = node.prev;
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
this.tail = node.prev;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
evictLRU() {
|
|
170
|
+
if (!this.tail)
|
|
171
|
+
return;
|
|
172
|
+
const key = this.tail.key;
|
|
173
|
+
this.removeNode(this.tail);
|
|
174
|
+
this.cache.delete(key);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Two-Tier Response Cache
|
|
179
|
+
*
|
|
180
|
+
* L1: In-Memory LRU Cache (~0.001ms access) - hot data
|
|
181
|
+
* L2: Disk Cache with gzip (~5ms access) - persistence
|
|
182
|
+
*
|
|
183
|
+
* Read path: L1 → L2 → Network
|
|
184
|
+
* Write path: L1 + L2 (write-through)
|
|
185
|
+
*/
|
|
186
|
+
export class ResponseCache {
|
|
187
|
+
l1;
|
|
188
|
+
cacheDir;
|
|
189
|
+
maxDiskSize;
|
|
190
|
+
constructor(l1Capacity = 100, cacheDir = ".cache/jiren", maxDiskSize = 100) {
|
|
191
|
+
this.l1 = new L1MemoryCache(l1Capacity);
|
|
192
|
+
this.maxDiskSize = maxDiskSize;
|
|
193
|
+
this.cacheDir = cacheDir;
|
|
194
|
+
// Create cache directory if it doesn't exist
|
|
195
|
+
if (!existsSync(this.cacheDir)) {
|
|
196
|
+
mkdirSync(this.cacheDir, { recursive: true });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Generate cache key from URL and options
|
|
201
|
+
*/
|
|
202
|
+
generateKey(url, path, options) {
|
|
203
|
+
const fullUrl = path ? `${url}${path}` : url;
|
|
204
|
+
const method = options?.method || "GET";
|
|
205
|
+
const headers = JSON.stringify(options?.headers || {});
|
|
206
|
+
const key = `${method}:${fullUrl}:${headers}`;
|
|
207
|
+
// Hash the key to create a valid filename
|
|
208
|
+
return createHash("md5").update(key).digest("hex");
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Get cache file path (compressed .gz file)
|
|
212
|
+
*/
|
|
213
|
+
getCacheFilePath(key) {
|
|
214
|
+
return join(this.cacheDir, `${key}.json.gz`);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Preload L2 disk cache entry into L1 memory cache.
|
|
218
|
+
* Call this during initialization to ensure first request hits L1.
|
|
219
|
+
* @param url - Base URL to preload
|
|
220
|
+
* @param path - Optional path
|
|
221
|
+
* @param options - Optional request options
|
|
222
|
+
* @returns true if entry was preloaded, false if not found/expired
|
|
223
|
+
*/
|
|
224
|
+
preloadL1(url, path, options) {
|
|
225
|
+
const key = this.generateKey(url, path, options);
|
|
226
|
+
// Check if already in L1
|
|
227
|
+
if (this.l1.get(key)) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
// Try to load from L2 disk
|
|
231
|
+
const l2Entry = this.getFromDisk(key);
|
|
232
|
+
if (l2Entry) {
|
|
233
|
+
this.l1.set(key, l2Entry);
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get cached response - checks L1 first, then L2
|
|
240
|
+
*/
|
|
241
|
+
get(url, path, options) {
|
|
242
|
+
const key = this.generateKey(url, path, options);
|
|
243
|
+
// L1: Check in-memory cache first (~0.001ms)
|
|
244
|
+
const l1Entry = this.l1.get(key);
|
|
245
|
+
if (l1Entry) {
|
|
246
|
+
return l1Entry.response;
|
|
247
|
+
}
|
|
248
|
+
// L2: Check disk cache (~5ms)
|
|
249
|
+
const l2Entry = this.getFromDisk(key);
|
|
250
|
+
if (l2Entry) {
|
|
251
|
+
// Promote to L1 for faster future access
|
|
252
|
+
this.l1.set(key, l2Entry);
|
|
253
|
+
return l2Entry.response;
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Get from L2 disk cache
|
|
259
|
+
*/
|
|
260
|
+
getFromDisk(key) {
|
|
261
|
+
const filePath = this.getCacheFilePath(key);
|
|
262
|
+
if (!existsSync(filePath))
|
|
263
|
+
return null;
|
|
264
|
+
try {
|
|
265
|
+
// Read compressed file
|
|
266
|
+
const compressed = readFileSync(filePath);
|
|
267
|
+
// Decompress
|
|
268
|
+
const decompressed = gunzipSync(compressed);
|
|
269
|
+
const data = decompressed.toString("utf-8");
|
|
270
|
+
const serialized = JSON.parse(data);
|
|
271
|
+
// Check if expired
|
|
272
|
+
const now = Date.now();
|
|
273
|
+
if (now - serialized.timestamp > serialized.ttl) {
|
|
274
|
+
// Delete expired cache file
|
|
275
|
+
try {
|
|
276
|
+
unlinkSync(filePath);
|
|
277
|
+
}
|
|
278
|
+
catch { }
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
// Reconstruct the response with working body methods
|
|
282
|
+
const response = {
|
|
283
|
+
status: serialized.status,
|
|
284
|
+
statusText: serialized.statusText,
|
|
285
|
+
headers: serialized.headers,
|
|
286
|
+
url: serialized.url,
|
|
287
|
+
ok: serialized.ok,
|
|
288
|
+
redirected: serialized.redirected,
|
|
289
|
+
type: serialized.type || "default",
|
|
290
|
+
body: reconstructBody(serialized.bodyData, serialized.bodyIsText),
|
|
291
|
+
};
|
|
292
|
+
return {
|
|
293
|
+
response,
|
|
294
|
+
timestamp: serialized.timestamp,
|
|
295
|
+
ttl: serialized.ttl,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
// Invalid cache file, delete it
|
|
300
|
+
try {
|
|
301
|
+
unlinkSync(filePath);
|
|
302
|
+
}
|
|
303
|
+
catch { }
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Store response in both L1 and L2 (write-through)
|
|
309
|
+
*/
|
|
310
|
+
set(url, response, ttl, path, options) {
|
|
311
|
+
const key = this.generateKey(url, path, options);
|
|
312
|
+
const entry = {
|
|
313
|
+
response,
|
|
314
|
+
timestamp: Date.now(),
|
|
315
|
+
ttl,
|
|
316
|
+
};
|
|
317
|
+
// L1: Store in memory (~0.001ms)
|
|
318
|
+
this.l1.set(key, entry);
|
|
319
|
+
// L2: Store on disk (async-ish, for persistence)
|
|
320
|
+
this.setToDisk(key, entry);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Write to L2 disk cache
|
|
324
|
+
*/
|
|
325
|
+
async setToDisk(key, entry) {
|
|
326
|
+
const filePath = this.getCacheFilePath(key);
|
|
327
|
+
try {
|
|
328
|
+
// Extract body text for serialization
|
|
329
|
+
let bodyData;
|
|
330
|
+
let bodyIsText = true;
|
|
331
|
+
try {
|
|
332
|
+
bodyData = await entry.response.body.text();
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
// If text fails, try arrayBuffer and convert to base64
|
|
336
|
+
try {
|
|
337
|
+
const buffer = await entry.response.body.arrayBuffer();
|
|
338
|
+
const bytes = new Uint8Array(buffer);
|
|
339
|
+
let binary = "";
|
|
340
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
341
|
+
binary += String.fromCharCode(bytes[i]);
|
|
342
|
+
}
|
|
343
|
+
bodyData = btoa(binary);
|
|
344
|
+
bodyIsText = false;
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
bodyData = "";
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
// Create serializable entry
|
|
351
|
+
const serialized = {
|
|
352
|
+
status: entry.response.status,
|
|
353
|
+
statusText: entry.response.statusText,
|
|
354
|
+
headers: entry.response.headers,
|
|
355
|
+
url: entry.response.url,
|
|
356
|
+
ok: entry.response.ok,
|
|
357
|
+
redirected: entry.response.redirected,
|
|
358
|
+
type: entry.response.type || "default",
|
|
359
|
+
bodyData,
|
|
360
|
+
bodyIsText,
|
|
361
|
+
timestamp: entry.timestamp,
|
|
362
|
+
ttl: entry.ttl,
|
|
363
|
+
};
|
|
364
|
+
// Convert to JSON
|
|
365
|
+
const json = JSON.stringify(serialized);
|
|
366
|
+
// Compress with gzip
|
|
367
|
+
const compressed = gzipSync(json);
|
|
368
|
+
// Write compressed file
|
|
369
|
+
writeFileSync(filePath, compressed);
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
// Silently fail if can't write cache
|
|
373
|
+
console.warn("Failed to write cache:", error);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Clear cache for a specific URL or all
|
|
378
|
+
*/
|
|
379
|
+
clear(url) {
|
|
380
|
+
// Clear L1
|
|
381
|
+
this.l1.clear();
|
|
382
|
+
// Clear L2
|
|
383
|
+
if (url) {
|
|
384
|
+
// Clear all cache files for this URL
|
|
385
|
+
// This is approximate since we hash the keys
|
|
386
|
+
// For now, just clear all to be safe
|
|
387
|
+
this.clearAllDisk();
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
this.clearAllDisk();
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Clear all L2 disk cache files
|
|
395
|
+
*/
|
|
396
|
+
clearAllDisk() {
|
|
397
|
+
try {
|
|
398
|
+
const files = readdirSync(this.cacheDir);
|
|
399
|
+
for (const file of files) {
|
|
400
|
+
if (file.endsWith(".json.gz")) {
|
|
401
|
+
unlinkSync(join(this.cacheDir, file));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
// Silently fail
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Get combined cache statistics
|
|
411
|
+
*/
|
|
412
|
+
stats() {
|
|
413
|
+
const l1Stats = this.l1.stats();
|
|
414
|
+
// L2 disk stats
|
|
415
|
+
let diskSize = 0;
|
|
416
|
+
let diskFiles = 0;
|
|
417
|
+
let totalDiskBytes = 0;
|
|
418
|
+
try {
|
|
419
|
+
const files = readdirSync(this.cacheDir);
|
|
420
|
+
const cacheFiles = files.filter((f) => f.endsWith(".json.gz"));
|
|
421
|
+
diskFiles = cacheFiles.length;
|
|
422
|
+
for (const file of cacheFiles) {
|
|
423
|
+
const stats = statSync(join(this.cacheDir, file));
|
|
424
|
+
totalDiskBytes += stats.size;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
catch { }
|
|
428
|
+
return {
|
|
429
|
+
l1: l1Stats,
|
|
430
|
+
l2: {
|
|
431
|
+
size: diskFiles,
|
|
432
|
+
maxSize: this.maxDiskSize,
|
|
433
|
+
cacheDir: this.cacheDir,
|
|
434
|
+
totalSizeKB: (totalDiskBytes / 1024).toFixed(2),
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../components/cache.ts"],"names":[],"mappings":"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"}
|