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.end();
 | 
			
		||||
		} else {
 | 
			
		||||
			var html = new TextDecoder("UTF-8").decode(File.readFile("core/auth.html"));
 | 
			
		||||
			var contents = "";
 | 
			
		||||
			File.readFile("core/auth.html").then(function(data) {
 | 
			
		||||
				var html = new TextDecoder("UTF-8").decode(data);
 | 
			
		||||
				var contents = "";
 | 
			
		||||
 | 
			
		||||
			if (entry) {
 | 
			
		||||
				if (sessionIsNew) {
 | 
			
		||||
					contents += '<div>Welcome back, ' + entry.name + '.</div>\n';
 | 
			
		||||
				if (entry) {
 | 
			
		||||
					if (sessionIsNew) {
 | 
			
		||||
						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 {
 | 
			
		||||
					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';
 | 
			
		||||
			} else {
 | 
			
		||||
				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>';
 | 
			
		||||
			}
 | 
			
		||||
			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);
 | 
			
		||||
				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);
 | 
			
		||||
			}).catch(function(error) {
 | 
			
		||||
				response.writeHead(404, {"Content-Type": "text/plain; charset=utf-8", "Connection": "close"});
 | 
			
		||||
				response.end("404 File not found");
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	} else if (request.uri == "/login/logout") {
 | 
			
		||||
		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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function readFileUtf8(fileName) {
 | 
			
		||||
	let data = File.readFile(fileName);
 | 
			
		||||
async function readFileUtf8(fileName) {
 | 
			
		||||
	let data = await File.readFile(fileName);
 | 
			
		||||
	data = utf8Decode(data);
 | 
			
		||||
	return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
	var process = gProcesses[key];
 | 
			
		||||
	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 = [
 | 
			
		||||
	{uri: '/', path: 'index.html', type: 'text/html; 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) {
 | 
			
		||||
	for (var i in kStaticFiles) {
 | 
			
		||||
		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.end(data);
 | 
			
		||||
			return;
 | 
			
		||||
@@ -403,7 +360,7 @@ async function blobHandler(request, response, blobId, uri) {
 | 
			
		||||
		for (var i in kStaticFiles) {
 | 
			
		||||
			if (uri === kStaticFiles[i].uri) {
 | 
			
		||||
				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.end(data);
 | 
			
		||||
				break;
 | 
			
		||||
@@ -483,41 +440,56 @@ ssb.onConnectionsChanged = function() {
 | 
			
		||||
	broadcastEvent('onConnectionsChanged', []);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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]);
 | 
			
		||||
async function loadSettings() {
 | 
			
		||||
	try {
 | 
			
		||||
		var data = await readFileUtf8(kGlobalSettingsFile);
 | 
			
		||||
		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");
 | 
			
		||||
			gGlobalSettings = JSON.parse(data);
 | 
			
		||||
		}
 | 
			
		||||
	} 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);
 | 
			
		||||
	} catch (error) {
 | 
			
		||||
		print("Error loading settings from " + kGlobalSettingsFile + ": " + error);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _free_array_buffer_data(JSRuntime* runtime, void* opaque, void* ptr) {
 | 
			
		||||
	free(ptr);
 | 
			
		||||
static const int k_file_read_max = 4 * 1024 * 1024;
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
	void* task = JS_GetContextOpaque(context);
 | 
			
		||||
	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;
 | 
			
		||||
	if (fseek(file, 0, SEEK_END) == 0) {
 | 
			
		||||
		size = ftell(file);
 | 
			
		||||
	promiseid_t promise = tf_task_allocate_promise(task);
 | 
			
		||||
	uv_fs_t* req = malloc(sizeof(uv_fs_t) + k_file_read_max);
 | 
			
		||||
	*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 &&
 | 
			
		||||
		size < 4 * 1024 * 1024 &&
 | 
			
		||||
		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;
 | 
			
		||||
	JS_FreeCString(context, file_name);
 | 
			
		||||
	return tf_task_get_promise(task, promise);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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));
 | 
			
		||||
	*task = (tf_task_t) { 0 };
 | 
			
		||||
	task->_loop = uv_loop_new();
 | 
			
		||||
	task->_loop->data = task;
 | 
			
		||||
	++_count;
 | 
			
		||||
	task->_runtime = JS_NewRuntime();
 | 
			
		||||
	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");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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))
 | 
			
		||||
{
 | 
			
		||||
	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, "uint8array", _test_uint8array);
 | 
			
		||||
	_tf_test_run(options, "socket", _test_socket);
 | 
			
		||||
	_tf_test_run(options, "file", _test_file);
 | 
			
		||||
	printf("Tests completed.\n");
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user