-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathprejs_file_api.js
More file actions
148 lines (145 loc) · 6.77 KB
/
prejs_file_api.js
File metadata and controls
148 lines (145 loc) · 6.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/**
* Web Worker API for libzim JavaScript bindings
*
* This file provides the pre-JS portion of the web worker that handles ZIM file operations.
* It is concatenated with postjs_file_api.js during the Emscripten build process (see Makefile)
* to create a complete web worker script that can be used with WebAssembly or asm.js builds.
*
* Supported actions: getEntryByPath, search, searchWithSnippets, suggest, getArticleCount, init
*/
self.addEventListener('message', function(e) {
var action = e.data.action;
var path = e.data.path;
var outgoingMessagePort = e.ports[0];
console.debug('WebWorker called with action=' + action);
// Retrieve content from ZIM archive by path
if (action === 'getEntryByPath') {
var follow = e.data.follow;
var entry = Module[action](path);
if (entry) {
var item = {};
if (follow || !entry.isRedirect()) {
item = entry.getItem(follow);
// It's necessary to keep an instance of the blob till the end of this block,
// to ensure that the corresponding content is not deleted on the C side.
var blob = item.getData();
var content = blob.getContent();
// TODO : is there a more efficient way to make the Array detachable? So that it can be transfered back from the WebWorker without a copy?
var contentArray = new Uint8Array(content);
outgoingMessagePort.postMessage({ content: contentArray, mimetype: item.getMimetype(), isRedirect: entry.isRedirect()});
}
else {
outgoingMessagePort.postMessage({ content: new Uint8Array(), isRedirect: true, redirectPath: entry.getRedirectEntry().getPath()});
}
}
else {
outgoingMessagePort.postMessage({ content: new Uint8Array(), mimetype: 'unknown', isRedirect: false});
}
}
// Full-text search across ZIM archive content (basic version - paths only)
else if (action === 'search') {
var text = e.data.text;
var numResults = e.data.numResults || 50;
var entries = Module[action](text, numResults);
console.debug('Found nb results = ' + entries.size(), entries);
var serializedResults = [];
for (var i=0; i<entries.size(); i++) {
var entry = entries.get(i);
serializedResults.push({
path: entry.getPath(),
title: entry.getTitle(),
snippet: null,
score: null,
wordCount: null
});
}
outgoingMessagePort.postMessage({ results: serializedResults });
}
// NEW: Enhanced full-text search with content snippets
else if (action === 'searchWithSnippets') {
var text = e.data.text;
var numResults = e.data.numResults || 50;
try {
var searchResults = Module['searchWithSnippets'](text, numResults);
console.debug('Found nb search results with snippets = ' + searchResults.size(), searchResults);
var serializedResults = [];
for (var i=0; i<searchResults.size(); i++) {
var result = searchResults.get(i);
try {
serializedResults.push({
path: result.getPath(),
title: result.getTitle(),
snippet: result.getSnippet(),
score: result.getScore(),
wordCount: result.getWordCount()
});
} catch (error) {
console.warn('Error processing search result ' + i + ':', error);
// Include basic info even if snippet extraction fails
serializedResults.push({
path: result.getPath() || '',
title: result.getTitle() || '',
snippet: '',
score: 0,
wordCount: 0
});
}
}
outgoingMessagePort.postMessage({ results: serializedResults });
} catch (error) {
console.error('searchWithSnippets error:', error);
outgoingMessagePort.postMessage({ results: [], error: error.message });
}
}
// Title-based suggestions for autocomplete (faster than full-text search)
else if (action === 'suggest') {
var text = e.data.text;
var numResults = e.data.numResults || 10;
var suggestions = Module[action](text, numResults);
console.debug('Found nb suggestions = ' + suggestions.size(), suggestions);
var serializedSuggestions = [];
for (var i=0; i<suggestions.size(); i++) {
var entry = suggestions.get(i);
serializedSuggestions.push({path: entry.getPath(), title: entry.getTitle()});
}
outgoingMessagePort.postMessage({ suggestions: serializedSuggestions });
}
// Get total number of articles in the ZIM archive
else if (action === 'getArticleCount') {
var articleCount = Module[action]();
outgoingMessagePort.postMessage(articleCount);
}
// Initialize the ZIM archive with file system mounting
else if (action === 'init') {
var files = e.data.files;
var assemblerType = e.data.assemblerType || 'runtime';
// When using split ZIM files, we need to remove the last two letters of the suffix (like .zimaa -> .zim)
var baseZimFileName = files[0].name.replace(/\.zim..$/, '.zim');
Module = {};
Module['onRuntimeInitialized'] = function() {
Module.loadArchive('/work/' + baseZimFileName);
console.debug(assemblerType + ' initialized');
outgoingMessagePort.postMessage('runtime initialized');
};
Module['arguments'] = [];
for (let i = 0; i < files.length; i++) {
Module['arguments'].push('/work/' + files[i].name);
}
// Mount file system for ZIM file access (Electron vs browser environments)
Module['preRun'] = function() {
FS.mkdir('/work');
if (files[0].readMode === 'electron') {
var path = files[0].path.replace(/[^\\/]+$/, '');
FS.mount(NODEFS, {
root: path
}, '/work');
} else {
FS.mount(WORKERFS, {
files: files
}, '/work');
}
};
console.debug('baseZimFileName = ' + baseZimFileName);
console.debug("Module['arguments'] = " + Module['arguments']);
// File continues in postjs_file_api.js - handles invalid actions and closes the event listener
// Between prejs and postjs: Emscripten injects the compiled WebAssembly/asm.js Module code and bindings