433 lines
11 KiB
C
433 lines
11 KiB
C
#include "qjs_os.h"
|
|
#include "jsffi.h"
|
|
#include "qjs_macros.h"
|
|
#include "qjs_wota.h"
|
|
#include "prosperon.h"
|
|
#include "transform.h"
|
|
|
|
#include <SDL3/SDL.h>
|
|
#include <sys/time.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
#include <signal.h>
|
|
#include <time.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#include <sys/utsname.h>
|
|
#ifdef __linux__
|
|
#include <sys/sysinfo.h>
|
|
#endif
|
|
#endif
|
|
|
|
// External variables
|
|
extern int trace;
|
|
extern prosperon_rt *io_actor;
|
|
|
|
// External function declarations
|
|
extern JSClassID js_transform_id;
|
|
JSValue transform2js(JSContext *js, transform *t);
|
|
transform *js2transform(JSContext *js, JSValue v);
|
|
|
|
// OS FUNCTIONS
|
|
|
|
JSC_SCALL(os_openurl,
|
|
if (SDL_OpenURL(str) < 0)
|
|
ret = JS_ThrowInternalError(js, "%s", SDL_GetError());
|
|
)
|
|
|
|
JSC_SCALL(os_env,
|
|
char *env = getenv(str);
|
|
if (env) ret = JS_NewString(js,env);
|
|
)
|
|
|
|
JSC_CCALL(os_exit, exit(js2number(js,argv[0]));)
|
|
JSC_CCALL(os_now, return number2js(js, (double)SDL_GetTicksNS()/1000000000.0))
|
|
|
|
|
|
JSC_SCALL(os_system, ret = number2js(js,system(str)); )
|
|
|
|
JSC_SCALL(os_kill,
|
|
pid_t pid = js2number(js,argv[0]);
|
|
if (kill(pid, SIGTERM) < 0)
|
|
ret = JS_ThrowReferenceError(js,"could not kill process");
|
|
)
|
|
|
|
JSC_CCALL(os_sleep,
|
|
double secs = js2number(js,argv[0]);
|
|
int ms = secs*1000;
|
|
SDL_Delay(ms);
|
|
)
|
|
|
|
JSC_CCALL(os_battery_pct,
|
|
int pct;
|
|
SDL_PowerState state = SDL_GetPowerInfo(&pct, NULL);
|
|
return number2js(js,pct);
|
|
)
|
|
|
|
JSC_CCALL(os_battery_voltage,
|
|
return number2js(js,0);
|
|
)
|
|
|
|
JSC_CCALL(os_battery_seconds,
|
|
int secs;
|
|
SDL_PowerState state = SDL_GetPowerInfo(NULL, &secs);
|
|
return number2js(js, secs);
|
|
)
|
|
|
|
JSC_CCALL(os_power_state,
|
|
int pct, secs;
|
|
SDL_PowerState state = SDL_GetPowerInfo(&pct, &secs);
|
|
const char *statestr = "unknown";
|
|
switch(state) {
|
|
case SDL_POWERSTATE_ON_BATTERY: statestr = "battery"; break;
|
|
case SDL_POWERSTATE_NO_BATTERY: statestr = "no battery"; break;
|
|
case SDL_POWERSTATE_CHARGING: statestr = "charging"; break;
|
|
case SDL_POWERSTATE_CHARGED: statestr = "charged"; break;
|
|
}
|
|
ret = JS_NewObject(js);
|
|
JS_SetPropertyStr(js,ret,"state",JS_NewString(js,statestr));
|
|
JS_SetPropertyStr(js,ret,"percent",number2js(js,pct));
|
|
JS_SetPropertyStr(js,ret,"seconds",number2js(js,secs));
|
|
)
|
|
|
|
JSC_CCALL(os_totalmem, return number2js(js, SDL_GetSystemRAM()))
|
|
JSC_CCALL(os_platform, return JS_NewString(js,SDL_GetPlatform()))
|
|
|
|
JSC_CCALL(os_hostname,
|
|
#ifdef _WIN32
|
|
TCHAR buffer[256] = TEXT("");
|
|
DWORD size = sizeof(buffer) / sizeof(TCHAR);
|
|
GetComputerName(buffer, &size);
|
|
return JS_NewString(js, buffer);
|
|
#else
|
|
struct utsname buffer;
|
|
if (uname(&buffer) != 0) return JS_ThrowReferenceError(js,"Could not get hostname.");
|
|
return JS_NewString(js, buffer.nodename);
|
|
#endif
|
|
)
|
|
|
|
JSC_CCALL(os_make_transform,
|
|
transform *t = make_transform();
|
|
ret = transform2js(js,t);
|
|
// t->self = JS_DupValue(js,ret);
|
|
t->self = ret;
|
|
)
|
|
|
|
JSC_CCALL(os_clean_transforms,
|
|
clean_all(js);
|
|
)
|
|
|
|
JSC_CCALL(os_arch,
|
|
#if defined(__x86_64__) || defined(_M_X64)
|
|
return JS_NewString(js,"x64");
|
|
#elif defined(__aarch64__) || defined(_M_ARM64)
|
|
return JS_NewString(js,"arm64");
|
|
#elif defined(__arm__) || defined(_M_ARM)
|
|
return JS_NewString(js,"arm");
|
|
#elif defined(__i386__) || defined(_M_IX86)
|
|
return JS_NewString(js,"ia32");
|
|
#elif defined(__loongarch__) || defined(__loongarch32) || defined(__loongarch64)
|
|
return JS_NewString(js,"loong64");
|
|
#elif defined(__mips__) || defined(__mips) || defined(_M_MIPS)
|
|
// You might want to distinguish mips vs mipsel
|
|
return JS_NewString(js,"mips");
|
|
#elif defined(__ppc64__) || defined(__powerpc64__) || defined(_M_PPC)
|
|
// You might want to distinguish ppc vs ppc64, big-endian vs little-endian
|
|
return JS_NewString(js,"ppc64");
|
|
#elif defined(__riscv) && __riscv_xlen == 64
|
|
return JS_NewString(js,"riscv64");
|
|
#elif defined(__s390x__)
|
|
return JS_NewString(js,"s390x");
|
|
#else
|
|
return JS_NewString(js,"unknown");
|
|
#endif
|
|
)
|
|
|
|
JSC_CCALL(os_freemem,
|
|
#ifdef _WIN32
|
|
MEMORYSTATUSEX statex;
|
|
statex.dwLength = sizeof(statex);
|
|
if (!GlobalMemoryStatusEx(&statex)) return JS_ThrowInternalError(js,"GlobalMemoryStatusEx failed");
|
|
return JS_NewInt64(js,(int64_t)statex.ullAvailPhys);
|
|
#elif defined(__linux__)
|
|
struct sysinfo info;
|
|
if (sysinfo(&info) == 0)
|
|
return JS_NewInt64(js,(int64_t)info.freeram * info.mem_unit);
|
|
return JS_NewInt64(js,0);
|
|
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
|
// A very rough fallback using the same sysconf approach
|
|
// (macOS or *BSD typically need specialized APIs to get free mem accurately)
|
|
// This is often only "unused" pages, ignoring caches, etc.
|
|
long pages = sysconf(_SC_AVPHYS_PAGES);
|
|
long page_size = sysconf(_SC_PAGE_SIZE);
|
|
if (pages < 0 || page_size < 0) return JS_NewInt64(js,0);
|
|
return JS_NewInt64(js,(int64_t)pages * (int64_t)page_size);
|
|
#else
|
|
// Fallback: unknown
|
|
return JS_NewInt64(js,0);
|
|
#endif
|
|
)
|
|
|
|
JSC_CCALL(os_version,
|
|
#ifdef _WIN32
|
|
typedef LONG (WINAPI *RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
|
|
HMODULE h = GetModuleHandleA("ntdll.dll");
|
|
if (h) {
|
|
RtlGetVersionPtr fx = (RtlGetVersionPtr)GetProcAddress(h, "RtlGetVersion");
|
|
if (fx) {
|
|
RTL_OSVERSIONINFOW ver;
|
|
memset(&ver, 0, sizeof(ver));
|
|
ver.dwOSVersionInfoSize = sizeof(ver);
|
|
if (!fx(&ver)) {
|
|
char buf[128];
|
|
sprintf(buf, "%u.%u.%u",
|
|
(unsigned)ver.dwMajorVersion,
|
|
(unsigned)ver.dwMinorVersion,
|
|
(unsigned)ver.dwBuildNumber
|
|
);
|
|
return JS_NewString(js, buf);
|
|
}
|
|
}
|
|
}
|
|
OSVERSIONINFOW wver;
|
|
memset(&wver, 0, sizeof(wver));
|
|
wver.dwOSVersionInfoSize = sizeof(wver);
|
|
if (GetVersionExW(&wver)) {
|
|
char buf[128];
|
|
sprintf(buf, "%u.%u.%u",
|
|
(unsigned)wver.dwMajorVersion,
|
|
(unsigned)wver.dwMinorVersion,
|
|
(unsigned)wver.dwBuildNumber
|
|
);
|
|
return JS_NewString(js, buf);
|
|
}
|
|
return JS_NewString(js, "Windows_Unknown");
|
|
#else
|
|
struct utsname info;
|
|
if (!uname(&info)) return JS_NewString(js, info.release);
|
|
return JS_NewString(js, "");
|
|
#endif
|
|
)
|
|
|
|
JSValue js_os_get_trace(JSContext *js, JSValue self)
|
|
{
|
|
return JS_NewBool(js, trace);
|
|
}
|
|
|
|
JSValue js_os_set_trace(JSContext *js, JSValue self, JSValue value)
|
|
{
|
|
trace = JS_ToBool(js, value);
|
|
return JS_UNDEFINED;
|
|
}
|
|
|
|
JSC_CCALL(os_on,
|
|
prosperon_rt *rt = JS_GetContextOpaque(js);
|
|
JS_FreeValue(js, rt->on_exception);
|
|
rt->on_exception = JS_DupValue(js,argv[1]);
|
|
)
|
|
|
|
#define JSOBJ_ADD_FIELD(OBJ, STRUCT, FIELD, TYPE) \
|
|
JS_SetPropertyStr(js, OBJ, #FIELD, TYPE##2js(js,STRUCT.FIELD));\
|
|
|
|
#define JSJMEMRET(FIELD) JSOBJ_ADD_FIELD(ret, jsmem, FIELD, number)
|
|
|
|
JSC_CCALL(os_mallinfo,
|
|
ret = JS_UNDEFINED;
|
|
/*struct mallinfo jsmem = mallinfo();
|
|
ret = JS_NewObject(js);
|
|
JSJMEMRET(arena);
|
|
JSJMEMRET(ordblks);
|
|
JSJMEMRET(smblks);
|
|
JSJMEMRET(hblks);
|
|
JSJMEMRET(hblkhd);
|
|
JSJMEMRET(usmblks);
|
|
JSJMEMRET(fsmblks);
|
|
JSJMEMRET(uordblks);
|
|
JSJMEMRET(fordblks);
|
|
JSJMEMRET(keepcost);*/
|
|
)
|
|
|
|
JSC_CCALL(os_rusage,
|
|
ret = JS_NewObject(js);
|
|
|
|
#ifndef _WIN32
|
|
struct rusage jsmem;
|
|
getrusage(RUSAGE_SELF, &jsmem);
|
|
JSJMEMRET(ru_maxrss);
|
|
JSJMEMRET(ru_ixrss);
|
|
JSJMEMRET(ru_idrss);
|
|
JSJMEMRET(ru_isrss);
|
|
JSJMEMRET(ru_minflt);
|
|
JSJMEMRET(ru_majflt);
|
|
JSJMEMRET(ru_nswap);
|
|
JSJMEMRET(ru_inblock);
|
|
JSJMEMRET(ru_oublock);
|
|
JSJMEMRET(ru_msgsnd);
|
|
JSJMEMRET(ru_msgrcv);
|
|
JSJMEMRET(ru_nsignals);
|
|
JSJMEMRET(ru_nvcsw);
|
|
JSJMEMRET(ru_nivcsw);
|
|
#endif
|
|
|
|
return ret;
|
|
)
|
|
|
|
JSC_CCALL(os_createprocess,
|
|
int ac = JS_ArrayLength(js,argv[0]);
|
|
const char *args[ac+1];
|
|
for (int i = 0; i < ac; i++) {
|
|
JSValue astr = JS_GetPropertyUint32(js,argv[0],i);
|
|
args[i] = JS_ToCString(js,astr);
|
|
JS_FreeValue(js,astr);
|
|
}
|
|
|
|
args[ac] = NULL;
|
|
|
|
SDL_Process *actor = SDL_CreateProcess(args, 0);
|
|
|
|
for (int i = 0; i < ac; i++)
|
|
JS_FreeCString(js,args[i]);
|
|
|
|
if (!actor)
|
|
return JS_ThrowReferenceError(js, "Unable to create process: %s\n", SDL_GetError());
|
|
)
|
|
|
|
JSC_CCALL(os_createactor,
|
|
int margc = JS_ArrayLength(js, argv[0]);
|
|
|
|
char **margv = malloc(margc*sizeof(char*));
|
|
|
|
for (int i = 0; i < margc; i++) {
|
|
JSValue val = JS_GetPropertyUint32(js, argv[0], i);
|
|
const char *cstr = JS_ToCString(js,val);
|
|
margv[i] = strdup(cstr);
|
|
JS_FreeCString(js,cstr);
|
|
JS_FreeValue(js,val);
|
|
}
|
|
|
|
create_actor(margc, margv);
|
|
)
|
|
|
|
JSC_CCALL(os_mailbox_push,
|
|
if (argc < 2) return JS_ThrowInternalError(js, "Need an actor and a message");
|
|
if (!JS_IsObject(argv[1])) return JS_ThrowInternalError(js, "Object to push must be an object.");
|
|
|
|
const char *id = JS_ToCString(js, argv[0]);
|
|
int exist = actor_exists(id);
|
|
JS_FreeCString(js,id);
|
|
if (!exist)
|
|
return JS_ThrowInternalError(js, "No mailbox found for given ID");
|
|
|
|
void *data = value2wota(js, argv[1], JS_UNDEFINED);
|
|
|
|
const char *err = send_message(id, data);
|
|
if (err) {
|
|
free(data);
|
|
return JS_ThrowInternalError(js, "Could not send message: %s", err);
|
|
}
|
|
)
|
|
|
|
JSC_CCALL(os_register_actor,
|
|
prosperon_rt *rt = JS_GetContextOpaque(js);
|
|
const char *id = JS_ToCString(js, argv[0]);
|
|
const char *err = register_actor(id, rt, JS_ToBool(js, argv[2]));
|
|
if (err) return JS_ThrowInternalError(js, "Could not register actor: %s", err);
|
|
rt->message_handle = JS_DupValue(js, argv[1]);
|
|
rt->context = js;
|
|
JS_FreeCString(js, id);
|
|
)
|
|
|
|
JSC_CCALL(os_mailbox_exist,
|
|
const char *id = JS_ToCString(js, argv[0]);
|
|
int exist = actor_exists(id);
|
|
JS_FreeCString(js, id);
|
|
|
|
return JS_NewBool(js, exist);
|
|
)
|
|
|
|
JSC_CCALL(os_unneeded,
|
|
prosperon_rt *actor = JS_GetContextOpaque(js);
|
|
SDL_LockMutex(actor->msg_mutex);
|
|
JS_FreeValue(js, actor->unneeded);
|
|
|
|
if (!JS_IsFunction(js, argv[0])) {
|
|
actor->unneeded = JS_UNDEFINED;
|
|
goto END;
|
|
}
|
|
|
|
actor->unneeded = JS_DupValue(js, argv[0]);
|
|
JS_ToFloat64(js, &actor->unneeded_secs, argv[1]);
|
|
|
|
END:
|
|
if (actor->ar) {
|
|
SDL_RemoveTimer(actor->ar);
|
|
actor->ar = 0;
|
|
}
|
|
set_actor_state(actor);
|
|
SDL_UnlockMutex(actor->msg_mutex);
|
|
)
|
|
|
|
JSC_CCALL(os_destroy,
|
|
prosperon_rt *rt = JS_GetContextOpaque(js);
|
|
rt->need_stop = 1;
|
|
)
|
|
|
|
static const JSCFunctionListEntry js_os_funcs[] = {
|
|
MIST_FUNC_DEF(os, make_transform, 0),
|
|
MIST_FUNC_DEF(os, clean_transforms, 0),
|
|
|
|
MIST_FUNC_DEF(os, platform, 0),
|
|
MIST_FUNC_DEF(os, arch, 0),
|
|
MIST_FUNC_DEF(os, totalmem, 0),
|
|
MIST_FUNC_DEF(os, freemem, 0),
|
|
MIST_FUNC_DEF(os, hostname, 0),
|
|
MIST_FUNC_DEF(os, version, 0),
|
|
JS_CGETSET_DEF("trace", js_os_get_trace, js_os_set_trace),
|
|
|
|
MIST_FUNC_DEF(os, kill, 1),
|
|
MIST_FUNC_DEF(os, exit, 1),
|
|
|
|
MIST_FUNC_DEF(os, now, 0),
|
|
|
|
MIST_FUNC_DEF(os, openurl, 1),
|
|
|
|
MIST_FUNC_DEF(os, sleep, 1),
|
|
MIST_FUNC_DEF(os, battery_pct, 0),
|
|
MIST_FUNC_DEF(os, battery_voltage, 0),
|
|
MIST_FUNC_DEF(os, battery_seconds, 0),
|
|
MIST_FUNC_DEF(os, power_state, 0),
|
|
|
|
MIST_FUNC_DEF(os, on, 2),
|
|
|
|
MIST_FUNC_DEF(os, rusage, 0),
|
|
MIST_FUNC_DEF(os, mallinfo, 0),
|
|
|
|
// dangerous ones that need disabled for shipping
|
|
MIST_FUNC_DEF(os, env, 1),
|
|
MIST_FUNC_DEF(os, system, 1),
|
|
MIST_FUNC_DEF(os, createprocess, 0),
|
|
MIST_FUNC_DEF(os, createactor, 1),
|
|
|
|
MIST_FUNC_DEF(os, mailbox_push, 2),
|
|
MIST_FUNC_DEF(os, mailbox_exist, 1),
|
|
MIST_FUNC_DEF(actor, delay, 2),
|
|
MIST_FUNC_DEF(actor, removetimer, 1),
|
|
MIST_FUNC_DEF(os, register_actor, 2),
|
|
MIST_FUNC_DEF(os, unneeded, 2),
|
|
MIST_FUNC_DEF(os, destroy, 0),
|
|
MIST_FUNC_DEF(os, ioactor, 0),
|
|
};
|
|
|
|
JSValue js_os_use(JSContext *js) {
|
|
JSValue mod = JS_NewObject(js);
|
|
JS_SetPropertyFunctionList(js,mod,js_os_funcs,countof(js_os_funcs));
|
|
return mod;
|
|
}
|