@avalw/search-worker 1.1.0 → 2.1.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/README.md +320 -358
- package/bin/cli.js +239 -38
- package/index.js +887 -0
- package/package.json +15 -22
- package/LICENSE +0 -21
- package/examples/basic-usage.js +0 -32
- package/examples/express-integration.js +0 -73
- package/examples/search-api.js +0 -58
- package/lib/worker.js +0 -319
package/bin/cli.js
CHANGED
|
@@ -1,54 +1,255 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* AVALW Search Worker CLI v2.1.0
|
|
5
|
+
* Distributed Cache Worker for AVALW Search Network
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Intelligent cache with configurable size limits (100MB - 2GB)
|
|
9
|
+
* - Time-based eviction (1-30 days, default 7)
|
|
10
|
+
* - Popularity scoring (frequently accessed stay longer)
|
|
11
|
+
* - Background auto-cleanup
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* npx @avalw/search-worker --token YOUR_TOKEN
|
|
15
|
+
* AVALW_WORKER_TOKEN=xxx npx @avalw/search-worker
|
|
16
|
+
*/
|
|
4
17
|
|
|
5
|
-
const
|
|
6
|
-
const
|
|
18
|
+
const { SearchWorker } = require('../index');
|
|
19
|
+
const os = require('os');
|
|
7
20
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
21
|
+
// Parse command line arguments
|
|
22
|
+
const args = process.argv.slice(2);
|
|
23
|
+
let token = process.env.AVALW_WORKER_TOKEN;
|
|
24
|
+
let dashboardUrl = process.env.AVALW_DASHBOARD_URL || 'https://worker.avalw.org';
|
|
25
|
+
let wsUrl = process.env.AVALW_WS_URL || 'wss://worker.avalw.org/ws/cache';
|
|
26
|
+
let cacheSizeMB = parseInt(process.env.AVALW_CACHE_SIZE_MB) || 500;
|
|
27
|
+
let maxAgeDays = parseInt(process.env.AVALW_MAX_AGE_DAYS) || 7;
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i < args.length; i++) {
|
|
30
|
+
if (args[i] === '--token' || args[i] === '-t') {
|
|
31
|
+
token = args[i + 1];
|
|
32
|
+
i++;
|
|
33
|
+
} else if (args[i] === '--dashboard' || args[i] === '-d') {
|
|
34
|
+
dashboardUrl = args[i + 1];
|
|
35
|
+
i++;
|
|
36
|
+
} else if (args[i] === '--ws' || args[i] === '-w') {
|
|
37
|
+
wsUrl = args[i + 1];
|
|
38
|
+
i++;
|
|
39
|
+
} else if (args[i] === '--cache-size' || args[i] === '-s') {
|
|
40
|
+
cacheSizeMB = Math.min(Math.max(parseInt(args[i + 1]) || 500, 100), 2048);
|
|
41
|
+
i++;
|
|
42
|
+
} else if (args[i] === '--max-age' || args[i] === '-a') {
|
|
43
|
+
maxAgeDays = Math.min(Math.max(parseInt(args[i + 1]) || 7, 1), 30);
|
|
44
|
+
i++;
|
|
45
|
+
} else if (args[i] === '--help' || args[i] === '-h') {
|
|
46
|
+
showHelp();
|
|
47
|
+
process.exit(0);
|
|
48
|
+
} else if (args[i] === '--version' || args[i] === '-v') {
|
|
49
|
+
const pkg = require('../package.json');
|
|
50
|
+
console.log(`@avalw/search-worker v${pkg.version}`);
|
|
51
|
+
process.exit(0);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function showHelp() {
|
|
56
|
+
console.log(`
|
|
57
|
+
AVALW Search Worker v2.1.0 - Intelligent Distributed Cache
|
|
58
|
+
|
|
59
|
+
USAGE:
|
|
60
|
+
npx @avalw/search-worker [options]
|
|
61
|
+
avalw-worker [options]
|
|
62
|
+
|
|
63
|
+
OPTIONS:
|
|
64
|
+
-t, --token <token> Worker token from worker.avalw.org
|
|
65
|
+
-s, --cache-size <MB> Max cache size in MB (100-2048, default: 500)
|
|
66
|
+
-a, --max-age <days> Remove unused queries after N days (1-30, default: 7)
|
|
67
|
+
-d, --dashboard <url> Dashboard URL (default: https://worker.avalw.org)
|
|
68
|
+
-w, --ws <url> WebSocket URL (default: wss://worker.avalw.org/ws/cache)
|
|
69
|
+
-h, --help Show this help
|
|
70
|
+
-v, --version Show version
|
|
71
|
+
|
|
72
|
+
ENVIRONMENT VARIABLES:
|
|
73
|
+
AVALW_WORKER_TOKEN Worker authentication token
|
|
74
|
+
AVALW_CACHE_SIZE_MB Max cache size in MB (default: 500)
|
|
75
|
+
AVALW_MAX_AGE_DAYS Days to keep unused queries (default: 7)
|
|
76
|
+
AVALW_DASHBOARD_URL Dashboard API URL
|
|
77
|
+
AVALW_WS_URL WebSocket coordinator URL
|
|
78
|
+
|
|
79
|
+
EXAMPLES:
|
|
80
|
+
# Run with default settings (500MB cache, 7 day retention)
|
|
81
|
+
npx @avalw/search-worker --token abc123...
|
|
82
|
+
|
|
83
|
+
# Run with 1GB cache and 14 day retention
|
|
84
|
+
npx @avalw/search-worker --token abc123 --cache-size 1024 --max-age 14
|
|
85
|
+
|
|
86
|
+
# Run with maximum cache (2GB)
|
|
87
|
+
npx @avalw/search-worker --token abc123 --cache-size 2048
|
|
88
|
+
|
|
89
|
+
# Run with environment variables
|
|
90
|
+
export AVALW_WORKER_TOKEN=abc123...
|
|
91
|
+
export AVALW_CACHE_SIZE_MB=1024
|
|
92
|
+
npx @avalw/search-worker
|
|
93
|
+
|
|
94
|
+
GET STARTED:
|
|
95
|
+
1. Visit https://worker.avalw.org
|
|
96
|
+
2. Register to get your worker token
|
|
97
|
+
3. Run: npx @avalw/search-worker --token YOUR_TOKEN
|
|
98
|
+
|
|
99
|
+
INTELLIGENT CACHE:
|
|
100
|
+
Your worker uses smart caching with:
|
|
101
|
+
- Size Limits: Configurable from 100MB to 2GB
|
|
102
|
+
- Time Eviction: Unused queries auto-removed after N days
|
|
103
|
+
- Popularity: Frequently accessed queries stay longer
|
|
104
|
+
- Auto-Cleanup: Background process keeps cache healthy
|
|
105
|
+
|
|
106
|
+
HOW IT WORKS:
|
|
107
|
+
Your worker connects to the AVALW coordinator and serves as a distributed
|
|
108
|
+
cache node. When users search on avalw.org, your worker may serve cached
|
|
109
|
+
results, reducing load on AVALW servers.
|
|
110
|
+
|
|
111
|
+
In exchange for contributing cache storage, you earn Core-Hours which
|
|
112
|
+
unlock API access tiers for your own applications.
|
|
113
|
+
`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Check token
|
|
117
|
+
if (!token) {
|
|
118
|
+
console.error(`
|
|
119
|
+
ERROR: Worker token required!
|
|
120
|
+
|
|
121
|
+
Get your token at https://worker.avalw.org
|
|
122
|
+
|
|
123
|
+
Usage:
|
|
124
|
+
npx @avalw/search-worker --token YOUR_TOKEN
|
|
125
|
+
|
|
126
|
+
Or set environment variable:
|
|
127
|
+
export AVALW_WORKER_TOKEN=YOUR_TOKEN
|
|
128
|
+
npx @avalw/search-worker
|
|
129
|
+
`);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Print banner
|
|
134
|
+
console.log('');
|
|
135
|
+
console.log('===============================================================');
|
|
136
|
+
console.log(' AVALW SEARCH WORKER v2.1.0 - Intelligent Distributed Cache');
|
|
137
|
+
console.log('===============================================================');
|
|
138
|
+
console.log('');
|
|
139
|
+
|
|
140
|
+
// Print system info
|
|
141
|
+
const cpus = os.cpus();
|
|
142
|
+
const totalMem = Math.round(os.totalmem() / (1024 * 1024 * 1024) * 10) / 10;
|
|
143
|
+
const cpuModel = cpus[0]?.model || 'Unknown';
|
|
144
|
+
const cpuSpeed = cpus[0]?.speed || 0;
|
|
145
|
+
|
|
146
|
+
console.log(` System Info:`);
|
|
147
|
+
console.log(` CPU: ${cpuModel}`);
|
|
148
|
+
console.log(` Cores: ${cpus.length}`);
|
|
149
|
+
console.log(` Speed: ${(cpuSpeed / 1000).toFixed(2)} GHz`);
|
|
150
|
+
console.log(` Memory: ${totalMem} GB`);
|
|
151
|
+
console.log(` Platform: ${os.platform()} ${os.arch()}`);
|
|
152
|
+
console.log('');
|
|
153
|
+
console.log(` Cache Config:`);
|
|
154
|
+
console.log(` Max Size: ${cacheSizeMB} MB`);
|
|
155
|
+
console.log(` Max Age: ${maxAgeDays} days (unused queries auto-removed)`);
|
|
156
|
+
console.log('');
|
|
157
|
+
console.log(` Coordinator: ${wsUrl}`);
|
|
158
|
+
console.log(` Dashboard: ${dashboardUrl}`);
|
|
159
|
+
console.log('');
|
|
160
|
+
console.log('===============================================================');
|
|
161
|
+
console.log('');
|
|
162
|
+
|
|
163
|
+
// Create and start worker
|
|
164
|
+
const worker = new SearchWorker({
|
|
165
|
+
workerToken: token,
|
|
166
|
+
dashboardUrl: dashboardUrl,
|
|
167
|
+
wsUrl: wsUrl,
|
|
168
|
+
cacheSizeMB: cacheSizeMB,
|
|
169
|
+
maxAgeDays: maxAgeDays,
|
|
170
|
+
|
|
171
|
+
onConnected: (w) => {
|
|
172
|
+
console.log('');
|
|
173
|
+
console.log(' [CONNECTED] Successfully connected to coordinator');
|
|
174
|
+
const config = w.getCacheConfig();
|
|
175
|
+
console.log(` [CACHE] Ready - Max: ${config.maxSizeFormatted}, Retention: ${config.maxAgeDays} days`);
|
|
176
|
+
console.log('');
|
|
177
|
+
console.log(' Press Ctrl+C to stop the worker');
|
|
178
|
+
console.log('');
|
|
179
|
+
console.log('---------------------------------------------------------------');
|
|
180
|
+
console.log('');
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
onDisconnected: (w) => {
|
|
184
|
+
console.log(' [DISCONNECTED] Lost connection to coordinator');
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
onCacheHit: (key) => {
|
|
188
|
+
const query = key.split(':')[0];
|
|
189
|
+
console.log(` [CACHE HIT] Served: "${query.substring(0, 30)}..."`);
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
onCacheStore: (key) => {
|
|
193
|
+
const query = key.split(':')[0];
|
|
194
|
+
console.log(` [CACHED] Stored: "${query.substring(0, 30)}..."`);
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
onError: (err) => {
|
|
198
|
+
console.error(` [ERROR] ${err}`);
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
onLog: (msg) => {
|
|
202
|
+
const time = new Date().toLocaleTimeString();
|
|
203
|
+
console.log(` [${time}] ${msg}`);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Connect to coordinator
|
|
208
|
+
worker.connect();
|
|
209
|
+
|
|
210
|
+
// Print stats every 5 minutes
|
|
211
|
+
setInterval(() => {
|
|
212
|
+
const stats = worker.getStats();
|
|
213
|
+
const cache = stats.cache;
|
|
13
214
|
console.log('');
|
|
14
|
-
console.log('
|
|
215
|
+
console.log('---------------------------------------------------------------');
|
|
216
|
+
console.log(` [STATS] Entries: ${cache.entries} | Size: ${cache.sizeFormatted} / ${cache.maxSizeFormatted} (${cache.utilizationPercent}%)`);
|
|
217
|
+
console.log(` [STATS] Hits: ${stats.cacheHits} | Misses: ${stats.cacheMisses} | Hit Rate: ${stats.hitRate}%`);
|
|
218
|
+
console.log(` [STATS] Evictions: ${cache.evictions} (time: ${cache.timeEvictions}, popularity: ${cache.popularityEvictions})`);
|
|
219
|
+
console.log('---------------------------------------------------------------');
|
|
15
220
|
console.log('');
|
|
16
|
-
|
|
221
|
+
}, 5 * 60 * 1000);
|
|
222
|
+
|
|
223
|
+
// Handle shutdown
|
|
224
|
+
process.on('SIGINT', () => {
|
|
17
225
|
console.log('');
|
|
18
|
-
console.log('
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
console.log(' │ Pro │ 20,000/day │ 36/day │ 6 cores │');
|
|
25
|
-
console.log(' │ Business │ 50,000/day │ 72/day │ 8 cores │');
|
|
26
|
-
console.log(' │ Enterprise│ 500,000/day │ 240/day │ 16 cores │');
|
|
27
|
-
console.log(' └───────────┴─────────────┴──────────────┴─────────────┘');
|
|
226
|
+
console.log(' [SHUTDOWN] Stopping worker...');
|
|
227
|
+
|
|
228
|
+
worker.disconnect();
|
|
229
|
+
|
|
230
|
+
const stats = worker.getStats();
|
|
231
|
+
const cache = stats.cache;
|
|
28
232
|
console.log('');
|
|
29
|
-
console.log('
|
|
30
|
-
console.log('
|
|
233
|
+
console.log('===============================================================');
|
|
234
|
+
console.log(' Final Stats:');
|
|
235
|
+
console.log(` Uptime: ${Math.round(stats.uptime / 1000 / 60)} minutes`);
|
|
236
|
+
console.log(` Cache Size: ${cache.entries} entries (${cache.sizeFormatted})`);
|
|
237
|
+
console.log(` Cache Hits: ${stats.cacheHits}`);
|
|
238
|
+
console.log(` Cache Misses: ${stats.cacheMisses}`);
|
|
239
|
+
console.log(` Hit Rate: ${stats.hitRate}%`);
|
|
240
|
+
console.log(` Served: ${stats.requestsServed} requests`);
|
|
241
|
+
console.log(` Evictions: ${cache.evictions} total`);
|
|
242
|
+
console.log(` - Time: ${cache.timeEvictions}`);
|
|
243
|
+
console.log(` - Popularity: ${cache.popularityEvictions}`);
|
|
244
|
+
console.log('===============================================================');
|
|
31
245
|
console.log('');
|
|
32
|
-
console.log('
|
|
33
|
-
console.log(' avalw-worker abc123def456...');
|
|
246
|
+
console.log(' Thank you for contributing to AVALW!');
|
|
34
247
|
console.log('');
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
248
|
|
|
38
|
-
const worker = new AvalwWorker(token, apiUrl);
|
|
39
|
-
|
|
40
|
-
// Handle graceful shutdown
|
|
41
|
-
process.on('SIGINT', async () => {
|
|
42
|
-
console.log('\n Shutting down worker...');
|
|
43
|
-
await worker.stop();
|
|
44
249
|
process.exit(0);
|
|
45
250
|
});
|
|
46
251
|
|
|
47
|
-
process.on('SIGTERM',
|
|
48
|
-
|
|
49
|
-
await worker.stop();
|
|
252
|
+
process.on('SIGTERM', () => {
|
|
253
|
+
worker.disconnect();
|
|
50
254
|
process.exit(0);
|
|
51
255
|
});
|
|
52
|
-
|
|
53
|
-
// Start worker
|
|
54
|
-
worker.start();
|