291 lines
11 KiB
C
291 lines
11 KiB
C
// network_playdate.c - Cell integration for Playdate Network API
|
|
// Wraps pd_api_network.h functions for JavaScript access
|
|
|
|
#include "cell.h"
|
|
#include "common.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
// --- Helpers ---
|
|
static HTTPConnection* js2http(JSContext *js, JSValueConst val) {
|
|
int64_t ptr;
|
|
if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
|
|
return (HTTPConnection*)(intptr_t)ptr;
|
|
}
|
|
|
|
static TCPConnection* js2tcp(JSContext *js, JSValueConst val) {
|
|
int64_t ptr;
|
|
if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
|
|
return (TCPConnection*)(intptr_t)ptr;
|
|
}
|
|
|
|
// --- Network Status ---
|
|
|
|
JSC_CCALL(network_getStatus,
|
|
if (!pd_network) return JS_ThrowInternalError(js, "network not initialized");
|
|
return JS_NewInt32(js, pd_network->getStatus());
|
|
)
|
|
|
|
JSC_CCALL(network_setEnabled,
|
|
if (!pd_network) return JS_ThrowInternalError(js, "network not initialized");
|
|
// Note: callback not implemented for simplicity
|
|
pd_network->setEnabled(JS_ToBool(js, argv[0]), NULL);
|
|
return JS_NULL;
|
|
)
|
|
|
|
// --- HTTP Functions ---
|
|
|
|
JSC_SCALL(http_newConnection,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
int port = (int)js2number(js, argv[1]);
|
|
int usessl = argc > 2 ? JS_ToBool(js, argv[2]) : 0;
|
|
HTTPConnection *conn = pd_network->http->newConnection(str, port, usessl);
|
|
ret = conn ? JS_NewInt64(js, (int64_t)(intptr_t)conn) : JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(http_retain,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
HTTPConnection *conn = js2http(js, argv[0]);
|
|
HTTPConnection *ret_conn = pd_network->http->retain(conn);
|
|
return ret_conn ? JS_NewInt64(js, (int64_t)(intptr_t)ret_conn) : JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(http_release,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
HTTPConnection *conn = js2http(js, argv[0]);
|
|
if (conn) pd_network->http->release(conn);
|
|
return JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(http_setConnectTimeout,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
pd_network->http->setConnectTimeout(js2http(js, argv[0]), (int)js2number(js, argv[1]));
|
|
return JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(http_setKeepAlive,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
pd_network->http->setKeepAlive(js2http(js, argv[0]), JS_ToBool(js, argv[1]));
|
|
return JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(http_setByteRange,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
pd_network->http->setByteRange(js2http(js, argv[0]), (int)js2number(js, argv[1]), (int)js2number(js, argv[2]));
|
|
return JS_NULL;
|
|
)
|
|
|
|
JSC_SCALL(http_get,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
HTTPConnection *conn = js2http(js, argv[0]);
|
|
const char *headers = argc > 2 ? JS_ToCString(js, argv[2]) : NULL;
|
|
size_t hlen = headers ? strlen(headers) : 0;
|
|
PDNetErr err = pd_network->http->get(conn, str, headers, hlen);
|
|
if (headers) JS_FreeCString(js, headers);
|
|
ret = JS_NewInt32(js, err);
|
|
)
|
|
|
|
JSC_SCALL(http_post,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
HTTPConnection *conn = js2http(js, argv[0]);
|
|
const char *headers = argc > 2 ? JS_ToCString(js, argv[2]) : NULL;
|
|
size_t hlen = headers ? strlen(headers) : 0;
|
|
size_t blen;
|
|
const char *body = argc > 3 ? js_get_blob_data(js, &blen, argv[3]) : NULL;
|
|
if (body == (void*)-1) body = NULL;
|
|
PDNetErr err = pd_network->http->post(conn, str, headers, hlen, body, body ? blen : 0);
|
|
if (headers) JS_FreeCString(js, headers);
|
|
ret = JS_NewInt32(js, err);
|
|
)
|
|
|
|
JSC_CCALL(http_getError,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
return JS_NewInt32(js, pd_network->http->getError(js2http(js, argv[0])));
|
|
)
|
|
|
|
JSC_CCALL(http_getProgress,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
int read, total;
|
|
pd_network->http->getProgress(js2http(js, argv[0]), &read, &total);
|
|
JSValue obj = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, obj, "read", JS_NewInt32(js, read));
|
|
JS_SetPropertyStr(js, obj, "total", JS_NewInt32(js, total));
|
|
return obj;
|
|
)
|
|
|
|
JSC_CCALL(http_getResponseStatus,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
return JS_NewInt32(js, pd_network->http->getResponseStatus(js2http(js, argv[0])));
|
|
)
|
|
|
|
JSC_CCALL(http_getBytesAvailable,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
return JS_NewInt64(js, pd_network->http->getBytesAvailable(js2http(js, argv[0])));
|
|
)
|
|
|
|
JSC_CCALL(http_setReadTimeout,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
pd_network->http->setReadTimeout(js2http(js, argv[0]), (int)js2number(js, argv[1]));
|
|
return JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(http_setReadBufferSize,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
pd_network->http->setReadBufferSize(js2http(js, argv[0]), (int)js2number(js, argv[1]));
|
|
return JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(http_read,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
HTTPConnection *conn = js2http(js, argv[0]);
|
|
unsigned int buflen = (unsigned int)js2number(js, argv[1]);
|
|
void *buf = malloc(buflen);
|
|
if (!buf) return JS_ThrowInternalError(js, "malloc failed");
|
|
int read = pd_network->http->read(conn, buf, buflen);
|
|
if (read < 0) {
|
|
free(buf);
|
|
return JS_NULL;
|
|
}
|
|
JSValue blob = js_new_blob_stoned_copy(js, buf, read);
|
|
free(buf);
|
|
return blob;
|
|
)
|
|
|
|
JSC_CCALL(http_close,
|
|
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
|
|
pd_network->http->close(js2http(js, argv[0]));
|
|
return JS_NULL;
|
|
)
|
|
|
|
// --- TCP Functions ---
|
|
|
|
JSC_SCALL(tcp_newConnection,
|
|
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
|
|
int port = (int)js2number(js, argv[1]);
|
|
int usessl = argc > 2 ? JS_ToBool(js, argv[2]) : 0;
|
|
TCPConnection *conn = pd_network->tcp->newConnection(str, port, usessl);
|
|
ret = conn ? JS_NewInt64(js, (int64_t)(intptr_t)conn) : JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(tcp_retain,
|
|
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
|
|
TCPConnection *conn = js2tcp(js, argv[0]);
|
|
TCPConnection *ret_conn = pd_network->tcp->retain(conn);
|
|
return ret_conn ? JS_NewInt64(js, (int64_t)(intptr_t)ret_conn) : JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(tcp_release,
|
|
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
|
|
TCPConnection *conn = js2tcp(js, argv[0]);
|
|
if (conn) pd_network->tcp->release(conn);
|
|
return JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(tcp_getError,
|
|
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
|
|
return JS_NewInt32(js, pd_network->tcp->getError(js2tcp(js, argv[0])));
|
|
)
|
|
|
|
JSC_CCALL(tcp_setConnectTimeout,
|
|
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
|
|
pd_network->tcp->setConnectTimeout(js2tcp(js, argv[0]), (int)js2number(js, argv[1]));
|
|
return JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(tcp_close,
|
|
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
|
|
return JS_NewInt32(js, pd_network->tcp->close(js2tcp(js, argv[0])));
|
|
)
|
|
|
|
JSC_CCALL(tcp_setReadTimeout,
|
|
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
|
|
pd_network->tcp->setReadTimeout(js2tcp(js, argv[0]), (int)js2number(js, argv[1]));
|
|
return JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(tcp_setReadBufferSize,
|
|
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
|
|
pd_network->tcp->setReadBufferSize(js2tcp(js, argv[0]), (int)js2number(js, argv[1]));
|
|
return JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(tcp_getBytesAvailable,
|
|
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
|
|
return JS_NewInt64(js, pd_network->tcp->getBytesAvailable(js2tcp(js, argv[0])));
|
|
)
|
|
|
|
JSC_CCALL(tcp_read,
|
|
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
|
|
TCPConnection *conn = js2tcp(js, argv[0]);
|
|
size_t len = (size_t)js2number(js, argv[1]);
|
|
void *buf = malloc(len);
|
|
if (!buf) return JS_ThrowInternalError(js, "malloc failed");
|
|
int read = pd_network->tcp->read(conn, buf, len);
|
|
if (read < 0) {
|
|
free(buf);
|
|
return JS_NewInt32(js, read); // Return error code
|
|
}
|
|
JSValue blob = js_new_blob_stoned_copy(js, buf, read);
|
|
free(buf);
|
|
return blob;
|
|
)
|
|
|
|
JSC_CCALL(tcp_write,
|
|
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
|
|
TCPConnection *conn = js2tcp(js, argv[0]);
|
|
size_t len;
|
|
const void *data = js_get_blob_data(js, &len, argv[1]);
|
|
if (data == (void*)-1) return JS_EXCEPTION;
|
|
return JS_NewInt32(js, pd_network->tcp->write(conn, data, len));
|
|
)
|
|
|
|
static const JSCFunctionListEntry js_network_funcs[] = {
|
|
MIST_FUNC_DEF(network, getStatus, 0),
|
|
MIST_FUNC_DEF(network, setEnabled, 1),
|
|
// HTTP
|
|
MIST_FUNC_DEF(http, newConnection, 3),
|
|
MIST_FUNC_DEF(http, retain, 1),
|
|
MIST_FUNC_DEF(http, release, 1),
|
|
MIST_FUNC_DEF(http, setConnectTimeout, 2),
|
|
MIST_FUNC_DEF(http, setKeepAlive, 2),
|
|
MIST_FUNC_DEF(http, setByteRange, 3),
|
|
MIST_FUNC_DEF(http, get, 3),
|
|
MIST_FUNC_DEF(http, post, 4),
|
|
MIST_FUNC_DEF(http, getError, 1),
|
|
MIST_FUNC_DEF(http, getProgress, 1),
|
|
MIST_FUNC_DEF(http, getResponseStatus, 1),
|
|
MIST_FUNC_DEF(http, getBytesAvailable, 1),
|
|
MIST_FUNC_DEF(http, setReadTimeout, 2),
|
|
MIST_FUNC_DEF(http, setReadBufferSize, 2),
|
|
MIST_FUNC_DEF(http, read, 2),
|
|
MIST_FUNC_DEF(http, close, 1),
|
|
// TCP
|
|
MIST_FUNC_DEF(tcp, newConnection, 3),
|
|
MIST_FUNC_DEF(tcp, retain, 1),
|
|
MIST_FUNC_DEF(tcp, release, 1),
|
|
MIST_FUNC_DEF(tcp, getError, 1),
|
|
MIST_FUNC_DEF(tcp, setConnectTimeout, 2),
|
|
MIST_FUNC_DEF(tcp, close, 1),
|
|
MIST_FUNC_DEF(tcp, setReadTimeout, 2),
|
|
MIST_FUNC_DEF(tcp, setReadBufferSize, 2),
|
|
MIST_FUNC_DEF(tcp, getBytesAvailable, 1),
|
|
MIST_FUNC_DEF(tcp, read, 2),
|
|
MIST_FUNC_DEF(tcp, write, 2),
|
|
};
|
|
|
|
JSValue js_network_use(JSContext *js) {
|
|
JSValue mod = JS_NewObject(js);
|
|
JS_SetPropertyFunctionList(js, mod, js_network_funcs, countof(js_network_funcs));
|
|
// Export constants
|
|
JS_SetPropertyStr(js, mod, "NET_OK", JS_NewInt32(js, NET_OK));
|
|
JS_SetPropertyStr(js, mod, "NET_NO_DEVICE", JS_NewInt32(js, NET_NO_DEVICE));
|
|
JS_SetPropertyStr(js, mod, "NET_BUSY", JS_NewInt32(js, NET_BUSY));
|
|
JS_SetPropertyStr(js, mod, "NET_WRITE_ERROR", JS_NewInt32(js, NET_WRITE_ERROR));
|
|
JS_SetPropertyStr(js, mod, "NET_READ_ERROR", JS_NewInt32(js, NET_READ_ERROR));
|
|
JS_SetPropertyStr(js, mod, "NET_CONNECTION_CLOSED", JS_NewInt32(js, NET_CONNECTION_CLOSED));
|
|
JS_SetPropertyStr(js, mod, "WIFI_NOT_CONNECTED", JS_NewInt32(js, kWifiNotConnected));
|
|
JS_SetPropertyStr(js, mod, "WIFI_CONNECTED", JS_NewInt32(js, kWifiConnected));
|
|
JS_SetPropertyStr(js, mod, "WIFI_NOT_AVAILABLE", JS_NewInt32(js, kWifiNotAvailable));
|
|
return mod;
|
|
}
|