Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
32fbce8
Separating file packager fetch.
seanmorris May 30, 2024
b88154d
Tweak
seanmorris May 30, 2024
b8e2ed9
Accounting for differences between FF & Chrome error text in test.
seanmorris May 30, 2024
58fcb8f
Fixing exception detection in test_missing_data_throws_error
seanmorris May 30, 2024
3945a0b
Correctly reporting overall total of dowloads
seanmorris May 30, 2024
c31c0f8
Removing debug.
seanmorris May 30, 2024
b76122f
Merge branch 'main' into sm-worker-package-fetch
seanmorris May 31, 2024
9712210
Reverting common.py
seanmorris Sep 17, 2024
ba19ffc
Merge branch 'main' into sm-worker-package-fetch
seanmorris Sep 17, 2024
30d2d8e
PR comments.
seanmorris Sep 17, 2024
0c88d25
Merge conflict res.
seanmorris Sep 17, 2024
0e769ca
Removing custom shell from test_fetch_polyfill_preload
seanmorris Sep 17, 2024
b23fffa
Restoring custom shell.
seanmorris Sep 17, 2024
c3fadbc
Removing shell correctly.
seanmorris Sep 17, 2024
4b05f80
origFetch.
seanmorris Sep 17, 2024
8a027b7
Tweaks
seanmorris Sep 17, 2024
9b415a6
Tweaks
seanmorris Sep 17, 2024
db4a31d
Spacing.
seanmorris Sep 17, 2024
3bf0964
Tweaks.
seanmorris Sep 17, 2024
03b301a
Correctly checking exit code.
seanmorris Sep 17, 2024
8ff77d0
Minimal custom shell.
seanmorris Sep 17, 2024
5b37c95
closing HTML tag.
seanmorris Sep 17, 2024
34b1afd
Extra test.
seanmorris Sep 17, 2024
bedece9
Spacing.
seanmorris Sep 17, 2024
6bffc95
Merge branch 'main' into sm-worker-package-fetch
seanmorris Sep 17, 2024
e2c4ea8
Merge branch 'main' into sm-worker-package-fetch
seanmorris Sep 18, 2024
efaf744
Style.
seanmorris Sep 18, 2024
027532e
Merge branch 'sm-worker-package-fetch' of github.com:seanmorris/emscr…
seanmorris Sep 18, 2024
e360fa8
Brackets.
seanmorris Sep 19, 2024
295b750
Style.
seanmorris Sep 19, 2024
27a84da
Style.
seanmorris Sep 19, 2024
206bb2b
Spacing
seanmorris Sep 19, 2024
4168338
Merge branch 'main' into sm-worker-package-fetch
seanmorris Sep 19, 2024
f622a0d
Modernizing JS.
seanmorris Sep 19, 2024
e24cc12
Merge branch 'sm-worker-package-fetch' of github.com:seanmorris/emscr…
seanmorris Sep 19, 2024
489bc06
Style.
seanmorris Sep 19, 2024
071b814
Spacing
seanmorris Sep 19, 2024
ddb958e
Style
seanmorris Sep 19, 2024
c553d28
Style
seanmorris Sep 19, 2024
61dea12
Merge branch 'main' into sm-worker-package-fetch
seanmorris Sep 19, 2024
661258b
Style & typo.
seanmorris Sep 19, 2024
06404fb
Merge branch 'sm-worker-package-fetch' of github.com:seanmorris/emscr…
seanmorris Sep 19, 2024
68d3d02
Removing debug.
seanmorris Sep 19, 2024
9b00c17
Simplifying package data assembly.
seanmorris Sep 20, 2024
e78ac48
Style.
seanmorris Sep 20, 2024
27a1c42
Readability.
seanmorris Sep 20, 2024
edd3a18
Readability.
seanmorris Sep 20, 2024
a7747d4
-1 diff size.
seanmorris Sep 20, 2024
78958aa
Simpler
seanmorris Sep 20, 2024
572bf74
Spacing.
seanmorris Sep 20, 2024
4386290
Merge branch 'main' into sm-worker-package-fetch
seanmorris Sep 20, 2024
e68044e
You can't concat() TypedArrays...
seanmorris Sep 20, 2024
4fac7e0
Spacing.
seanmorris Sep 20, 2024
1c9d521
Merge branch 'main' into sm-worker-package-fetch
seanmorris Sep 20, 2024
aadfaec
Spacing.
seanmorris Sep 20, 2024
6fd7e01
Merge branch 'sm-worker-package-fetch' of github.com:seanmorris/emscr…
seanmorris Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion test/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2266,7 +2266,7 @@ def compile_btest(self, filename, args, reporting=Reporting.FULL):
if reporting == Reporting.FULL:
# If C reporting (i.e. the REPORT_RESULT macro) is required we
# also include report_result.c and force-include report_result.h
self.run_process([EMCC, '-c', '-I' + TEST_ROOT,
self.run_process([EMCC, '-c', '-fPIC', '-I' + TEST_ROOT,
'-DEMTEST_PORT_NUMBER=%d' % self.port,
test_file('report_result.c')] + self.get_emcc_args(compile_only=True) + (['-fPIC'] if '-fPIC' in args else []))
args += ['report_result.o', '-include', test_file('report_result.h')]
Expand Down
60 changes: 60 additions & 0 deletions test/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -5541,6 +5541,66 @@ def test_webpack(self):
shutil.copyfile('webpack/src/hello.wasm', 'webpack/dist/hello.wasm')
self.run_browser('webpack/dist/index.html', '/report_result?exit:0')

def test_fetch_polyfill_preload(self):
path = 'hello-world.txt'
create_file(path, 'hello, world!')
create_file('main.cpp', r'''
#include <stdio.h>
#include <string.h>
#include <emscripten.h>
int main() {
FILE *f = fopen("%s", "r");
char buf[100];
fread(buf, 1, 20, f);
buf[20] = 0;
fclose(f);
printf("|%%s|\n", buf);
return 0;
}
''' % path)
create_file('on_window_error_shell.html', r'''
<html>
<center><canvas id='canvas' width='256' height='256'></canvas></center>
<hr><div id='output'></div><hr>
<script type='text/javascript'>
window.addEventListener('error', event => {
const error = String(event.message);
console.log({error});
window.disableErrorReporting = true;
window.onerror = null;
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8888/report_result?' + (error.includes('fetch is not a function') ? 1 : 0), true);
xhr.send();
setTimeout(function() { window.close() }, 1000);
});
var Module = {
print: (function() {
var element = document.getElementById('output');
return function(text) {
console.log({text});
if(window.disableErrorReporting) return;
element.innerHTML += text.replace('\n', '<br>', 'g') + '<br>';
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8888/report_result?' + (text === '|hello, world!|' ? 1 : 0), true);
xhr.send();
};
})(),
canvas: document.getElementById('canvas')
};
</script>
{{{ SCRIPT }}}
</body>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than require special shell can you just rely on the fact that default reporting will try bot fetch and origFetch:

let doFetch = typeof origFetch != 'undefined' ? origFetch : fetch;

i.e. when you disable fetch you can cache the original fetch so that that browser reporting doesn't break.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sbc100 I'm not able to get the exception out of the browser without the custom shell. It just hangs with the exception listed as uncaught in the browser's console.

</html>''')

def test(args, expect_fail):
self.compile_btest('main.cpp', args + ['--preload-file', path, '--shell-file', 'on_window_error_shell.html', '-o', 'a.out.html'])
js = read_file('a.out.js')
if expect_fail:
create_file('a.out.js', 'fetch = undefined;\n' + js)
return self.run_browser('a.out.html', '/report_result?1')
else:
return self.run_browser('a.out.html', '/report_result?1')

def test_fetch_polyfill_shared_lib(self):
create_file('library.c', r'''
#include <stdio.h>
Expand Down
135 changes: 78 additions & 57 deletions tools/file_packager.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ def generate_object_file(data_files):

def main():
if len(sys.argv) == 1:
err('''Usage: file_packager TARGET [--preload A [B..]] [--embed C [D..]] [--exclude E [F..]]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--indexedDB-name=EM_PRELOAD_CACHE] [--separate-metadata] [--lz4] [--use-preload-plugins]
err('''Usage: file_packager TARGET [--preload A [B..]] [--embed C [D..]] [--exclude E [F..]]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--indexedDB-name=EM_PRELOAD_CACHE] [--separate-metadata] [--lz4] [--use-preload-plugins] [--no-node]
See the source for more details.''')
return 1

Expand Down Expand Up @@ -775,7 +775,7 @@ def generate_js(data_target, data_files, metadata):
}
var REMOTE_PACKAGE_NAME = Module['locateFile'] ? Module['locateFile'](REMOTE_PACKAGE_BASE, '') : REMOTE_PACKAGE_BASE;\n''' % (js_manipulation.escape_for_js_string(data_target), js_manipulation.escape_for_js_string(remote_package_name))
metadata['remote_package_size'] = remote_package_size
ret += '''var REMOTE_PACKAGE_SIZE = metadata['remote_package_size'];\n'''
ret += ''' var REMOTE_PACKAGE_SIZE = metadata['remote_package_size'];\n'''

if options.use_preload_cache:
# Set the id to a hash of the preloaded data, so that caches survive over multiple builds
Expand Down Expand Up @@ -965,59 +965,82 @@ def generate_js(data_target, data_files, metadata):
});
return;
}'''.strip()

ret += '''
function fetchRemotePackage(packageName, packageSize, callback, errback) {
%(node_support_code)s
var xhr = new XMLHttpRequest();
xhr.open('GET', packageName, true);
xhr.responseType = 'arraybuffer';
xhr.onprogress = function(event) {
var url = packageName;
var size = packageSize;
if (event.total) size = event.total;
if (event.loaded) {
if (!xhr.addedTotal) {
xhr.addedTotal = true;
if (!Module.dataFileDownloads) Module.dataFileDownloads = {};
Module.dataFileDownloads[url] = {
loaded: event.loaded,
total: size
};
} else {
Module.dataFileDownloads[url].loaded = event.loaded;
}
var total = 0;
var loaded = 0;
var num = 0;
for (var download in Module.dataFileDownloads) {
var data = Module.dataFileDownloads[download];
total += data.total;
loaded += data.loaded;
num++;
}
total = Math.ceil(total * Module.expectedDataFileDownloads/num);
if (Module['setStatus']) Module['setStatus'](`Downloading data... (${loaded}/${total})`);
} else if (!Module.dataFileDownloads) {
if (Module['setStatus']) Module['setStatus']('Downloading data...');
Module.dataFileDownloads = Module.dataFileDownloads || {};
const url = packageName;
fetch(url)
.catch(cause => Promise.reject(new Error('Network Error : ' + url, {cause}))) // If fetch fails, rewrite the error to include the failing URL & the cause.
.then(response => {

let loaded = 0;

if (!response.ok) {
return Promise.reject(new Error(response.statusText + ' : ' + response.url));
}
};
xhr.onerror = function(event) {
throw new Error("NetworkError for: " + packageName);
}
xhr.onload = function(event) {
if (xhr.status == 200 || xhr.status == 304 || xhr.status == 206 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
var packageData = xhr.response;
callback(packageData);
} else {
throw new Error(xhr.statusText + " : " + xhr.responseURL);

// If we're using the polyfill, readers won't be available...
if(!response.body && response.arrayBuffer) {
response.arrayBuffer().then(buffer => callback(buffer));
return;
}
};
xhr.send(null);
};

const reader = response.body.getReader();
const headers = response.headers;

const size = headers.get('Content-Length') ?? packageSize;
const chunks = [];

const iterate = () => reader.read().then(handleChunk).catch(cause => {
return Promise.reject(new Error('Unexpected error while handling : ' + response.url + ' ' + cause, {cause}));
});

const handleChunk = ({done, value}) => {
if (!done) {
chunks.push(value);
loaded += value.length;
Module.dataFileDownloads[url] = Module.dataFileDownloads[url] ?? {};
Module.dataFileDownloads[url].loaded = loaded;
Module.dataFileDownloads[url].total = size;

let totalLoaded = 0;
let totalSize = 0;

for (const dowload of Object.values(Module.dataFileDownloads)) {
totalLoaded += dowload.loaded;
totalSize += dowload.total;
}

if (totalSize) {
if (Module['setStatus']) Module['setStatus'](`Downloading data... (${totalLoaded}/${totalSize})`);
}
else {
if (Module['setStatus']) Module['setStatus']('Downloading data...');
}
return iterate();
}
else {
const size = chunks.map(c => c.length).reduce((a, b) => a + b, 0);
let index = 0;
const packageData = new Uint8Array(size);
for(const chunk of chunks) {
packageData.set(chunk, index);
index += chunk.length;
}

callback(packageData.buffer);
}
};
return iterate();
});
};\n''' % {'node_support_code': node_support_code}

ret += '''
function handleError(error) {
console.error('package error:', error);
};\n''' % {'node_support_code': node_support_code}
};\n'''

code += '''
function processPackageData(arrayBuffer) {
Expand Down Expand Up @@ -1113,15 +1136,14 @@ def generate_js(data_target, data_files, metadata):
function runMetaWithFS() {
Module['addRunDependency']('%(metadata_file)s');
var REMOTE_METADATA_NAME = Module['locateFile'] ? Module['locateFile']('%(metadata_file)s', '') : '%(metadata_file)s';
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
loadPackage(JSON.parse(xhr.responseText));
}
}
xhr.open('GET', REMOTE_METADATA_NAME, true);
xhr.overrideMimeType('application/json');
xhr.send(null);
fetch(REMOTE_METADATA_NAME)
.then(response => {
if(response.ok) {
return response.json();
}
return Promise.reject(new Error(response.statusText + ' : ' + response.url));
})
.then(loadPackage);
}

if (Module['calledRun']) {
Expand All @@ -1130,7 +1152,6 @@ def generate_js(data_target, data_files, metadata):
if (!Module['preRun']) Module['preRun'] = [];
Module["preRun"].push(runMetaWithFS);
}\n''' % {'metadata_file': os.path.basename(options.jsoutput + '.metadata')}

else:
_metadata_template = '''
}
Expand Down