// 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 #include // --- 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_UNDEFINED; ) // --- 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_UNDEFINED; ) 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_UNDEFINED; ) 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_UNDEFINED; ) 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_UNDEFINED; ) 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_UNDEFINED; ) 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_UNDEFINED; ) 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_UNDEFINED; ) // --- 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_UNDEFINED; ) 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_UNDEFINED; ) 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_UNDEFINED; ) 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_UNDEFINED; ) 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; }