473 lines
18 KiB
C
473 lines
18 KiB
C
#include "cell.h"
|
|
#define ENET_IMPLEMENTATION
|
|
#include "enet.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
static JSClassID enet_host_id;
|
|
static JSClassID enet_peer_class_id;
|
|
|
|
static void js_enet_host_finalizer(JSRuntime *rt, JSValue val)
|
|
{
|
|
ENetHost *host = JS_GetOpaque(val, enet_host_id);
|
|
if (host) enet_host_destroy(host);
|
|
}
|
|
|
|
static JSClassDef enet_host_def = {
|
|
"ENetHost",
|
|
.finalizer = js_enet_host_finalizer,
|
|
};
|
|
|
|
static JSClassDef enet_peer_def = {
|
|
"ENetPeer",
|
|
};
|
|
|
|
/* Helper: create a JS peer wrapper for an ENetPeer pointer.
|
|
Fresh wrapper each time — no caching in peer->data. */
|
|
static JSValue peer_wrap(JSContext *ctx, ENetPeer *peer)
|
|
{
|
|
JSValue obj = JS_NewObjectClass(ctx, enet_peer_class_id);
|
|
if (JS_IsException(obj)) return obj;
|
|
JS_SetOpaque(obj, peer);
|
|
return obj;
|
|
}
|
|
|
|
/* ── Host functions ─────────────────────────────────────────── */
|
|
|
|
static JSValue js_enet_create_host(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
ENetHost *host;
|
|
ENetAddress address;
|
|
ENetAddress *send = &address;
|
|
size_t peer_count = 1000;
|
|
size_t channel_limit = 0;
|
|
enet_uint32 incoming_bandwidth = 0;
|
|
enet_uint32 outgoing_bandwidth = 0;
|
|
JSValue obj;
|
|
|
|
if (argc < 1 || !JS_IsRecord(argv[0])) {
|
|
host = enet_host_create(NULL, peer_count, channel_limit, incoming_bandwidth, outgoing_bandwidth);
|
|
if (!host) return JS_RaiseDisrupt(ctx, "Failed to create ENet client host");
|
|
goto wrap;
|
|
}
|
|
|
|
JSValue config_obj = argv[0];
|
|
JSValue addr_val = JS_GetPropertyStr(ctx, config_obj, "address");
|
|
const char *addr_str = JS_IsText(addr_val) ? JS_ToCString(ctx, addr_val) : NULL;
|
|
|
|
if (!addr_str)
|
|
send = NULL;
|
|
else {
|
|
JSValue port_val = JS_GetPropertyStr(ctx, config_obj, "port");
|
|
int32_t port32 = 0;
|
|
JS_ToInt32(ctx, &port32, port_val);
|
|
|
|
if (strcmp(addr_str, "any") == 0)
|
|
address.host = ENET_HOST_ANY;
|
|
else if (strcmp(addr_str, "broadcast") == 0)
|
|
enet_address_set_host_ip(&address, "255.255.255.255");
|
|
else {
|
|
int err = enet_address_set_host_ip(&address, addr_str);
|
|
if (err != 0) {
|
|
JS_FreeCString(ctx, addr_str);
|
|
return JS_RaiseDisrupt(ctx, "Failed to set host IP. Error: %d", err);
|
|
}
|
|
}
|
|
address.port = (enet_uint16)port32;
|
|
JS_FreeCString(ctx, addr_str);
|
|
}
|
|
|
|
JSValue chan_val = JS_GetPropertyStr(ctx, config_obj, "channels");
|
|
JS_ToUint32(ctx, &channel_limit, chan_val);
|
|
|
|
JSValue in_bw_val = JS_GetPropertyStr(ctx, config_obj, "incoming_bandwidth");
|
|
JS_ToUint32(ctx, &incoming_bandwidth, in_bw_val);
|
|
|
|
JSValue out_bw_val = JS_GetPropertyStr(ctx, config_obj, "outgoing_bandwidth");
|
|
JS_ToUint32(ctx, &outgoing_bandwidth, out_bw_val);
|
|
|
|
host = enet_host_create(send, peer_count, channel_limit, incoming_bandwidth, outgoing_bandwidth);
|
|
if (!host) return JS_RaiseDisrupt(ctx, "Failed to create ENet host");
|
|
|
|
wrap:
|
|
obj = JS_NewObjectClass(ctx, enet_host_id);
|
|
if (JS_IsException(obj)) {
|
|
enet_host_destroy(host);
|
|
return obj;
|
|
}
|
|
JS_SetOpaque(obj, host);
|
|
return obj;
|
|
}
|
|
|
|
/* service(host, callback [, timeout]) */
|
|
static JSValue js_enet_service(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 2) return JS_RaiseDisrupt(ctx, "service: expected (host, callback)");
|
|
|
|
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
|
|
if (!host) return JS_RaiseDisrupt(ctx, "service: invalid host");
|
|
|
|
if (!JS_IsFunction(argv[1]))
|
|
return JS_RaiseDisrupt(ctx, "service: expected callback function");
|
|
|
|
enet_uint32 timeout_ms = 0;
|
|
if (argc >= 3 && !JS_IsNull(argv[2])) {
|
|
double secs = 0;
|
|
JS_ToFloat64(ctx, &secs, argv[2]);
|
|
if (secs > 0) timeout_ms = (enet_uint32)(secs * 1000.0);
|
|
}
|
|
|
|
JS_FRAME(ctx);
|
|
JS_ROOT(event_obj, JS_NULL);
|
|
|
|
ENetEvent event;
|
|
while (enet_host_service(host, &event, timeout_ms) > 0) {
|
|
event_obj.val = JS_NewObject(ctx);
|
|
|
|
JSValue peer_val = peer_wrap(ctx, event.peer);
|
|
JS_SetPropertyStr(ctx, event_obj.val, "peer", peer_val);
|
|
|
|
switch (event.type) {
|
|
case ENET_EVENT_TYPE_CONNECT:
|
|
JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "connect"));
|
|
break;
|
|
case ENET_EVENT_TYPE_RECEIVE:
|
|
JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "receive"));
|
|
JS_SetPropertyStr(ctx, event_obj.val, "channelID", JS_NewInt32(ctx, event.channelID));
|
|
if (event.packet->dataLength > 0) {
|
|
JSValue data_val = js_new_blob_stoned_copy(ctx, event.packet->data, event.packet->dataLength);
|
|
JS_SetPropertyStr(ctx, event_obj.val, "data", data_val);
|
|
}
|
|
enet_packet_destroy(event.packet);
|
|
break;
|
|
case ENET_EVENT_TYPE_DISCONNECT:
|
|
JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "disconnect"));
|
|
break;
|
|
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT:
|
|
JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "disconnect_timeout"));
|
|
break;
|
|
case ENET_EVENT_TYPE_NONE:
|
|
JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "none"));
|
|
break;
|
|
}
|
|
|
|
JS_Call(ctx, argv[1], JS_NULL, 1, &event_obj.val);
|
|
}
|
|
|
|
JS_RETURN_NULL();
|
|
}
|
|
|
|
/* connect(host, address, port) → peer */
|
|
static JSValue js_enet_connect(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 3) return JS_RaiseDisrupt(ctx, "connect: expected (host, address, port)");
|
|
|
|
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
|
|
if (!host) return JS_RaiseDisrupt(ctx, "connect: invalid host");
|
|
|
|
const char *hostname = JS_ToCString(ctx, argv[1]);
|
|
if (!hostname) return JS_EXCEPTION;
|
|
int port;
|
|
JS_ToInt32(ctx, &port, argv[2]);
|
|
|
|
ENetAddress address;
|
|
enet_address_set_host(&address, hostname);
|
|
JS_FreeCString(ctx, hostname);
|
|
address.port = port;
|
|
|
|
ENetPeer *peer = enet_host_connect(host, &address, 2, 0);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "No available peers for connection");
|
|
|
|
return peer_wrap(ctx, peer);
|
|
}
|
|
|
|
/* flush(host) */
|
|
static JSValue js_enet_flush(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "flush: expected (host)");
|
|
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
|
|
if (!host) return JS_RaiseDisrupt(ctx, "flush: invalid host");
|
|
enet_host_flush(host);
|
|
return JS_NULL;
|
|
}
|
|
|
|
/* broadcast(host, data) */
|
|
static JSValue js_enet_broadcast(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 2) return JS_RaiseDisrupt(ctx, "broadcast: expected (host, data)");
|
|
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
|
|
if (!host) return JS_RaiseDisrupt(ctx, "broadcast: invalid host");
|
|
|
|
const char *data_str = NULL;
|
|
size_t data_len = 0;
|
|
uint8_t *buf = NULL;
|
|
|
|
if (JS_IsText(argv[1])) {
|
|
data_str = JS_ToCStringLen(ctx, &data_len, argv[1]);
|
|
if (!data_str) return JS_EXCEPTION;
|
|
} else if (js_is_blob(ctx, argv[1])) {
|
|
buf = js_get_blob_data(ctx, &data_len, argv[1]);
|
|
if (!buf) return JS_EXCEPTION;
|
|
} else {
|
|
return JS_RaiseDisrupt(ctx, "broadcast: data must be string or blob");
|
|
}
|
|
|
|
ENetPacket *packet = enet_packet_create(data_str ? (const void *)data_str : (const void *)buf, data_len, ENET_PACKET_FLAG_RELIABLE);
|
|
if (data_str) JS_FreeCString(ctx, data_str);
|
|
if (!packet) return JS_RaiseDisrupt(ctx, "Failed to create ENet packet");
|
|
|
|
enet_host_broadcast(host, 0, packet);
|
|
return JS_NULL;
|
|
}
|
|
|
|
/* host_port(host) → number */
|
|
static JSValue js_enet_host_port(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "host_port: expected (host)");
|
|
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
|
|
if (!host) return JS_RaiseDisrupt(ctx, "host_port: invalid host");
|
|
return JS_NewInt32(ctx, host->address.port);
|
|
}
|
|
|
|
/* host_address(host) → string */
|
|
static JSValue js_enet_host_address(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "host_address: expected (host)");
|
|
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
|
|
if (!host) return JS_RaiseDisrupt(ctx, "host_address: invalid host");
|
|
char ip_str[128];
|
|
if (enet_address_get_host_ip(&host->address, ip_str, sizeof(ip_str)) != 0)
|
|
return JS_NULL;
|
|
return JS_NewString(ctx, ip_str);
|
|
}
|
|
|
|
/* ── Peer functions ─────────────────────────────────────────── */
|
|
|
|
/* send(peer, data) */
|
|
static JSValue js_enet_send(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 2) return JS_RaiseDisrupt(ctx, "send: expected (peer, data)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "send: invalid peer");
|
|
|
|
const char *data_str = NULL;
|
|
size_t data_len = 0;
|
|
uint8_t *buf = NULL;
|
|
|
|
if (JS_IsText(argv[1])) {
|
|
data_str = JS_ToCStringLen(ctx, &data_len, argv[1]);
|
|
if (!data_str) return JS_EXCEPTION;
|
|
} else if (js_is_blob(ctx, argv[1])) {
|
|
buf = js_get_blob_data(ctx, &data_len, argv[1]);
|
|
if (!buf) return JS_EXCEPTION;
|
|
} else {
|
|
return JS_RaiseDisrupt(ctx, "send: data must be string or blob");
|
|
}
|
|
|
|
ENetPacket *packet = enet_packet_create(data_str ? (const void *)data_str : (const void *)buf, data_len, ENET_PACKET_FLAG_RELIABLE);
|
|
if (data_str) JS_FreeCString(ctx, data_str);
|
|
if (!packet) return JS_RaiseDisrupt(ctx, "Failed to create ENet packet");
|
|
|
|
if (enet_peer_send(peer, 0, packet) < 0) return JS_RaiseDisrupt(ctx, "Unable to send packet");
|
|
return JS_NULL;
|
|
}
|
|
|
|
/* disconnect(peer) */
|
|
static JSValue js_enet_disconnect(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "disconnect: expected (peer)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "disconnect: invalid peer");
|
|
enet_peer_disconnect(peer, 0);
|
|
return JS_NULL;
|
|
}
|
|
|
|
/* disconnect_now(peer) */
|
|
static JSValue js_enet_disconnect_now(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "disconnect_now: expected (peer)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "disconnect_now: invalid peer");
|
|
enet_peer_disconnect_now(peer, 0);
|
|
return JS_NULL;
|
|
}
|
|
|
|
/* disconnect_later(peer) */
|
|
static JSValue js_enet_disconnect_later(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "disconnect_later: expected (peer)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "disconnect_later: invalid peer");
|
|
enet_peer_disconnect_later(peer, 0);
|
|
return JS_NULL;
|
|
}
|
|
|
|
/* reset(peer) */
|
|
static JSValue js_enet_reset(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "reset: expected (peer)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "reset: invalid peer");
|
|
enet_peer_reset(peer);
|
|
return JS_NULL;
|
|
}
|
|
|
|
/* ping(peer) */
|
|
static JSValue js_enet_ping(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "ping: expected (peer)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "ping: invalid peer");
|
|
enet_peer_ping(peer);
|
|
return JS_NULL;
|
|
}
|
|
|
|
/* throttle_configure(peer, interval, acceleration, deceleration) */
|
|
static JSValue js_enet_throttle_configure(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 4) return JS_RaiseDisrupt(ctx, "throttle_configure: expected (peer, interval, accel, decel)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "throttle_configure: invalid peer");
|
|
int interval, acceleration, deceleration;
|
|
if (JS_ToInt32(ctx, &interval, argv[1]) || JS_ToInt32(ctx, &acceleration, argv[2]) || JS_ToInt32(ctx, &deceleration, argv[3]))
|
|
return JS_RaiseDisrupt(ctx, "throttle_configure: expected integer arguments");
|
|
enet_peer_throttle_configure(peer, interval, acceleration, deceleration);
|
|
return JS_NULL;
|
|
}
|
|
|
|
/* peer_timeout(peer, limit, min, max) */
|
|
static JSValue js_enet_peer_timeout(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 4) return JS_RaiseDisrupt(ctx, "peer_timeout: expected (peer, limit, min, max)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "peer_timeout: invalid peer");
|
|
int timeout_limit, timeout_min, timeout_max;
|
|
if (JS_ToInt32(ctx, &timeout_limit, argv[1]) || JS_ToInt32(ctx, &timeout_min, argv[2]) || JS_ToInt32(ctx, &timeout_max, argv[3]))
|
|
return JS_RaiseDisrupt(ctx, "peer_timeout: expected integer arguments");
|
|
enet_peer_timeout(peer, timeout_limit, timeout_min, timeout_max);
|
|
return JS_NULL;
|
|
}
|
|
|
|
/* ── Peer property getters ──────────────────────────────────── */
|
|
|
|
#define PEER_GETTER(name, field, convert) \
|
|
static JSValue js_enet_##name(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { \
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, #name ": expected (peer)"); \
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id); \
|
|
if (!peer) return JS_RaiseDisrupt(ctx, #name ": invalid peer"); \
|
|
return convert(ctx, peer->field); \
|
|
}
|
|
|
|
static inline JSValue _int32(JSContext *ctx, int v) { return JS_NewInt32(ctx, v); }
|
|
static inline JSValue _uint32(JSContext *ctx, unsigned int v) { return JS_NewUint32(ctx, v); }
|
|
|
|
PEER_GETTER(peer_rtt, roundTripTime, _int32)
|
|
PEER_GETTER(peer_rtt_variance, roundTripTimeVariance, _int32)
|
|
PEER_GETTER(peer_last_send_time, lastSendTime, _int32)
|
|
PEER_GETTER(peer_last_receive_time, lastReceiveTime, _int32)
|
|
PEER_GETTER(peer_mtu, mtu, _int32)
|
|
PEER_GETTER(peer_outgoing_data_total, outgoingDataTotal, _int32)
|
|
PEER_GETTER(peer_incoming_data_total, incomingDataTotal, _int32)
|
|
PEER_GETTER(peer_packet_loss, packetLoss, _int32)
|
|
PEER_GETTER(peer_state, state, _int32)
|
|
PEER_GETTER(peer_reliable_data_in_transit, reliableDataInTransit, _int32)
|
|
|
|
static JSValue js_enet_peer_incoming_bandwidth(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "peer_incoming_bandwidth: expected (peer)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "peer_incoming_bandwidth: invalid peer");
|
|
if (peer->incomingBandwidth == 0) return JS_NewFloat64(ctx, INFINITY);
|
|
return JS_NewInt32(ctx, peer->incomingBandwidth);
|
|
}
|
|
|
|
static JSValue js_enet_peer_outgoing_bandwidth(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "peer_outgoing_bandwidth: expected (peer)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "peer_outgoing_bandwidth: invalid peer");
|
|
if (peer->outgoingBandwidth == 0) return JS_NewFloat64(ctx, INFINITY);
|
|
return JS_NewInt32(ctx, peer->outgoingBandwidth);
|
|
}
|
|
|
|
static JSValue js_enet_peer_port(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "peer_port: expected (peer)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "peer_port: invalid peer");
|
|
return JS_NewUint32(ctx, peer->address.port);
|
|
}
|
|
|
|
static JSValue js_enet_peer_address(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
if (argc < 1) return JS_RaiseDisrupt(ctx, "peer_address: expected (peer)");
|
|
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
|
|
if (!peer) return JS_RaiseDisrupt(ctx, "peer_address: invalid peer");
|
|
char ip_str[128];
|
|
if (enet_address_get_host_ip(&peer->address, ip_str, sizeof(ip_str)) != 0)
|
|
return JS_NULL;
|
|
return JS_NewString(ctx, ip_str);
|
|
}
|
|
|
|
static JSValue js_enet_resolve_hostname(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
|
{
|
|
const char *hostname = JS_ToCString(ctx, argv[0]);
|
|
JS_FreeCString(ctx, hostname);
|
|
return JS_NULL;
|
|
}
|
|
|
|
/* ── Module export ──────────────────────────────────────────── */
|
|
|
|
static const JSCFunctionListEntry js_enet_funcs[] = {
|
|
/* host */
|
|
JS_CFUNC_DEF("create_host", 1, js_enet_create_host),
|
|
JS_CFUNC_DEF("service", 2, js_enet_service),
|
|
JS_CFUNC_DEF("connect", 3, js_enet_connect),
|
|
JS_CFUNC_DEF("flush", 1, js_enet_flush),
|
|
JS_CFUNC_DEF("broadcast", 2, js_enet_broadcast),
|
|
JS_CFUNC_DEF("host_port", 1, js_enet_host_port),
|
|
JS_CFUNC_DEF("host_address", 1, js_enet_host_address),
|
|
/* peer */
|
|
JS_CFUNC_DEF("send", 2, js_enet_send),
|
|
JS_CFUNC_DEF("disconnect", 1, js_enet_disconnect),
|
|
JS_CFUNC_DEF("disconnect_now", 1, js_enet_disconnect_now),
|
|
JS_CFUNC_DEF("disconnect_later", 1, js_enet_disconnect_later),
|
|
JS_CFUNC_DEF("reset", 1, js_enet_reset),
|
|
JS_CFUNC_DEF("ping", 1, js_enet_ping),
|
|
JS_CFUNC_DEF("throttle_configure", 4, js_enet_throttle_configure),
|
|
JS_CFUNC_DEF("peer_timeout", 4, js_enet_peer_timeout),
|
|
JS_CFUNC_DEF("peer_address", 1, js_enet_peer_address),
|
|
JS_CFUNC_DEF("peer_port", 1, js_enet_peer_port),
|
|
JS_CFUNC_DEF("peer_rtt", 1, js_enet_peer_rtt),
|
|
JS_CFUNC_DEF("peer_rtt_variance", 1, js_enet_peer_rtt_variance),
|
|
JS_CFUNC_DEF("peer_incoming_bandwidth", 1, js_enet_peer_incoming_bandwidth),
|
|
JS_CFUNC_DEF("peer_outgoing_bandwidth", 1, js_enet_peer_outgoing_bandwidth),
|
|
JS_CFUNC_DEF("peer_last_send_time", 1, js_enet_peer_last_send_time),
|
|
JS_CFUNC_DEF("peer_last_receive_time", 1, js_enet_peer_last_receive_time),
|
|
JS_CFUNC_DEF("peer_mtu", 1, js_enet_peer_mtu),
|
|
JS_CFUNC_DEF("peer_outgoing_data_total", 1, js_enet_peer_outgoing_data_total),
|
|
JS_CFUNC_DEF("peer_incoming_data_total", 1, js_enet_peer_incoming_data_total),
|
|
JS_CFUNC_DEF("peer_packet_loss", 1, js_enet_peer_packet_loss),
|
|
JS_CFUNC_DEF("peer_state", 1, js_enet_peer_state),
|
|
JS_CFUNC_DEF("peer_reliable_data_in_transit", 1, js_enet_peer_reliable_data_in_transit),
|
|
JS_CFUNC_DEF("resolve_hostname", 1, js_enet_resolve_hostname),
|
|
};
|
|
|
|
JSValue js_core_internal_enet_use(JSContext *ctx)
|
|
{
|
|
enet_initialize();
|
|
|
|
JS_FRAME(ctx);
|
|
|
|
JS_NewClassID(&enet_host_id);
|
|
JS_NewClass(ctx, enet_host_id, &enet_host_def);
|
|
|
|
JS_NewClassID(&enet_peer_class_id);
|
|
JS_NewClass(ctx, enet_peer_class_id, &enet_peer_def);
|
|
|
|
JS_ROOT(export_obj, JS_NewObject(ctx));
|
|
JS_SetPropertyFunctionList(ctx, export_obj.val, js_enet_funcs, countof(js_enet_funcs));
|
|
JS_RETURN(export_obj.val);
|
|
}
|