forked from cory/tildefriends
		
	git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3783 ed5197a5-7fde-0310-b194-c3ffbd925b24
		
			
				
	
	
		
			191 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include "util.js.h"
 | 
						|
 | 
						|
#include "task.h"
 | 
						|
#include "trace.h"
 | 
						|
 | 
						|
#include "quickjs-libc.h"
 | 
						|
 | 
						|
#include <uv.h>
 | 
						|
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
static JSValue _util_utf8_decode(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
 | 
						|
{
 | 
						|
	JSValue result = JS_NULL;
 | 
						|
	size_t length;
 | 
						|
	if (JS_IsString(argv[0]))
 | 
						|
	{
 | 
						|
		result = JS_DupValue(context, argv[0]);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		uint8_t* array = tf_util_try_get_array_buffer(context, &length, argv[0]);
 | 
						|
		if (array)
 | 
						|
		{
 | 
						|
			result = JS_NewStringLen(context, (const char*)array, length);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			size_t offset;
 | 
						|
			size_t element_size;
 | 
						|
			JSValue buffer = tf_util_try_get_typed_array_buffer(context, argv[0], &offset, &length, &element_size);
 | 
						|
			size_t size;
 | 
						|
			if (!JS_IsException(buffer))
 | 
						|
			{
 | 
						|
				array = tf_util_try_get_array_buffer(context, &size, buffer);
 | 
						|
				if (array)
 | 
						|
				{
 | 
						|
					result = JS_NewStringLen(context, (const char*)array, size);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			JS_FreeValue(context, buffer);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
JSValue tf_util_utf8_decode(JSContext* context, JSValue value)
 | 
						|
{
 | 
						|
	return _util_utf8_decode(context, JS_NULL, 1, &value);
 | 
						|
}
 | 
						|
 | 
						|
uint8_t* tf_util_try_get_array_buffer(JSContext* context, size_t* psize, JSValueConst obj)
 | 
						|
{
 | 
						|
	uint8_t* result = JS_GetArrayBuffer(context, psize, obj);
 | 
						|
	JS_FreeValue(context, JS_GetException(context));
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
JSValue tf_util_try_get_typed_array_buffer(JSContext* context, JSValueConst obj, size_t* pbyte_offset, size_t* pbyte_length, size_t* pbytes_per_element)
 | 
						|
{
 | 
						|
	JSValue result = JS_GetTypedArrayBuffer(context, obj, pbyte_offset, pbyte_length, pbytes_per_element);
 | 
						|
	JS_FreeValue(context, JS_GetException(context));
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
JSValue _util_print(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
 | 
						|
{
 | 
						|
	tf_task_t* task = JS_GetContextOpaque(context);
 | 
						|
	if (task)
 | 
						|
	{
 | 
						|
		printf("Task[%p:%s]>", task, tf_task_get_name(task));
 | 
						|
	}
 | 
						|
	for (int i = 0; i < argc; ++i)
 | 
						|
	{
 | 
						|
		if (JS_IsNull(argv[i]))
 | 
						|
		{
 | 
						|
			printf(" null");
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			const char* value = JS_ToCString(context, argv[i]);
 | 
						|
			printf(" %s", value);
 | 
						|
			JS_FreeCString(context, value);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	printf("\n");
 | 
						|
	return JS_NULL;
 | 
						|
}
 | 
						|
 | 
						|
bool tf_util_report_error(JSContext* context, JSValue value)
 | 
						|
{
 | 
						|
	bool is_error = false;
 | 
						|
	if (JS_IsError(context, value))
 | 
						|
	{
 | 
						|
		const char* string = JS_ToCString(context, value);
 | 
						|
		printf("ERROR: %s\n", string);
 | 
						|
		JS_FreeCString(context, string);
 | 
						|
 | 
						|
		JSValue stack = JS_GetPropertyStr(context, value, "stack");
 | 
						|
		if (!JS_IsUndefined(stack))
 | 
						|
		{
 | 
						|
			const char* stack_str = JS_ToCString(context, stack);
 | 
						|
			printf("%s\n", stack_str);
 | 
						|
			JS_FreeCString(context, stack_str);
 | 
						|
		}
 | 
						|
		JS_FreeValue(context, stack);
 | 
						|
 | 
						|
		tf_task_t* task = tf_task_get(context);
 | 
						|
		if (task)
 | 
						|
		{
 | 
						|
			tf_task_send_error_to_parent(task, value);
 | 
						|
		}
 | 
						|
		is_error = true;
 | 
						|
	}
 | 
						|
	else if (JS_IsException(value))
 | 
						|
	{
 | 
						|
		js_std_dump_error(context);
 | 
						|
		JSValue exception = JS_GetException(context);
 | 
						|
		const char* string = JS_ToCString(context, exception);
 | 
						|
		printf("Exception: %s\n", string);
 | 
						|
		JS_FreeCString(context, string);
 | 
						|
		tf_task_t* task = tf_task_get(context);
 | 
						|
		if (task)
 | 
						|
		{
 | 
						|
			tf_task_send_error_to_parent(task, exception);
 | 
						|
		}
 | 
						|
		JS_FreeValue(context, exception);
 | 
						|
		is_error = true;
 | 
						|
	}
 | 
						|
	return is_error;
 | 
						|
}
 | 
						|
 | 
						|
typedef struct _timeout_t {
 | 
						|
	tf_task_t* _task;
 | 
						|
	JSValue _callback;
 | 
						|
} timeout_t;
 | 
						|
 | 
						|
static void _handle_closed(uv_handle_t* handle)
 | 
						|
{
 | 
						|
	free(handle);
 | 
						|
}
 | 
						|
 | 
						|
static void _util_timeoutCallback(uv_timer_t* handle)
 | 
						|
{
 | 
						|
	timeout_t* timeout = handle->data;
 | 
						|
	tf_trace_begin(tf_task_get_trace(timeout->_task), "_util_timeoutCallback");
 | 
						|
	JSContext* context = tf_task_get_context(timeout->_task);
 | 
						|
	JSValue result = JS_Call(
 | 
						|
		context,
 | 
						|
		timeout->_callback,
 | 
						|
		JS_NULL,
 | 
						|
		0,
 | 
						|
		NULL);
 | 
						|
	tf_util_report_error(context, result);
 | 
						|
	JS_FreeValue(context, result);
 | 
						|
	tf_trace_end(tf_task_get_trace(timeout->_task));
 | 
						|
	free(timeout);
 | 
						|
	uv_close((uv_handle_t*)handle, _handle_closed);
 | 
						|
}
 | 
						|
 | 
						|
static JSValue _util_setTimeout(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
 | 
						|
{
 | 
						|
	tf_task_t* task = JS_GetContextOpaque(context);
 | 
						|
 | 
						|
	timeout_t* timeout = malloc(sizeof(timeout_t));
 | 
						|
	*timeout = (timeout_t)
 | 
						|
	{
 | 
						|
		._task = task,
 | 
						|
		._callback = JS_DupValue(context, argv[0]),
 | 
						|
	};
 | 
						|
 | 
						|
	uv_timer_t* timer = malloc(sizeof(uv_timer_t));
 | 
						|
	memset(timer, 0, sizeof(uv_timer_t));
 | 
						|
	uv_timer_init(tf_task_get_loop(task), timer);
 | 
						|
	timer->data = timeout;
 | 
						|
 | 
						|
	int64_t duration;
 | 
						|
	JS_ToInt64(context, &duration, argv[1]);
 | 
						|
	uv_timer_start(timer, _util_timeoutCallback, duration, 0);
 | 
						|
	return JS_NULL;
 | 
						|
}
 | 
						|
 | 
						|
void tf_util_register(JSContext* context)
 | 
						|
{
 | 
						|
	JSValue global = JS_GetGlobalObject(context);
 | 
						|
	JS_SetPropertyStr(context, global, "utf8Decode", JS_NewCFunction(context, _util_utf8_decode, "utf8Decode", 1));
 | 
						|
	JS_SetPropertyStr(context, global, "print", JS_NewCFunction(context, _util_print, "print", 1));
 | 
						|
	JS_SetPropertyStr(context, global, "setTimeout", JS_NewCFunction(context, _util_setTimeout, "setTimeout", 2));
 | 
						|
	JS_FreeValue(context, global);
 | 
						|
}
 |