mirror of
https://github.com/MrLowPr/overdrive.git
synced 2026-10-17 20:01:06 +02:00
73 lines
3.3 KiB
C++
73 lines
3.3 KiB
C++
// Copyright (C) 2026 half144 and PS5 React contributors
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// Additional attribution term: see LICENSE-ATTRIBUTION.
|
|
#include "host_api.hpp"
|
|
#include "lan.hpp"
|
|
#include <cmath>
|
|
#include <cstring>
|
|
|
|
namespace {
|
|
bool integer(JSContext* ctx, JSValueConst value, double minimum, double maximum, double& out) {
|
|
return JS_IsNumber(value) && !JS_ToFloat64(ctx, &out, value) && std::isfinite(out) && out == std::floor(out) &&
|
|
out >= minimum && out <= maximum;
|
|
}
|
|
|
|
JSValue broadcast(JSContext* ctx, JSValueConst, int argc, JSValueConst* argv) {
|
|
double port = 0, timeout = 0, replies = 0;
|
|
std::size_t size = 0;
|
|
const char* bytes = argc >= 2 && JS_IsString(argv[1]) ? JS_ToCStringLen(ctx, &size, argv[1]) : nullptr;
|
|
std::string message;
|
|
if (bytes) {
|
|
if (size && size <= lan::kMaxMessageBytes) message.assign(bytes, size);
|
|
JS_FreeCString(ctx, bytes);
|
|
}
|
|
if (argc < 4 || !integer(ctx, argv[0], 1, 65535, port) || message.empty() ||
|
|
!integer(ctx, argv[2], lan::kMinTimeoutMs, lan::kMaxTimeoutMs, timeout) ||
|
|
!integer(ctx, argv[3], 1, lan::kMaxReplies, replies))
|
|
return JS_ThrowTypeError(ctx, "lan.broadcast: expected port 1..65535, a message of 1..%zu bytes, %d..%d ms and 1..%u replies",
|
|
lan::kMaxMessageBytes, lan::kMinTimeoutMs, lan::kMaxTimeoutMs, lan::kMaxReplies);
|
|
std::string error;
|
|
const auto id = lan::broadcast(static_cast<std::uint16_t>(port), std::move(message), static_cast<int>(timeout),
|
|
static_cast<unsigned>(replies), error);
|
|
return id ? JS_NewUint32(ctx, id) : JS_ThrowPlainError(ctx, "lan.broadcast %d: %s", static_cast<int>(port), error.c_str());
|
|
}
|
|
|
|
JSValue cancel(JSContext* ctx, JSValueConst, int argc, JSValueConst* argv) {
|
|
std::uint32_t id = 0;
|
|
if (!argc || JS_ToUint32(ctx, &id, argv[0])) return JS_ThrowTypeError(ctx, "lan.cancel: expected task id");
|
|
lan::cancel(id);
|
|
return JS_UNDEFINED;
|
|
}
|
|
|
|
JSValue poll(JSContext* ctx, JSValueConst, int, JSValueConst*) {
|
|
JSValue out = JS_NewArray(ctx);
|
|
std::uint32_t index = 0;
|
|
for (const auto& snapshot : lan::poll()) {
|
|
JSValue item = JS_NewObject(ctx);
|
|
JS_SetPropertyStr(ctx, item, "id", JS_NewUint32(ctx, snapshot.id));
|
|
JS_SetPropertyStr(ctx, item, "state", JS_NewString(ctx, snapshot.state.c_str()));
|
|
JS_SetPropertyStr(ctx, item, "error", JS_NewString(ctx, snapshot.error.c_str()));
|
|
JSValue replies = JS_NewArray(ctx);
|
|
std::uint32_t at = 0;
|
|
for (const auto& reply : snapshot.replies) {
|
|
JSValue entry = JS_NewObject(ctx);
|
|
JS_SetPropertyStr(ctx, entry, "address", JS_NewString(ctx, reply.address.c_str()));
|
|
JS_SetPropertyStr(ctx, entry, "port", JS_NewUint32(ctx, reply.port));
|
|
JS_SetPropertyStr(ctx, entry, "body", JS_NewStringLen(ctx, reply.body.data(), reply.body.size()));
|
|
JS_SetPropertyUint32(ctx, replies, at++, entry);
|
|
}
|
|
JS_SetPropertyStr(ctx, item, "replies", replies);
|
|
JS_SetPropertyUint32(ctx, out, index++, item);
|
|
}
|
|
return out;
|
|
}
|
|
} // namespace
|
|
|
|
JSValue ps5_react_lan_api(JSContext* ctx) {
|
|
JSValue api = JS_NewObject(ctx);
|
|
JS_SetPropertyStr(ctx, api, "broadcast", JS_NewCFunction(ctx, broadcast, "broadcast", 4));
|
|
JS_SetPropertyStr(ctx, api, "cancel", JS_NewCFunction(ctx, cancel, "cancel", 1));
|
|
JS_SetPropertyStr(ctx, api, "poll", JS_NewCFunction(ctx, poll, "poll", 0));
|
|
return api;
|
|
}
|