forked from cory/tildefriends
		
	Made File.readFile async.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3667 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		
							
								
								
									
										73
									
								
								core/auth.js
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								core/auth.js
									
									
									
									
									
								
							| @@ -120,43 +120,48 @@ function authHandler(request, response) { | |||||||
| 			response.writeHead(303, {"Location": formData.return, "Set-Cookie": cookie}); | 			response.writeHead(303, {"Location": formData.return, "Set-Cookie": cookie}); | ||||||
| 			response.end(); | 			response.end(); | ||||||
| 		} else { | 		} else { | ||||||
| 			var html = new TextDecoder("UTF-8").decode(File.readFile("core/auth.html")); | 			File.readFile("core/auth.html").then(function(data) { | ||||||
| 			var contents = ""; | 				var html = new TextDecoder("UTF-8").decode(data); | ||||||
|  | 				var contents = ""; | ||||||
|  |  | ||||||
| 			if (entry) { | 				if (entry) { | ||||||
| 				if (sessionIsNew) { | 					if (sessionIsNew) { | ||||||
| 					contents += '<div>Welcome back, ' + entry.name + '.</div>\n'; | 						contents += '<div>Welcome back, ' + entry.name + '.</div>\n'; | ||||||
|  | 					} else { | ||||||
|  | 						contents += '<div>You are already logged in, ' + entry.name + '.</div>\n'; | ||||||
|  | 					} | ||||||
|  | 					contents += '<div><a href="/login/logout">Logout</a></div>\n'; | ||||||
| 				} else { | 				} else { | ||||||
| 					contents += '<div>You are already logged in, ' + entry.name + '.</div>\n'; | 					contents += '<form method="POST">\n'; | ||||||
|  | 					if (loginError) { | ||||||
|  | 						contents += "<p>" + loginError + "</p>\n"; | ||||||
|  | 					} | ||||||
|  | 					contents += '<div id="auth_greeting"><b>Halt.  Who goes there?</b></div>\n' | ||||||
|  | 					contents += '<div id="auth">\n'; | ||||||
|  | 					contents += '<div id="auth_login">\n' | ||||||
|  | 					if (noAdministrator()) { | ||||||
|  | 						contents += '<div class="notice">There is currently no administrator.  You will be made administrator.</div>\n'; | ||||||
|  | 					} | ||||||
|  | 					contents += '<div><label for="name">Name:</label> <input type="text" id="name" name="name" value=""></div>\n'; | ||||||
|  | 					contents += '<div><label for="password">Password:</label> <input type="password" id="password" name="password" value=""></div>\n'; | ||||||
|  | 					contents += '<div id="confirmPassword" style="display: none"><label for="confirm">Confirm:</label> <input type="password" id="confirm" name="confirm" value=""></div>\n'; | ||||||
|  | 					contents += '<div><input type="checkbox" id="register" name="register" value="1" onchange="showHideConfirm()"> <label for="register">Register a new account</label></div>\n'; | ||||||
|  | 					contents += '<div><input id="loginButton" type="submit" name="submit" value="Login"></div>\n'; | ||||||
|  | 					contents += '</div>'; | ||||||
|  | 					contents += '<div class="auth_or"> - or - </div>'; | ||||||
|  | 					contents += '<div id="auth_guest">\n'; | ||||||
|  | 					contents += '<input id="guestButton" type="submit" name="submit" value="Proceeed as Guest">\n'; | ||||||
|  | 					contents += '</div>\n'; | ||||||
|  | 					contents += '</div>\n'; | ||||||
|  | 					contents += '</form>'; | ||||||
| 				} | 				} | ||||||
| 				contents += '<div><a href="/login/logout">Logout</a></div>\n'; | 				var text = html.replace("<!--SESSION-->", contents); | ||||||
| 			} else { | 				response.writeHead(200, {"Content-Type": "text/html; charset=utf-8", "Set-Cookie": cookie, "Content-Length": text.length}); | ||||||
| 				contents += '<form method="POST">\n'; | 				response.end(text); | ||||||
| 				if (loginError) { | 			}).catch(function(error) { | ||||||
| 					contents += "<p>" + loginError + "</p>\n"; | 				response.writeHead(404, {"Content-Type": "text/plain; charset=utf-8", "Connection": "close"}); | ||||||
| 				} | 				response.end("404 File not found"); | ||||||
| 				contents += '<div id="auth_greeting"><b>Halt.  Who goes there?</b></div>\n' | 			}); | ||||||
| 				contents += '<div id="auth">\n'; |  | ||||||
| 				contents += '<div id="auth_login">\n' |  | ||||||
| 				if (noAdministrator()) { |  | ||||||
| 					contents += '<div class="notice">There is currently no administrator.  You will be made administrator.</div>\n'; |  | ||||||
| 				} |  | ||||||
| 				contents += '<div><label for="name">Name:</label> <input type="text" id="name" name="name" value=""></div>\n'; |  | ||||||
| 				contents += '<div><label for="password">Password:</label> <input type="password" id="password" name="password" value=""></div>\n'; |  | ||||||
| 				contents += '<div id="confirmPassword" style="display: none"><label for="confirm">Confirm:</label> <input type="password" id="confirm" name="confirm" value=""></div>\n'; |  | ||||||
| 				contents += '<div><input type="checkbox" id="register" name="register" value="1" onchange="showHideConfirm()"> <label for="register">Register a new account</label></div>\n'; |  | ||||||
| 				contents += '<div><input id="loginButton" type="submit" name="submit" value="Login"></div>\n'; |  | ||||||
| 				contents += '</div>'; |  | ||||||
| 				contents += '<div class="auth_or"> - or - </div>'; |  | ||||||
| 				contents += '<div id="auth_guest">\n'; |  | ||||||
| 				contents += '<input id="guestButton" type="submit" name="submit" value="Proceeed as Guest">\n'; |  | ||||||
| 				contents += '</div>\n'; |  | ||||||
| 				contents += '</div>\n'; |  | ||||||
| 				contents += '</form>'; |  | ||||||
| 			} |  | ||||||
| 			var text = html.replace("<!--SESSION-->", contents); |  | ||||||
| 			response.writeHead(200, {"Content-Type": "text/html; charset=utf-8", "Set-Cookie": cookie, "Content-Length": text.length}); |  | ||||||
| 			response.end(text); |  | ||||||
| 		} | 		} | ||||||
| 	} else if (request.uri == "/login/logout") { | 	} else if (request.uri == "/login/logout") { | ||||||
| 		removeSession(session); | 		removeSession(session); | ||||||
|   | |||||||
							
								
								
									
										134
									
								
								core/core.js
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								core/core.js
									
									
									
									
									
								
							| @@ -138,48 +138,14 @@ async function getSessionProcessBlob(blobId, session, options) { | |||||||
| 	return getProcessBlob(blobId, 'session_' + session, actualOptions); | 	return getProcessBlob(blobId, 'session_' + session, actualOptions); | ||||||
| } | } | ||||||
|  |  | ||||||
| function readFileUtf8(fileName) { | async function readFileUtf8(fileName) { | ||||||
| 	let data = File.readFile(fileName); | 	let data = await File.readFile(fileName); | ||||||
| 	data = utf8Decode(data); | 	data = utf8Decode(data); | ||||||
| 	return data; | 	return data; | ||||||
| } | } | ||||||
|  |  | ||||||
| let gManifestCache = {}; | let gManifestCache = {}; | ||||||
|  |  | ||||||
| async function getManifest(fileName) { |  | ||||||
| 	let oldEntry = gManifestCache[fileName]; |  | ||||||
| 	let stat = await File.stat(fileName); |  | ||||||
| 	if (oldEntry) { |  | ||||||
| 		if (oldEntry.stat.mtime == stat.mtime && oldEntry.stat.size == stat.size) { |  | ||||||
| 			return oldEntry.manifest; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	let manifest = []; |  | ||||||
| 	let lines = readFileUtf8(fileName).split("\n").map(x => x.trimRight()); |  | ||||||
| 	for (let i = 0; i < lines.length; i++) { |  | ||||||
| 		if (lines[i].substring(0, 4) == "//! ") { |  | ||||||
| 			manifest.push(lines[i].substring(4)); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	let result; |  | ||||||
| 	try { |  | ||||||
| 		if (manifest.length) { |  | ||||||
| 			result = JSON.parse(manifest.join("\n")); |  | ||||||
| 		} |  | ||||||
| 	} catch (error) { |  | ||||||
| 		print("ERROR: getManifest(" + fileName + "): ", error); |  | ||||||
| 		// Oh well.  No manifest. |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	gManifestCache[fileName] = { |  | ||||||
| 		stat: stat, |  | ||||||
| 		manifest: result, |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	return result; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function getProcessBlob(blobId, key, options) { | async function getProcessBlob(blobId, key, options) { | ||||||
| 	var process = gProcesses[key]; | 	var process = gProcesses[key]; | ||||||
| 	if (!process | 	if (!process | ||||||
| @@ -319,15 +285,6 @@ function setGlobalSettings(settings) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| try { |  | ||||||
| 	var data = readFileUtf8(kGlobalSettingsFile); |  | ||||||
| 	if (data) { |  | ||||||
| 		gGlobalSettings = JSON.parse(data); |  | ||||||
| 	} |  | ||||||
| } catch (error) { |  | ||||||
| 	print("Error loading settings from " + kGlobalSettingsFile + ": " + error); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var kStaticFiles = [ | var kStaticFiles = [ | ||||||
| 	{uri: '/', path: 'index.html', type: 'text/html; charset=UTF-8'}, | 	{uri: '/', path: 'index.html', type: 'text/html; charset=UTF-8'}, | ||||||
| 	{uri: '/style.css', path: 'style.css', type: 'text/css; charset=UTF-8'}, | 	{uri: '/style.css', path: 'style.css', type: 'text/css; charset=UTF-8'}, | ||||||
| @@ -351,7 +308,7 @@ function startsWithBytes(data, bytes) { | |||||||
| async function staticFileHandler(request, response, blobId, uri) { | async function staticFileHandler(request, response, blobId, uri) { | ||||||
| 	for (var i in kStaticFiles) { | 	for (var i in kStaticFiles) { | ||||||
| 		if (uri === kStaticFiles[i].uri) { | 		if (uri === kStaticFiles[i].uri) { | ||||||
| 			var data = File.readFile("core/" + kStaticFiles[i].path); | 			var data = await File.readFile("core/" + kStaticFiles[i].path); | ||||||
| 			response.writeHead(200, {"Content-Type": kStaticFiles[i].type, "Content-Length": data.byteLength}); | 			response.writeHead(200, {"Content-Type": kStaticFiles[i].type, "Content-Length": data.byteLength}); | ||||||
| 			response.end(data); | 			response.end(data); | ||||||
| 			return; | 			return; | ||||||
| @@ -403,7 +360,7 @@ async function blobHandler(request, response, blobId, uri) { | |||||||
| 		for (var i in kStaticFiles) { | 		for (var i in kStaticFiles) { | ||||||
| 			if (uri === kStaticFiles[i].uri) { | 			if (uri === kStaticFiles[i].uri) { | ||||||
| 				found = true; | 				found = true; | ||||||
| 				var data = File.readFile("core/" + kStaticFiles[i].path); | 				var data = await File.readFile("core/" + kStaticFiles[i].path); | ||||||
| 				response.writeHead(200, {"Content-Type": kStaticFiles[i].type, "Content-Length": data.byteLength}); | 				response.writeHead(200, {"Content-Type": kStaticFiles[i].type, "Content-Length": data.byteLength}); | ||||||
| 				response.end(data); | 				response.end(data); | ||||||
| 				break; | 				break; | ||||||
| @@ -483,41 +440,56 @@ ssb.onConnectionsChanged = function() { | |||||||
| 	broadcastEvent('onConnectionsChanged', []); | 	broadcastEvent('onConnectionsChanged', []); | ||||||
| } | } | ||||||
|  |  | ||||||
| var auth = require("auth"); | async function loadSettings() { | ||||||
| var httpd = require("httpd"); | 	try { | ||||||
| httpd.all("/login", auth.handler); | 		var data = await readFileUtf8(kGlobalSettingsFile); | ||||||
| httpd.all("", function(request, response) { |  | ||||||
| 	var match; |  | ||||||
| 	if (request.uri === "/" || request.uri === "") { |  | ||||||
| 		response.writeHead(303, {"Location": 'http://' + request.headers.host + gGlobalSettings.index, "Content-Length": "0"}); |  | ||||||
| 		return response.end(); |  | ||||||
| 	} else if (match = /^(\/~[^\/]+\/[^\/]+)(\/?.*)$/.exec(request.uri)) { |  | ||||||
| 		return blobHandler(request, response, match[1], match[2]); |  | ||||||
| 	} else if (match = /^\/([&\%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(request.uri)) { |  | ||||||
| 		return blobHandler(request, response, match[1], match[2]); |  | ||||||
| 	} else if (match = /^\/static(\/.*)/.exec(request.uri)) { |  | ||||||
| 		return staticFileHandler(request, response, null, match[1]); |  | ||||||
| 	} else if (match = /^(.*)(\/save)$/.exec(request.uri)) { |  | ||||||
| 		return blobHandler(request, response, match[1], match[2]); |  | ||||||
| 	} else if (match = /^\/trace$/.exec(request.uri)) { |  | ||||||
| 		var data = trace(); |  | ||||||
| 		response.writeHead(404, {"Content-Type": "application/json; charset=utf-8", "Content-Length": data.length.toString()}); |  | ||||||
| 		return response.end(data); |  | ||||||
| 	} else if (request.uri == "/robots.txt") { |  | ||||||
| 		return blobHandler(request, response, null, request.uri); |  | ||||||
| 	} else if ((match = /^\/.well-known\/(.*)/.exec(request.uri)) && request.uri.indexOf("..") == -1) { |  | ||||||
| 		var data = File.readFile("data/global/.well-known/" + match[1]); |  | ||||||
| 		if (data) { | 		if (data) { | ||||||
| 			response.writeHead(200, {"Content-Type": "text/plain", "Content-Length": data.length}); | 			gGlobalSettings = JSON.parse(data); | ||||||
| 			response.end(data); |  | ||||||
| 		} else { |  | ||||||
| 			response.writeHead(404, {"Content-Type": "text/plain", "Content-Length": "File not found".length}); |  | ||||||
| 			response.end("File not found"); |  | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} catch (error) { | ||||||
| 		var data = "File not found."; | 		print("Error loading settings from " + kGlobalSettingsFile + ": " + error); | ||||||
| 		response.writeHead(404, {"Content-Type": "text/plain; charset=utf-8", "Content-Length": data.length.toString()}); |  | ||||||
| 		return response.end(data); |  | ||||||
| 	} | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | loadSettings().then(function() { | ||||||
|  | 	var auth = require("auth"); | ||||||
|  | 	var httpd = require("httpd"); | ||||||
|  | 	httpd.all("/login", auth.handler); | ||||||
|  | 	httpd.all("", function(request, response) { | ||||||
|  | 		var match; | ||||||
|  | 		if (request.uri === "/" || request.uri === "") { | ||||||
|  | 			response.writeHead(303, {"Location": 'http://' + request.headers.host + gGlobalSettings.index, "Content-Length": "0"}); | ||||||
|  | 			return response.end(); | ||||||
|  | 		} else if (match = /^(\/~[^\/]+\/[^\/]+)(\/?.*)$/.exec(request.uri)) { | ||||||
|  | 			return blobHandler(request, response, match[1], match[2]); | ||||||
|  | 		} else if (match = /^\/([&\%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(request.uri)) { | ||||||
|  | 			return blobHandler(request, response, match[1], match[2]); | ||||||
|  | 		} else if (match = /^\/static(\/.*)/.exec(request.uri)) { | ||||||
|  | 			return staticFileHandler(request, response, null, match[1]); | ||||||
|  | 		} else if (match = /^(.*)(\/save)$/.exec(request.uri)) { | ||||||
|  | 			return blobHandler(request, response, match[1], match[2]); | ||||||
|  | 		} else if (match = /^\/trace$/.exec(request.uri)) { | ||||||
|  | 			var data = trace(); | ||||||
|  | 			response.writeHead(404, {"Content-Type": "application/json; charset=utf-8", "Content-Length": data.length.toString()}); | ||||||
|  | 			return response.end(data); | ||||||
|  | 		} else if (request.uri == "/robots.txt") { | ||||||
|  | 			return blobHandler(request, response, null, request.uri); | ||||||
|  | 		} else if ((match = /^\/.well-known\/(.*)/.exec(request.uri)) && request.uri.indexOf("..") == -1) { | ||||||
|  | 			var data = File.readFile("data/global/.well-known/" + match[1]); | ||||||
|  | 			if (data) { | ||||||
|  | 				response.writeHead(200, {"Content-Type": "text/plain", "Content-Length": data.length}); | ||||||
|  | 				response.end(data); | ||||||
|  | 			} else { | ||||||
|  | 				response.writeHead(404, {"Content-Type": "text/plain", "Content-Length": "File not found".length}); | ||||||
|  | 				response.end("File not found"); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			var data = "File not found."; | ||||||
|  | 			response.writeHead(404, {"Content-Type": "text/plain; charset=utf-8", "Content-Length": data.length.toString()}); | ||||||
|  | 			return response.end(data); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | 	httpd.registerSocketHandler("/app/socket", app.socket); | ||||||
|  | }).catch(function(error) { | ||||||
|  | 	print('Failed to load settings.'); | ||||||
| }); | }); | ||||||
| httpd.registerSocketHandler("/app/socket", app.socket); |  | ||||||
|   | |||||||
							
								
								
									
										101
									
								
								src/file.c
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								src/file.c
									
									
									
									
									
								
							| @@ -45,41 +45,84 @@ void tf_file_init(JSContext* context) { | |||||||
| 	JS_FreeValue(context, global); | 	JS_FreeValue(context, global); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void _free_array_buffer_data(JSRuntime* runtime, void* opaque, void* ptr) { | static const int k_file_read_max = 4 * 1024 * 1024; | ||||||
| 	free(ptr); |  | ||||||
|  | static void _file_read_close_callback(uv_fs_t* req) | ||||||
|  | { | ||||||
|  | 	uv_fs_req_cleanup(req); | ||||||
|  | 	free(req); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void _file_read_read_callback(uv_fs_t* req) | ||||||
|  | { | ||||||
|  | 	uv_fs_req_cleanup(req); | ||||||
|  | 	tf_task_t* task = req->loop->data; | ||||||
|  | 	JSContext* context = tf_task_get_context(task); | ||||||
|  | 	promiseid_t promise = (promiseid_t)(intptr_t)req->data; | ||||||
|  | 	if (req->result >= 0) | ||||||
|  | 	{ | ||||||
|  | 		JSValue arrayBuffer = JS_NewArrayBufferCopy(context, (uint8_t*)(req + 1), req->result); | ||||||
|  | 		JSValue global = JS_GetGlobalObject(context); | ||||||
|  | 		JSValue constructor = JS_GetPropertyStr(context, global, "Uint8Array"); | ||||||
|  | 		JSValue typedArray = JS_CallConstructor(context, constructor, 1, &arrayBuffer); | ||||||
|  | 		JS_FreeValue(context, constructor); | ||||||
|  | 		JS_FreeValue(context, global); | ||||||
|  | 		JS_FreeValue(context, arrayBuffer); | ||||||
|  | 		tf_task_resolve_promise(task, promise, typedArray); | ||||||
|  | 		JS_FreeValue(context, typedArray); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, uv_strerror(req->result))); | ||||||
|  | 	} | ||||||
|  | 	int result = uv_fs_close(req->loop, req, req->file, _file_read_close_callback); | ||||||
|  | 	if (result < 0) | ||||||
|  | 	{ | ||||||
|  | 		free(req); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void _file_read_open_callback(uv_fs_t* req) | ||||||
|  | { | ||||||
|  | 	uv_fs_req_cleanup(req); | ||||||
|  | 	tf_task_t* task = req->loop->data; | ||||||
|  | 	JSContext* context = tf_task_get_context(task); | ||||||
|  | 	promiseid_t promise = (promiseid_t)(intptr_t)req->data; | ||||||
|  | 	if (req->result >= 0) | ||||||
|  | 	{ | ||||||
|  | 		uv_buf_t buf = { .base = (char*)(req + 1), .len = k_file_read_max }; | ||||||
|  | 		uv_file file = req->result; | ||||||
|  | 		int result = uv_fs_read(req->loop, req, file, &buf, 1, 0, _file_read_read_callback); | ||||||
|  | 		if (result < 0) | ||||||
|  | 		{ | ||||||
|  | 			tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, uv_strerror(result))); | ||||||
|  | 			result = uv_fs_close(req->loop, req, file, _file_read_close_callback); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, uv_strerror(req->result))); | ||||||
|  | 		free(req); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { | static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { | ||||||
|  | 	void* task = JS_GetContextOpaque(context); | ||||||
| 	const char* file_name = JS_ToCString(context, argv[0]); | 	const char* file_name = JS_ToCString(context, argv[0]); | ||||||
| 	FILE* file = fopen(file_name, "rb"); |  | ||||||
| 	JS_FreeCString(context, file_name); |  | ||||||
| 	if (!file) { |  | ||||||
| 		return JS_NULL; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	long size = 0; | 	promiseid_t promise = tf_task_allocate_promise(task); | ||||||
| 	if (fseek(file, 0, SEEK_END) == 0) { | 	uv_fs_t* req = malloc(sizeof(uv_fs_t) + k_file_read_max); | ||||||
| 		size = ftell(file); | 	*req = (uv_fs_t) | ||||||
|  | 	{ | ||||||
|  | 		.data = (void*)(intptr_t)promise, | ||||||
|  | 	}; | ||||||
|  | 	int result = uv_fs_open(tf_task_get_loop(task), req, file_name, UV_FS_O_RDONLY, 0, _file_read_open_callback); | ||||||
|  | 	if (result < 0) | ||||||
|  | 	{ | ||||||
|  | 		tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, uv_strerror(result))); | ||||||
| 	} | 	} | ||||||
| 	if (size >= 0 && | 	JS_FreeCString(context, file_name); | ||||||
| 		size < 4 * 1024 * 1024 && | 	return tf_task_get_promise(task, promise); | ||||||
| 		fseek(file, 0, SEEK_SET) == 0) { |  | ||||||
| 		uint8_t* data = malloc(size); |  | ||||||
| 		if (data && |  | ||||||
| 			fread(data, 1, size, file) == (size_t)size) { |  | ||||||
| 			JSValue arrayBuffer = JS_NewArrayBuffer(context, data, size, _free_array_buffer_data, NULL, false); |  | ||||||
| 			JSValue global = JS_GetGlobalObject(context); |  | ||||||
| 			JSValue constructor = JS_GetPropertyStr(context, global, "Uint8Array"); |  | ||||||
| 			JSValue typedArray = JS_CallConstructor(context, constructor, 1, &arrayBuffer); |  | ||||||
| 			JS_FreeValue(context, constructor); |  | ||||||
| 			JS_FreeValue(context, global); |  | ||||||
| 			JS_FreeValue(context, arrayBuffer); |  | ||||||
| 			return typedArray; |  | ||||||
| 		} else if (data) { |  | ||||||
| 			free(data); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return JS_NULL; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { | static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { | ||||||
|   | |||||||
| @@ -1142,6 +1142,7 @@ tf_task_t* tf_task_create() { | |||||||
| 	tf_task_t* task = malloc(sizeof(tf_task_t)); | 	tf_task_t* task = malloc(sizeof(tf_task_t)); | ||||||
| 	*task = (tf_task_t) { 0 }; | 	*task = (tf_task_t) { 0 }; | ||||||
| 	task->_loop = uv_loop_new(); | 	task->_loop = uv_loop_new(); | ||||||
|  | 	task->_loop->data = task; | ||||||
| 	++_count; | 	++_count; | ||||||
| 	task->_runtime = JS_NewRuntime(); | 	task->_runtime = JS_NewRuntime(); | ||||||
| 	task->_context = JS_NewContext(task->_runtime); | 	task->_context = JS_NewContext(task->_runtime); | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								src/tests.c
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								src/tests.c
									
									
									
									
									
								
							| @@ -480,6 +480,36 @@ static void _test_socket(const tf_test_options_t* options) | |||||||
| 	unlink("out/test.js"); | 	unlink("out/test.js"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void _test_file(const tf_test_options_t* options) | ||||||
|  | { | ||||||
|  | 	FILE* file = fopen("out/test.js", "w"); | ||||||
|  | 	fprintf(file, | ||||||
|  | 		"'use strict';\n" | ||||||
|  | 		"File.readFile('out/test.js').then(function(data) {\n" | ||||||
|  | 		"	print('READ', utf8Decode(data));\n" | ||||||
|  | 		"}).catch(function(error) {\n" | ||||||
|  | 		"	print('ERROR', error);\n" | ||||||
|  | 		"	exit(1);\n" | ||||||
|  | 		"});\n" | ||||||
|  | 		"File.readFile('out/missing.txt').then(function(data) {\n" | ||||||
|  | 		"	print('READ', utf8Decode(data));\n" | ||||||
|  | 		"	exit(1);\n" | ||||||
|  | 		"}).catch(function(error) {\n" | ||||||
|  | 		"	print('expected error', error);\n" | ||||||
|  | 		"});\n"); | ||||||
|  | 	fclose(file); | ||||||
|  |  | ||||||
|  | 	char command[256]; | ||||||
|  | 	snprintf(command, sizeof(command), "%s run --ssb-port=0 -s out/test.js", options->exe_path); | ||||||
|  | 	printf("%s\n", command); | ||||||
|  | 	int result = system(command); | ||||||
|  | 	printf("returned %d\n", WEXITSTATUS(result)); | ||||||
|  | 	assert(WIFEXITED(result)); | ||||||
|  | 	assert(WEXITSTATUS(result) == 0); | ||||||
|  |  | ||||||
|  | 	unlink("out/test.js"); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void _tf_test_run(const tf_test_options_t* options, const char* name, void (*test)(const tf_test_options_t* options)) | static void _tf_test_run(const tf_test_options_t* options, const char* name, void (*test)(const tf_test_options_t* options)) | ||||||
| { | { | ||||||
| 	bool specified = false; | 	bool specified = false; | ||||||
| @@ -521,5 +551,6 @@ void tf_tests(const tf_test_options_t* options) | |||||||
| 	_tf_test_run(options, "icu", _test_icu); | 	_tf_test_run(options, "icu", _test_icu); | ||||||
| 	_tf_test_run(options, "uint8array", _test_uint8array); | 	_tf_test_run(options, "uint8array", _test_uint8array); | ||||||
| 	_tf_test_run(options, "socket", _test_socket); | 	_tf_test_run(options, "socket", _test_socket); | ||||||
|  | 	_tf_test_run(options, "file", _test_file); | ||||||
| 	printf("Tests completed.\n"); | 	printf("Tests completed.\n"); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user