feat: add fswatch, sysinfo, and udp demo scripts plus reorder manual sidebar links
Add three new example scripts demonstrating the fswatch, sysinfo, and udp modules with file watching, system metrics, and UDP echo server/client patterns. Reorder the manual API sidebar navigation to list modules alphabetically, removing deprecated entries like websocket, tls, net, json, regex, jinja, os, signal, subprocess, sqlite, and timer while adding argparse, dataset, fswatch, and html.
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fswatch.h"
|
||||
#include "scheduler.h"
|
||||
#include "vm.h"
|
||||
#include "wren.h"
|
||||
#include "uv.h"
|
||||
|
||||
typedef struct {
|
||||
uv_fs_event_t handle;
|
||||
WrenHandle* fiber;
|
||||
WrenHandle* eventClass;
|
||||
char* path;
|
||||
int isActive;
|
||||
int isClosed;
|
||||
} FileWatcherData;
|
||||
|
||||
static WrenHandle* schedulerClass = NULL;
|
||||
static WrenHandle* resumeMethod = NULL;
|
||||
|
||||
static void ensureSchedulerMethods()
|
||||
{
|
||||
if (schedulerClass != NULL) return;
|
||||
|
||||
WrenVM* vm = getVM();
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenGetVariable(vm, "scheduler", "Scheduler", 0);
|
||||
schedulerClass = wrenGetSlotHandle(vm, 0);
|
||||
resumeMethod = wrenMakeCallHandle(vm, "resume_(_,_)");
|
||||
}
|
||||
|
||||
static void resumeFiberWithEvent(WrenHandle* fiber, WrenHandle* event)
|
||||
{
|
||||
WrenVM* vm = getVM();
|
||||
ensureSchedulerMethods();
|
||||
|
||||
wrenEnsureSlots(vm, 3);
|
||||
wrenSetSlotHandle(vm, 0, schedulerClass);
|
||||
wrenSetSlotHandle(vm, 1, fiber);
|
||||
wrenSetSlotHandle(vm, 2, event);
|
||||
|
||||
WrenInterpretResult result = wrenCall(vm, resumeMethod);
|
||||
if (result == WREN_RESULT_RUNTIME_ERROR) {
|
||||
uv_stop(getLoop());
|
||||
setExitCode(70);
|
||||
}
|
||||
}
|
||||
|
||||
static void closeCallback(uv_handle_t* handle)
|
||||
{
|
||||
}
|
||||
|
||||
void fswatchAllocate(WrenVM* vm)
|
||||
{
|
||||
FileWatcherData* data = (FileWatcherData*)wrenSetSlotNewForeign(vm, 0, 0, sizeof(FileWatcherData));
|
||||
memset(data, 0, sizeof(FileWatcherData));
|
||||
|
||||
const char* path = wrenGetSlotString(vm, 1);
|
||||
data->path = strdup(path);
|
||||
data->isActive = 0;
|
||||
data->isClosed = 0;
|
||||
data->fiber = NULL;
|
||||
data->eventClass = NULL;
|
||||
|
||||
uv_fs_event_init(getLoop(), &data->handle);
|
||||
data->handle.data = data;
|
||||
}
|
||||
|
||||
void fswatchFinalize(void* data)
|
||||
{
|
||||
FileWatcherData* watcher = (FileWatcherData*)data;
|
||||
|
||||
if (watcher->path != NULL) {
|
||||
free(watcher->path);
|
||||
watcher->path = NULL;
|
||||
}
|
||||
|
||||
if (!watcher->isClosed && watcher->isActive) {
|
||||
uv_fs_event_stop(&watcher->handle);
|
||||
watcher->isClosed = 1;
|
||||
}
|
||||
|
||||
watcher->isActive = 0;
|
||||
}
|
||||
|
||||
static void eventCallback(uv_fs_event_t* handle, const char* filename, int events, int status)
|
||||
{
|
||||
FileWatcherData* watcher = (FileWatcherData*)handle->data;
|
||||
|
||||
if (!watcher->isActive || watcher->fiber == NULL) return;
|
||||
|
||||
if (status < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
WrenVM* vm = getVM();
|
||||
|
||||
if (watcher->eventClass == NULL) {
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenGetVariable(vm, "fswatch", "FsEvent", 0);
|
||||
watcher->eventClass = wrenGetSlotHandle(vm, 0);
|
||||
}
|
||||
|
||||
wrenEnsureSlots(vm, 4);
|
||||
wrenSetSlotHandle(vm, 0, watcher->eventClass);
|
||||
wrenSetSlotString(vm, 1, filename != NULL ? filename : "");
|
||||
wrenSetSlotDouble(vm, 2, (double)events);
|
||||
|
||||
WrenHandle* constructor = wrenMakeCallHandle(vm, "new(_,_)");
|
||||
WrenInterpretResult result = wrenCall(vm, constructor);
|
||||
wrenReleaseHandle(vm, constructor);
|
||||
|
||||
if (result != WREN_RESULT_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
WrenHandle* event = wrenGetSlotHandle(vm, 0);
|
||||
resumeFiberWithEvent(watcher->fiber, event);
|
||||
wrenReleaseHandle(vm, event);
|
||||
}
|
||||
|
||||
void fswatchStart(WrenVM* vm)
|
||||
{
|
||||
FileWatcherData* watcher = (FileWatcherData*)wrenGetSlotForeign(vm, 0);
|
||||
WrenHandle* fiber = wrenGetSlotHandle(vm, 1);
|
||||
|
||||
if (watcher->isActive) {
|
||||
wrenSetSlotString(vm, 0, "Watcher is already active.");
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
watcher->fiber = fiber;
|
||||
watcher->isActive = 1;
|
||||
|
||||
int result = uv_fs_event_start(&watcher->handle, eventCallback, watcher->path, 0);
|
||||
if (result != 0) {
|
||||
watcher->fiber = NULL;
|
||||
watcher->isActive = 0;
|
||||
wrenReleaseHandle(vm, fiber);
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotNull(vm, 0);
|
||||
}
|
||||
|
||||
void fswatchStop(WrenVM* vm)
|
||||
{
|
||||
FileWatcherData* watcher = (FileWatcherData*)wrenGetSlotForeign(vm, 0);
|
||||
|
||||
if (watcher->isActive) {
|
||||
uv_fs_event_stop(&watcher->handle);
|
||||
watcher->isActive = 0;
|
||||
}
|
||||
|
||||
if (watcher->fiber != NULL) {
|
||||
wrenReleaseHandle(vm, watcher->fiber);
|
||||
watcher->fiber = NULL;
|
||||
}
|
||||
|
||||
if (watcher->eventClass != NULL) {
|
||||
wrenReleaseHandle(vm, watcher->eventClass);
|
||||
watcher->eventClass = NULL;
|
||||
}
|
||||
|
||||
wrenSetSlotNull(vm, 0);
|
||||
}
|
||||
|
||||
void fswatchIsActive(WrenVM* vm)
|
||||
{
|
||||
FileWatcherData* watcher = (FileWatcherData*)wrenGetSlotForeign(vm, 0);
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenSetSlotBool(vm, 0, watcher->isActive != 0);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
#ifndef fswatch_h
|
||||
#define fswatch_h
|
||||
|
||||
#include "wren.h"
|
||||
|
||||
void fswatchAllocate(WrenVM* vm);
|
||||
void fswatchFinalize(void* data);
|
||||
void fswatchStart(WrenVM* vm);
|
||||
void fswatchStop(WrenVM* vm);
|
||||
void fswatchIsActive(WrenVM* vm);
|
||||
|
||||
#endif
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
import "scheduler" for Scheduler
|
||||
|
||||
class FsEvent {
|
||||
construct new(filename, events) {
|
||||
_filename = filename
|
||||
_isRename = (events & 1) != 0
|
||||
_isChange = (events & 2) != 0
|
||||
}
|
||||
|
||||
filename { _filename }
|
||||
isRename { _isRename }
|
||||
isChange { _isChange }
|
||||
|
||||
toString { "FsEvent(%(filename), rename: %(isRename), change: %(isChange))" }
|
||||
}
|
||||
|
||||
foreign class FileWatcher {
|
||||
construct new(path) {}
|
||||
|
||||
start(callback) {
|
||||
if (!(callback is Fn)) Fiber.abort("Callback must be a function.")
|
||||
var fiber = Fiber.new {
|
||||
while (true) {
|
||||
var event = Fiber.yield()
|
||||
if (event == null) return
|
||||
callback.call(event)
|
||||
}
|
||||
}
|
||||
fiber.call()
|
||||
start_(fiber)
|
||||
}
|
||||
|
||||
stop() { stop_() }
|
||||
|
||||
foreign isActive
|
||||
|
||||
foreign start_(fiber)
|
||||
foreign stop_()
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Please do not edit this file. It has been generated automatically
|
||||
// from `src/module/fswatch.wren` using `util/wren_to_c_string.py`
|
||||
|
||||
static const char* fswatchModuleSource =
|
||||
"// retoor <retoor@molodetz.nl>\n"
|
||||
"\n"
|
||||
"import \"scheduler\" for Scheduler\n"
|
||||
"\n"
|
||||
"class FsEvent {\n"
|
||||
" construct new(filename, events) {\n"
|
||||
" _filename = filename\n"
|
||||
" _isRename = (events & 1) != 0\n"
|
||||
" _isChange = (events & 2) != 0\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" filename { _filename }\n"
|
||||
" isRename { _isRename }\n"
|
||||
" isChange { _isChange }\n"
|
||||
"\n"
|
||||
" toString { \"FsEvent(%(filename), rename: %(isRename), change: %(isChange))\" }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"foreign class FileWatcher {\n"
|
||||
" construct new(path) {}\n"
|
||||
"\n"
|
||||
" start(callback) {\n"
|
||||
" if (!(callback is Fn)) Fiber.abort(\"Callback must be a function.\")\n"
|
||||
" var fiber = Fiber.new {\n"
|
||||
" while (true) {\n"
|
||||
" var event = Fiber.yield()\n"
|
||||
" if (event == null) return\n"
|
||||
" callback.call(event)\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" fiber.call()\n"
|
||||
" start_(fiber)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" stop() { stop_() }\n"
|
||||
"\n"
|
||||
" foreign isActive\n"
|
||||
"\n"
|
||||
" foreign start_(fiber)\n"
|
||||
" foreign stop_()\n"
|
||||
"}\n";
|
||||
@@ -0,0 +1,275 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sysinfo.h"
|
||||
#include "wren.h"
|
||||
#include "uv.h"
|
||||
|
||||
void sysinfoGetCpuInfo(WrenVM* vm)
|
||||
{
|
||||
wrenEnsureSlots(vm, 4);
|
||||
|
||||
uv_cpu_info_t* cpus;
|
||||
int count;
|
||||
int result = uv_cpu_info(&cpus, &count);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotNewList(vm, 0);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
wrenSetSlotNewMap(vm, 1);
|
||||
|
||||
wrenSetSlotString(vm, 2, "model");
|
||||
wrenSetSlotString(vm, 3, cpus[i].model);
|
||||
wrenSetMapValue(vm, 1, 2, 3);
|
||||
|
||||
wrenSetSlotString(vm, 2, "speed");
|
||||
wrenSetSlotDouble(vm, 3, (double)cpus[i].speed);
|
||||
wrenSetMapValue(vm, 1, 2, 3);
|
||||
|
||||
wrenSetSlotNewMap(vm, 3);
|
||||
|
||||
wrenSetSlotString(vm, 2, "user");
|
||||
wrenSetSlotDouble(vm, 3, (double)cpus[i].cpu_times.user);
|
||||
wrenEnsureSlots(vm, 5);
|
||||
wrenSetSlotNewMap(vm, 4);
|
||||
wrenSetSlotString(vm, 2, "user");
|
||||
wrenSetSlotDouble(vm, 3, (double)cpus[i].cpu_times.user);
|
||||
|
||||
wrenSetSlotNewMap(vm, 2);
|
||||
|
||||
wrenSetSlotString(vm, 3, "user");
|
||||
wrenEnsureSlots(vm, 5);
|
||||
wrenSetSlotDouble(vm, 4, (double)cpus[i].cpu_times.user);
|
||||
wrenSetMapValue(vm, 2, 3, 4);
|
||||
|
||||
wrenSetSlotString(vm, 3, "nice");
|
||||
wrenSetSlotDouble(vm, 4, (double)cpus[i].cpu_times.nice);
|
||||
wrenSetMapValue(vm, 2, 3, 4);
|
||||
|
||||
wrenSetSlotString(vm, 3, "sys");
|
||||
wrenSetSlotDouble(vm, 4, (double)cpus[i].cpu_times.sys);
|
||||
wrenSetMapValue(vm, 2, 3, 4);
|
||||
|
||||
wrenSetSlotString(vm, 3, "idle");
|
||||
wrenSetSlotDouble(vm, 4, (double)cpus[i].cpu_times.idle);
|
||||
wrenSetMapValue(vm, 2, 3, 4);
|
||||
|
||||
wrenSetSlotString(vm, 3, "irq");
|
||||
wrenSetSlotDouble(vm, 4, (double)cpus[i].cpu_times.irq);
|
||||
wrenSetMapValue(vm, 2, 3, 4);
|
||||
|
||||
wrenSetSlotString(vm, 3, "times");
|
||||
wrenSetMapValue(vm, 1, 3, 2);
|
||||
|
||||
wrenInsertInList(vm, 0, -1, 1);
|
||||
}
|
||||
|
||||
uv_free_cpu_info(cpus, count);
|
||||
}
|
||||
|
||||
void sysinfoGetCpuCount(WrenVM* vm)
|
||||
{
|
||||
wrenEnsureSlots(vm, 1);
|
||||
|
||||
uv_cpu_info_t* cpus;
|
||||
int count;
|
||||
int result = uv_cpu_info(&cpus, &count);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotDouble(vm, 0, (double)count);
|
||||
uv_free_cpu_info(cpus, count);
|
||||
}
|
||||
|
||||
void sysinfoGetLoadAverage(WrenVM* vm)
|
||||
{
|
||||
wrenEnsureSlots(vm, 2);
|
||||
|
||||
double avg[3];
|
||||
uv_loadavg(avg);
|
||||
|
||||
wrenSetSlotNewList(vm, 0);
|
||||
|
||||
wrenSetSlotDouble(vm, 1, avg[0]);
|
||||
wrenInsertInList(vm, 0, -1, 1);
|
||||
|
||||
wrenSetSlotDouble(vm, 1, avg[1]);
|
||||
wrenInsertInList(vm, 0, -1, 1);
|
||||
|
||||
wrenSetSlotDouble(vm, 1, avg[2]);
|
||||
wrenInsertInList(vm, 0, -1, 1);
|
||||
}
|
||||
|
||||
void sysinfoGetTotalMemory(WrenVM* vm)
|
||||
{
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenSetSlotDouble(vm, 0, (double)uv_get_total_memory());
|
||||
}
|
||||
|
||||
void sysinfoGetFreeMemory(WrenVM* vm)
|
||||
{
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenSetSlotDouble(vm, 0, (double)uv_get_free_memory());
|
||||
}
|
||||
|
||||
void sysinfoGetUptime(WrenVM* vm)
|
||||
{
|
||||
wrenEnsureSlots(vm, 1);
|
||||
|
||||
double uptime;
|
||||
int result = uv_uptime(&uptime);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotDouble(vm, 0, uptime);
|
||||
}
|
||||
|
||||
void sysinfoGetHostname(WrenVM* vm)
|
||||
{
|
||||
wrenEnsureSlots(vm, 1);
|
||||
|
||||
char buffer[UV_MAXHOSTNAMESIZE];
|
||||
size_t size = sizeof(buffer);
|
||||
int result = uv_os_gethostname(buffer, &size);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotString(vm, 0, buffer);
|
||||
}
|
||||
|
||||
void sysinfoGetNetworkInterfaces(WrenVM* vm)
|
||||
{
|
||||
wrenEnsureSlots(vm, 5);
|
||||
|
||||
uv_interface_address_t* addresses;
|
||||
int count;
|
||||
int result = uv_interface_addresses(&addresses, &count);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotNewMap(vm, 0);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
wrenSetSlotString(vm, 1, addresses[i].name);
|
||||
|
||||
if (!wrenGetMapContainsKey(vm, 0, 1))
|
||||
{
|
||||
wrenSetSlotNewList(vm, 2);
|
||||
wrenSetMapValue(vm, 0, 1, 2);
|
||||
}
|
||||
|
||||
wrenGetMapValue(vm, 0, 1, 2);
|
||||
|
||||
wrenSetSlotNewMap(vm, 3);
|
||||
|
||||
if (addresses[i].address.address4.sin_family == AF_INET)
|
||||
{
|
||||
uv_ip4_name(&addresses[i].address.address4, ip, sizeof(ip));
|
||||
wrenSetSlotString(vm, 4, "IPv4");
|
||||
}
|
||||
else
|
||||
{
|
||||
uv_ip6_name(&addresses[i].address.address6, ip, sizeof(ip));
|
||||
wrenSetSlotString(vm, 4, "IPv6");
|
||||
}
|
||||
|
||||
wrenSetSlotString(vm, 1, "family");
|
||||
wrenSetMapValue(vm, 3, 1, 4);
|
||||
|
||||
wrenSetSlotString(vm, 1, "address");
|
||||
wrenSetSlotString(vm, 4, ip);
|
||||
wrenSetMapValue(vm, 3, 1, 4);
|
||||
|
||||
wrenSetSlotString(vm, 1, "internal");
|
||||
wrenSetSlotBool(vm, 4, addresses[i].is_internal);
|
||||
wrenSetMapValue(vm, 3, 1, 4);
|
||||
|
||||
char netmask[INET6_ADDRSTRLEN];
|
||||
if (addresses[i].address.address4.sin_family == AF_INET)
|
||||
{
|
||||
uv_ip4_name(&addresses[i].netmask.netmask4, netmask, sizeof(netmask));
|
||||
}
|
||||
else
|
||||
{
|
||||
uv_ip6_name(&addresses[i].netmask.netmask6, netmask, sizeof(netmask));
|
||||
}
|
||||
wrenSetSlotString(vm, 1, "netmask");
|
||||
wrenSetSlotString(vm, 4, netmask);
|
||||
wrenSetMapValue(vm, 3, 1, 4);
|
||||
|
||||
char mac[18];
|
||||
unsigned char* phys = addresses[i].phys_addr;
|
||||
snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
phys[0], phys[1], phys[2], phys[3], phys[4], phys[5]);
|
||||
wrenSetSlotString(vm, 1, "mac");
|
||||
wrenSetSlotString(vm, 4, mac);
|
||||
wrenSetMapValue(vm, 3, 1, 4);
|
||||
|
||||
wrenInsertInList(vm, 2, -1, 3);
|
||||
|
||||
wrenSetSlotString(vm, 1, addresses[i].name);
|
||||
wrenSetMapValue(vm, 0, 1, 2);
|
||||
}
|
||||
|
||||
uv_free_interface_addresses(addresses, count);
|
||||
}
|
||||
|
||||
void sysinfoGetHrtime(WrenVM* vm)
|
||||
{
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenSetSlotDouble(vm, 0, (double)uv_hrtime());
|
||||
}
|
||||
|
||||
void sysinfoGetResidentMemory(WrenVM* vm)
|
||||
{
|
||||
wrenEnsureSlots(vm, 1);
|
||||
|
||||
size_t rss;
|
||||
int result = uv_resident_set_memory(&rss);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotDouble(vm, 0, (double)rss);
|
||||
}
|
||||
|
||||
void sysinfoGetConstrainedMemory(WrenVM* vm)
|
||||
{
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenSetSlotDouble(vm, 0, (double)uv_get_constrained_memory());
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
#ifndef sysinfo_h
|
||||
#define sysinfo_h
|
||||
|
||||
#include "wren.h"
|
||||
|
||||
void sysinfoGetCpuInfo(WrenVM* vm);
|
||||
void sysinfoGetCpuCount(WrenVM* vm);
|
||||
void sysinfoGetLoadAverage(WrenVM* vm);
|
||||
void sysinfoGetTotalMemory(WrenVM* vm);
|
||||
void sysinfoGetFreeMemory(WrenVM* vm);
|
||||
void sysinfoGetUptime(WrenVM* vm);
|
||||
void sysinfoGetHostname(WrenVM* vm);
|
||||
void sysinfoGetNetworkInterfaces(WrenVM* vm);
|
||||
void sysinfoGetHrtime(WrenVM* vm);
|
||||
void sysinfoGetResidentMemory(WrenVM* vm);
|
||||
void sysinfoGetConstrainedMemory(WrenVM* vm);
|
||||
|
||||
#endif
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
class SysInfo {
|
||||
foreign static cpuInfo
|
||||
foreign static cpuCount
|
||||
foreign static loadAverage
|
||||
foreign static totalMemory
|
||||
foreign static freeMemory
|
||||
foreign static uptime
|
||||
foreign static hostname
|
||||
foreign static networkInterfaces
|
||||
foreign static hrtime
|
||||
foreign static residentMemory
|
||||
foreign static constrainedMemory
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Please do not edit this file. It has been generated automatically
|
||||
// from `src/module/sysinfo.wren` using `util/wren_to_c_string.py`
|
||||
|
||||
static const char* sysinfoModuleSource =
|
||||
"// retoor <retoor@molodetz.nl>\n"
|
||||
"\n"
|
||||
"class SysInfo {\n"
|
||||
" foreign static cpuInfo\n"
|
||||
" foreign static cpuCount\n"
|
||||
" foreign static loadAverage\n"
|
||||
" foreign static totalMemory\n"
|
||||
" foreign static freeMemory\n"
|
||||
" foreign static uptime\n"
|
||||
" foreign static hostname\n"
|
||||
" foreign static networkInterfaces\n"
|
||||
" foreign static hrtime\n"
|
||||
" foreign static residentMemory\n"
|
||||
" foreign static constrainedMemory\n"
|
||||
"}\n";
|
||||
@@ -0,0 +1,384 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "udp.h"
|
||||
#include "scheduler.h"
|
||||
#include "vm.h"
|
||||
#include "wren.h"
|
||||
#include "uv.h"
|
||||
|
||||
typedef struct {
|
||||
uv_udp_t handle;
|
||||
int isClosed;
|
||||
int isReceiving;
|
||||
WrenHandle* receiveFiber;
|
||||
WrenHandle* messageClass;
|
||||
} UdpSocketData;
|
||||
|
||||
typedef struct {
|
||||
WrenHandle* fiber;
|
||||
uv_buf_t buffer;
|
||||
} UdpSendData;
|
||||
|
||||
static void allocCallback(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf)
|
||||
{
|
||||
buf->base = (char*)malloc(suggestedSize);
|
||||
buf->len = suggestedSize;
|
||||
}
|
||||
|
||||
void udpSocketAllocate(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* data = (UdpSocketData*)wrenSetSlotNewForeign(vm, 0, 0, sizeof(UdpSocketData));
|
||||
memset(data, 0, sizeof(UdpSocketData));
|
||||
|
||||
uv_udp_init(getLoop(), &data->handle);
|
||||
data->handle.data = data;
|
||||
data->isClosed = 0;
|
||||
data->isReceiving = 0;
|
||||
data->receiveFiber = NULL;
|
||||
data->messageClass = NULL;
|
||||
}
|
||||
|
||||
static void closeCallback(uv_handle_t* handle)
|
||||
{
|
||||
}
|
||||
|
||||
void udpSocketFinalize(void* data)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)data;
|
||||
|
||||
if (!socket->isClosed) {
|
||||
uv_close((uv_handle_t*)&socket->handle, closeCallback);
|
||||
socket->isClosed = 1;
|
||||
}
|
||||
|
||||
if (socket->messageClass != NULL) {
|
||||
socket->messageClass = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void udpSocketBind(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)wrenGetSlotForeign(vm, 0);
|
||||
const char* host = wrenGetSlotString(vm, 1);
|
||||
int port = (int)wrenGetSlotDouble(vm, 2);
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
int result;
|
||||
|
||||
if (strchr(host, ':') != NULL) {
|
||||
result = uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr);
|
||||
} else {
|
||||
result = uv_ip4_addr(host, port, (struct sockaddr_in*)&addr);
|
||||
}
|
||||
|
||||
if (result != 0) {
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
result = uv_udp_bind(&socket->handle, (struct sockaddr*)&addr, 0);
|
||||
if (result != 0) {
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotNull(vm, 0);
|
||||
}
|
||||
|
||||
static void sendCallback(uv_udp_send_t* req, int status)
|
||||
{
|
||||
UdpSendData* data = (UdpSendData*)req->data;
|
||||
WrenHandle* fiber = data->fiber;
|
||||
|
||||
free(data->buffer.base);
|
||||
free(data);
|
||||
free(req);
|
||||
|
||||
if (status != 0) {
|
||||
schedulerResumeError(fiber, uv_strerror(status));
|
||||
return;
|
||||
}
|
||||
|
||||
schedulerResume(fiber, false);
|
||||
}
|
||||
|
||||
void udpSocketSend(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)wrenGetSlotForeign(vm, 0);
|
||||
int dataLen;
|
||||
const char* data = wrenGetSlotBytes(vm, 1, &dataLen);
|
||||
const char* host = wrenGetSlotString(vm, 2);
|
||||
int port = (int)wrenGetSlotDouble(vm, 3);
|
||||
WrenHandle* fiber = wrenGetSlotHandle(vm, 4);
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
int result;
|
||||
|
||||
if (strchr(host, ':') != NULL) {
|
||||
result = uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr);
|
||||
} else {
|
||||
result = uv_ip4_addr(host, port, (struct sockaddr_in*)&addr);
|
||||
}
|
||||
|
||||
if (result != 0) {
|
||||
schedulerResumeError(fiber, uv_strerror(result));
|
||||
return;
|
||||
}
|
||||
|
||||
uv_udp_send_t* req = (uv_udp_send_t*)malloc(sizeof(uv_udp_send_t));
|
||||
UdpSendData* sendData = (UdpSendData*)malloc(sizeof(UdpSendData));
|
||||
|
||||
sendData->fiber = fiber;
|
||||
sendData->buffer.base = (char*)malloc(dataLen);
|
||||
sendData->buffer.len = dataLen;
|
||||
memcpy(sendData->buffer.base, data, dataLen);
|
||||
|
||||
req->data = sendData;
|
||||
|
||||
result = uv_udp_send(req, &socket->handle, &sendData->buffer, 1,
|
||||
(struct sockaddr*)&addr, sendCallback);
|
||||
|
||||
if (result != 0) {
|
||||
free(sendData->buffer.base);
|
||||
free(sendData);
|
||||
free(req);
|
||||
schedulerResumeError(fiber, uv_strerror(result));
|
||||
}
|
||||
}
|
||||
|
||||
static void recvCallback(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf,
|
||||
const struct sockaddr* addr, unsigned flags)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)handle->data;
|
||||
|
||||
if (socket->receiveFiber == NULL) {
|
||||
if (buf->base != NULL) free(buf->base);
|
||||
return;
|
||||
}
|
||||
|
||||
uv_udp_recv_stop(handle);
|
||||
socket->isReceiving = 0;
|
||||
|
||||
WrenHandle* fiber = socket->receiveFiber;
|
||||
socket->receiveFiber = NULL;
|
||||
|
||||
if (nread < 0) {
|
||||
if (buf->base != NULL) free(buf->base);
|
||||
schedulerResumeError(fiber, uv_strerror(nread));
|
||||
return;
|
||||
}
|
||||
|
||||
if (nread == 0 && addr == NULL) {
|
||||
if (buf->base != NULL) free(buf->base);
|
||||
schedulerResume(fiber, true);
|
||||
wrenSetSlotNull(getVM(), 2);
|
||||
schedulerFinishResume();
|
||||
return;
|
||||
}
|
||||
|
||||
WrenVM* vm = getVM();
|
||||
wrenEnsureSlots(vm, 5);
|
||||
|
||||
if (socket->messageClass == NULL) {
|
||||
wrenGetVariable(vm, "udp", "UdpMessage", 3);
|
||||
socket->messageClass = wrenGetSlotHandle(vm, 3);
|
||||
}
|
||||
|
||||
wrenSetSlotHandle(vm, 3, socket->messageClass);
|
||||
wrenSetSlotBytes(vm, 4, buf->base, nread);
|
||||
|
||||
char addrStr[INET6_ADDRSTRLEN];
|
||||
int port;
|
||||
|
||||
if (addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in* addr4 = (struct sockaddr_in*)addr;
|
||||
uv_ip4_name(addr4, addrStr, sizeof(addrStr));
|
||||
port = ntohs(addr4->sin_port);
|
||||
} else {
|
||||
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)addr;
|
||||
uv_ip6_name(addr6, addrStr, sizeof(addrStr));
|
||||
port = ntohs(addr6->sin6_port);
|
||||
}
|
||||
|
||||
free(buf->base);
|
||||
|
||||
wrenSetSlotNewList(vm, 2);
|
||||
wrenSetSlotString(vm, 1, addrStr);
|
||||
wrenInsertInList(vm, 2, -1, 4);
|
||||
wrenInsertInList(vm, 2, -1, 1);
|
||||
wrenSetSlotDouble(vm, 1, (double)port);
|
||||
wrenInsertInList(vm, 2, -1, 1);
|
||||
|
||||
schedulerResume(fiber, true);
|
||||
schedulerFinishResume();
|
||||
}
|
||||
|
||||
void udpSocketReceive(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)wrenGetSlotForeign(vm, 0);
|
||||
WrenHandle* fiber = wrenGetSlotHandle(vm, 1);
|
||||
|
||||
if (socket->isReceiving) {
|
||||
schedulerResumeError(fiber, "Already receiving.");
|
||||
return;
|
||||
}
|
||||
|
||||
socket->receiveFiber = fiber;
|
||||
socket->isReceiving = 1;
|
||||
|
||||
int result = uv_udp_recv_start(&socket->handle, allocCallback, recvCallback);
|
||||
if (result != 0) {
|
||||
socket->receiveFiber = NULL;
|
||||
socket->isReceiving = 0;
|
||||
schedulerResumeError(fiber, uv_strerror(result));
|
||||
}
|
||||
}
|
||||
|
||||
void udpSocketClose(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)wrenGetSlotForeign(vm, 0);
|
||||
|
||||
if (!socket->isClosed) {
|
||||
if (socket->isReceiving) {
|
||||
uv_udp_recv_stop(&socket->handle);
|
||||
socket->isReceiving = 0;
|
||||
}
|
||||
uv_close((uv_handle_t*)&socket->handle, closeCallback);
|
||||
socket->isClosed = 1;
|
||||
}
|
||||
|
||||
if (socket->messageClass != NULL) {
|
||||
wrenReleaseHandle(vm, socket->messageClass);
|
||||
socket->messageClass = NULL;
|
||||
}
|
||||
|
||||
wrenSetSlotNull(vm, 0);
|
||||
}
|
||||
|
||||
void udpSocketSetBroadcast(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)wrenGetSlotForeign(vm, 0);
|
||||
bool enabled = wrenGetSlotBool(vm, 1);
|
||||
|
||||
int result = uv_udp_set_broadcast(&socket->handle, enabled ? 1 : 0);
|
||||
if (result != 0) {
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotNull(vm, 0);
|
||||
}
|
||||
|
||||
void udpSocketSetMulticastTTL(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)wrenGetSlotForeign(vm, 0);
|
||||
int ttl = (int)wrenGetSlotDouble(vm, 1);
|
||||
|
||||
int result = uv_udp_set_multicast_ttl(&socket->handle, ttl);
|
||||
if (result != 0) {
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotNull(vm, 0);
|
||||
}
|
||||
|
||||
void udpSocketSetMulticastLoopback(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)wrenGetSlotForeign(vm, 0);
|
||||
bool enabled = wrenGetSlotBool(vm, 1);
|
||||
|
||||
int result = uv_udp_set_multicast_loop(&socket->handle, enabled ? 1 : 0);
|
||||
if (result != 0) {
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotNull(vm, 0);
|
||||
}
|
||||
|
||||
void udpSocketJoinMulticast(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)wrenGetSlotForeign(vm, 0);
|
||||
const char* group = wrenGetSlotString(vm, 1);
|
||||
const char* iface = wrenGetSlotString(vm, 2);
|
||||
|
||||
int result = uv_udp_set_membership(&socket->handle, group, iface, UV_JOIN_GROUP);
|
||||
if (result != 0) {
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotNull(vm, 0);
|
||||
}
|
||||
|
||||
void udpSocketLeaveMulticast(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)wrenGetSlotForeign(vm, 0);
|
||||
const char* group = wrenGetSlotString(vm, 1);
|
||||
const char* iface = wrenGetSlotString(vm, 2);
|
||||
|
||||
int result = uv_udp_set_membership(&socket->handle, group, iface, UV_LEAVE_GROUP);
|
||||
if (result != 0) {
|
||||
wrenSetSlotString(vm, 0, uv_strerror(result));
|
||||
wrenAbortFiber(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wrenSetSlotNull(vm, 0);
|
||||
}
|
||||
|
||||
void udpSocketLocalAddress(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)wrenGetSlotForeign(vm, 0);
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
int len = sizeof(addr);
|
||||
int result = uv_udp_getsockname(&socket->handle, (struct sockaddr*)&addr, &len);
|
||||
|
||||
if (result != 0) {
|
||||
wrenSetSlotNull(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
char addrStr[INET6_ADDRSTRLEN];
|
||||
if (addr.ss_family == AF_INET) {
|
||||
uv_ip4_name((struct sockaddr_in*)&addr, addrStr, sizeof(addrStr));
|
||||
} else {
|
||||
uv_ip6_name((struct sockaddr_in6*)&addr, addrStr, sizeof(addrStr));
|
||||
}
|
||||
|
||||
wrenSetSlotString(vm, 0, addrStr);
|
||||
}
|
||||
|
||||
void udpSocketLocalPort(WrenVM* vm)
|
||||
{
|
||||
UdpSocketData* socket = (UdpSocketData*)wrenGetSlotForeign(vm, 0);
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
int len = sizeof(addr);
|
||||
int result = uv_udp_getsockname(&socket->handle, (struct sockaddr*)&addr, &len);
|
||||
|
||||
if (result != 0) {
|
||||
wrenSetSlotDouble(vm, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int port;
|
||||
if (addr.ss_family == AF_INET) {
|
||||
port = ntohs(((struct sockaddr_in*)&addr)->sin_port);
|
||||
} else {
|
||||
port = ntohs(((struct sockaddr_in6*)&addr)->sin6_port);
|
||||
}
|
||||
|
||||
wrenSetSlotDouble(vm, 0, (double)port);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
#ifndef udp_h
|
||||
#define udp_h
|
||||
|
||||
#include "wren.h"
|
||||
|
||||
void udpSocketAllocate(WrenVM* vm);
|
||||
void udpSocketFinalize(void* data);
|
||||
void udpSocketBind(WrenVM* vm);
|
||||
void udpSocketSend(WrenVM* vm);
|
||||
void udpSocketReceive(WrenVM* vm);
|
||||
void udpSocketClose(WrenVM* vm);
|
||||
void udpSocketSetBroadcast(WrenVM* vm);
|
||||
void udpSocketSetMulticastTTL(WrenVM* vm);
|
||||
void udpSocketSetMulticastLoopback(WrenVM* vm);
|
||||
void udpSocketJoinMulticast(WrenVM* vm);
|
||||
void udpSocketLeaveMulticast(WrenVM* vm);
|
||||
void udpSocketLocalAddress(WrenVM* vm);
|
||||
void udpSocketLocalPort(WrenVM* vm);
|
||||
|
||||
#endif
|
||||
Vendored
+90
@@ -0,0 +1,90 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
import "scheduler" for Scheduler
|
||||
|
||||
foreign class UdpSocket {
|
||||
construct new() {}
|
||||
|
||||
bind(host, port) {
|
||||
if (!(host is String)) Fiber.abort("Host must be a string.")
|
||||
if (!(port is Num)) Fiber.abort("Port must be a number.")
|
||||
return bind_(host, port)
|
||||
}
|
||||
|
||||
send(data, host, port) {
|
||||
if (!(data is String)) Fiber.abort("Data must be a string.")
|
||||
if (!(host is String)) Fiber.abort("Host must be a string.")
|
||||
if (!(port is Num)) Fiber.abort("Port must be a number.")
|
||||
return Scheduler.await_ { send_(data, host, port, Fiber.current) }
|
||||
}
|
||||
|
||||
receive() {
|
||||
return Scheduler.await_ { receive_(Fiber.current) }
|
||||
}
|
||||
|
||||
close() { close_() }
|
||||
|
||||
setBroadcast(enabled) {
|
||||
if (!(enabled is Bool)) Fiber.abort("Enabled must be a boolean.")
|
||||
return setBroadcast_(enabled)
|
||||
}
|
||||
|
||||
setMulticastTTL(ttl) {
|
||||
if (!(ttl is Num)) Fiber.abort("TTL must be a number.")
|
||||
return setMulticastTTL_(ttl)
|
||||
}
|
||||
|
||||
setMulticastLoopback(enabled) {
|
||||
if (!(enabled is Bool)) Fiber.abort("Enabled must be a boolean.")
|
||||
return setMulticastLoopback_(enabled)
|
||||
}
|
||||
|
||||
joinMulticast(group) {
|
||||
if (!(group is String)) Fiber.abort("Group must be a string.")
|
||||
return joinMulticast_(group, "0.0.0.0")
|
||||
}
|
||||
|
||||
joinMulticast(group, iface) {
|
||||
if (!(group is String)) Fiber.abort("Group must be a string.")
|
||||
if (!(iface is String)) Fiber.abort("Interface must be a string.")
|
||||
return joinMulticast_(group, iface)
|
||||
}
|
||||
|
||||
leaveMulticast(group) {
|
||||
if (!(group is String)) Fiber.abort("Group must be a string.")
|
||||
return leaveMulticast_(group, "0.0.0.0")
|
||||
}
|
||||
|
||||
leaveMulticast(group, iface) {
|
||||
if (!(group is String)) Fiber.abort("Group must be a string.")
|
||||
if (!(iface is String)) Fiber.abort("Interface must be a string.")
|
||||
return leaveMulticast_(group, iface)
|
||||
}
|
||||
|
||||
foreign localAddress
|
||||
foreign localPort
|
||||
|
||||
foreign bind_(host, port)
|
||||
foreign send_(data, host, port, fiber)
|
||||
foreign receive_(fiber)
|
||||
foreign close_()
|
||||
foreign setBroadcast_(enabled)
|
||||
foreign setMulticastTTL_(ttl)
|
||||
foreign setMulticastLoopback_(enabled)
|
||||
foreign joinMulticast_(group, iface)
|
||||
foreign leaveMulticast_(group, iface)
|
||||
}
|
||||
|
||||
class UdpMessage {
|
||||
construct new(data, address, port) {
|
||||
_data = data
|
||||
_address = address
|
||||
_port = port
|
||||
}
|
||||
|
||||
data { _data }
|
||||
address { _address }
|
||||
port { _port }
|
||||
|
||||
toString { "UdpMessage(%(data.count) bytes from %(address):%(port))" }
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Please do not edit this file. It has been generated automatically
|
||||
// from `src/module/udp.wren` using `util/wren_to_c_string.py`
|
||||
|
||||
static const char* udpModuleSource =
|
||||
"// retoor <retoor@molodetz.nl>\n"
|
||||
"\n"
|
||||
"import \"scheduler\" for Scheduler\n"
|
||||
"\n"
|
||||
"foreign class UdpSocket {\n"
|
||||
" construct new() {}\n"
|
||||
"\n"
|
||||
" bind(host, port) {\n"
|
||||
" if (!(host is String)) Fiber.abort(\"Host must be a string.\")\n"
|
||||
" if (!(port is Num)) Fiber.abort(\"Port must be a number.\")\n"
|
||||
" return bind_(host, port)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" send(data, host, port) {\n"
|
||||
" if (!(data is String)) Fiber.abort(\"Data must be a string.\")\n"
|
||||
" if (!(host is String)) Fiber.abort(\"Host must be a string.\")\n"
|
||||
" if (!(port is Num)) Fiber.abort(\"Port must be a number.\")\n"
|
||||
" return Scheduler.await_ { send_(data, host, port, Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" receive() {\n"
|
||||
" return Scheduler.await_ { receive_(Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" close() { close_() }\n"
|
||||
"\n"
|
||||
" setBroadcast(enabled) {\n"
|
||||
" if (!(enabled is Bool)) Fiber.abort(\"Enabled must be a boolean.\")\n"
|
||||
" return setBroadcast_(enabled)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" setMulticastTTL(ttl) {\n"
|
||||
" if (!(ttl is Num)) Fiber.abort(\"TTL must be a number.\")\n"
|
||||
" return setMulticastTTL_(ttl)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" setMulticastLoopback(enabled) {\n"
|
||||
" if (!(enabled is Bool)) Fiber.abort(\"Enabled must be a boolean.\")\n"
|
||||
" return setMulticastLoopback_(enabled)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" joinMulticast(group) {\n"
|
||||
" if (!(group is String)) Fiber.abort(\"Group must be a string.\")\n"
|
||||
" return joinMulticast_(group, \"0.0.0.0\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" joinMulticast(group, iface) {\n"
|
||||
" if (!(group is String)) Fiber.abort(\"Group must be a string.\")\n"
|
||||
" if (!(iface is String)) Fiber.abort(\"Interface must be a string.\")\n"
|
||||
" return joinMulticast_(group, iface)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" leaveMulticast(group) {\n"
|
||||
" if (!(group is String)) Fiber.abort(\"Group must be a string.\")\n"
|
||||
" return leaveMulticast_(group, \"0.0.0.0\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" leaveMulticast(group, iface) {\n"
|
||||
" if (!(group is String)) Fiber.abort(\"Group must be a string.\")\n"
|
||||
" if (!(iface is String)) Fiber.abort(\"Interface must be a string.\")\n"
|
||||
" return leaveMulticast_(group, iface)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign localAddress\n"
|
||||
" foreign localPort\n"
|
||||
"\n"
|
||||
" foreign bind_(host, port)\n"
|
||||
" foreign send_(data, host, port, fiber)\n"
|
||||
" foreign receive_(fiber)\n"
|
||||
" foreign close_()\n"
|
||||
" foreign setBroadcast_(enabled)\n"
|
||||
" foreign setMulticastTTL_(ttl)\n"
|
||||
" foreign setMulticastLoopback_(enabled)\n"
|
||||
" foreign joinMulticast_(group, iface)\n"
|
||||
" foreign leaveMulticast_(group, iface)\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class UdpMessage {\n"
|
||||
" construct new(data, address, port) {\n"
|
||||
" _data = data\n"
|
||||
" _address = address\n"
|
||||
" _port = port\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" data { _data }\n"
|
||||
" address { _address }\n"
|
||||
" port { _port }\n"
|
||||
"\n"
|
||||
" toString { \"UdpMessage(%(data.count) bytes from %(address):%(port))\" }\n"
|
||||
"}\n";
|
||||
Reference in New Issue
Block a user