diff --git a/binding.gyp b/binding.gyp index 538e054..42b5f4c 100644 --- a/binding.gyp +++ b/binding.gyp @@ -5,6 +5,7 @@ "sources": [ "lib/main.cc", "lib/client.cc", + "lib/client_peer.cc", "'lib/include/'+file).join(' ')\")", "'lib/src/'+file).join(' ')\")" ], diff --git a/lib/client.cc b/lib/client.cc index f913ab0..795b684 100644 --- a/lib/client.cc +++ b/lib/client.cc @@ -1,4 +1,5 @@ #include +#include Napi::FunctionReference Client::constructor; @@ -218,22 +219,26 @@ Napi::Value Client::connect(NAPI_CB) return Napi::Boolean::New(env, true); } -Napi::Value Client::getPeerState(NAPI_CB) +Napi::Value Client::getPeer(NAPI_CB) { Napi::Env env = info.Env(); uint32_t peerID = info[0].As().Uint32Value(); - ENetPeer *peer = this->peers[peerID]; - return Napi::Number::New(env, peer->state); -} + if (this->peers.find(peerID) == this->peers.end()) + { + Napi::TypeError::New(env, "Invalid peer ID").ThrowAsJavaScriptException(); + return env.Null(); + } -Napi::Value Client::getPeerRTT(NAPI_CB) -{ - Napi::Env env = info.Env(); - uint32_t peerID = info[0].As().Uint32Value(); - ENetPeer *peer = this->peers[peerID]; + ENetPeer *enetPeer = this->peers[peerID]; + + Napi::Function peerConstructor = env.GetInstanceData()->Value(); + Napi::Object peerObj = peerConstructor.New({}); + ClientPeer *peer = Napi::ObjectWrap::Unwrap(peerObj); + + peer->SetENetPeer(enetPeer); - return Napi::Number::New(env, peer->roundTripTime); + return peerObj; } Napi::Object Client::Init(Napi::Env env, Napi::Object exports) @@ -251,8 +256,7 @@ Napi::Object Client::Init(Napi::Env env, Napi::Object exports) InstanceMethod<&Client::disconnectLater>("disconnectLater"), InstanceMethod<&Client::disconnectNow>("disconnectNow"), InstanceMethod<&Client::toggleNewPacket>("toggleNewPacket"), - InstanceMethod<&Client::getPeerRTT>("getPeerRTT"), - InstanceMethod<&Client::getPeerState>("getPeerState"), + InstanceMethod<&Client::getPeer>("getPeer"), InstanceMethod<&Client::connect>("connect") }); // clang-format on diff --git a/lib/client_peer.cc b/lib/client_peer.cc new file mode 100644 index 0000000..d304925 --- /dev/null +++ b/lib/client_peer.cc @@ -0,0 +1,109 @@ +#include +#include + +ClientPeer::ClientPeer(NAPI_CB) : Napi::ObjectWrap(info), peer(nullptr) {} + +Napi::Value ClientPeer::GetRTT(NAPI_CB) +{ + Napi::Env env = info.Env(); + return Napi::Number::New(env, peer->roundTripTime); +} + +Napi::Value ClientPeer::GetState(NAPI_CB) +{ + Napi::Env env = info.Env(); + return Napi::Number::New(env, peer->state); +} + +Napi::Value ClientPeer::GetChannelCount(NAPI_CB) +{ + Napi::Env env = info.Env(); + return Napi::Number::New(env, peer->channelCount); +} + +Napi::Value ClientPeer::GetConnectID(NAPI_CB) +{ + Napi::Env env = info.Env(); + return Napi::Number::New(env, peer->connectID); +} + +Napi::Value ClientPeer::GetIncomingBandwidth(NAPI_CB) +{ + Napi::Env env = info.Env(); + return Napi::Number::New(env, peer->incomingBandwidth); +} + +Napi::Value ClientPeer::GetOutgoingBandwidth(NAPI_CB) +{ + Napi::Env env = info.Env(); + return Napi::Number::New(env, peer->outgoingBandwidth); +} + +Napi::Value ClientPeer::GetPacketsLost(NAPI_CB) +{ + Napi::Env env = info.Env(); + return Napi::Number::New(env, peer->packetsLost); +} + +Napi::Value ClientPeer::GetPacketsSent(NAPI_CB) +{ + Napi::Env env = info.Env(); + return Napi::Number::New(env, peer->packetsSent); +} + +Napi::Value ClientPeer::GetPacketLoss(NAPI_CB) +{ + Napi::Env env = info.Env(); + return Napi::Number::New(env, peer->packetLoss); +} + +Napi::Value ClientPeer::GetTotalWaitingData(NAPI_CB) +{ + Napi::Env env = info.Env(); + return Napi::Number::New(env, peer->totalWaitingData); +} + +Napi::Value ClientPeer::GetAddress(NAPI_CB) +{ + Napi::Env env = info.Env(); + + Napi::Object obj = Napi::Object::New(env); + + char ipStr[INET_ADDRSTRLEN]; + if (inet_ntop(AF_INET, &(peer->address.host), ipStr, INET_ADDRSTRLEN) == NULL) + { + Napi::Error::New(env, "Failed to convert IP address").ThrowAsJavaScriptException(); + return env.Null(); + } + + obj.Set("address", Napi::String::New(env, ipStr)); + obj.Set("port", Napi::Number::New(env, peer->address.port)); + return obj; +} + +Napi::Object ClientPeer::Init(Napi::Env env, Napi::Object exports) +{ + + // clang-format off + Napi::Function func = DefineClass(env, "Peer", { + InstanceMethod("getRTT", &ClientPeer::GetRTT), + InstanceMethod("getState", &ClientPeer::GetState), + InstanceMethod("getChannelCount", &ClientPeer::GetChannelCount), + InstanceMethod("getConnectID", &ClientPeer::GetConnectID), + InstanceMethod("getIncomingBandwidth", &ClientPeer::GetIncomingBandwidth), + InstanceMethod("getOutgoingBandwidth", &ClientPeer::GetOutgoingBandwidth), + InstanceMethod("getPacketsLost", &ClientPeer::GetPacketsLost), + InstanceMethod("getPacketsSent", &ClientPeer::GetPacketsSent), + InstanceMethod("getPacketLoss", &ClientPeer::GetPacketLoss), + InstanceMethod("getTotalWaitingData", &ClientPeer::GetTotalWaitingData), + InstanceMethod("getAddress", &ClientPeer::GetAddress) + }); + // clang-format on + + Napi::FunctionReference *constructor = new Napi::FunctionReference(); + *constructor = Napi::Persistent(func); + exports.Set("Peer", func); + env.SetInstanceData(constructor); + + return exports; +} \ No newline at end of file diff --git a/lib/include/client.h b/lib/include/client.h index 2628571..7beca63 100644 --- a/lib/include/client.h +++ b/lib/include/client.h @@ -29,13 +29,8 @@ class Client : public Napi::ObjectWrap void disconnectNow(NAPI_CB); void toggleNewPacket(NAPI_CB); - ENetPeer *getPeer(uint32_t peerID); Napi::Value connect(NAPI_CB); - - Napi::Value getPeerRTT(NAPI_CB); - Napi::Value getPeerState(NAPI_CB); - // Napi::Value getPeerPing(NAPI_CB); - // Napi::Value getPeerPing(NAPI_CB); + Napi::Value getPeer(NAPI_CB); private: Napi::FunctionReference eventEmit; diff --git a/lib/include/client_peer.h b/lib/include/client_peer.h new file mode 100644 index 0000000..4206a9e --- /dev/null +++ b/lib/include/client_peer.h @@ -0,0 +1,38 @@ +#include +#include + +#ifdef _WIN32 +// Windows specific headers and code +#include +#include // for InetNtop +#else +// Unix-like specific headers and code +#include +#endif + +#define NAPI_CB const Napi::CallbackInfo &info + +class ClientPeer : public Napi::ObjectWrap +{ +public: + static Napi::Object Init(Napi::Env env, Napi::Object exports); + ClientPeer(NAPI_CB); + + void SetENetPeer(ENetPeer *peer) { this->peer = peer; } + +private: + Napi::Value GetRTT(NAPI_CB); + Napi::Value GetState(NAPI_CB); + Napi::Value GetChannelCount(NAPI_CB); + Napi::Value GetConnectID(NAPI_CB); + Napi::Value GetData(NAPI_CB); + Napi::Value GetIncomingBandwidth(NAPI_CB); + Napi::Value GetOutgoingBandwidth(NAPI_CB); + Napi::Value GetPacketsLost(NAPI_CB); + Napi::Value GetPacketsSent(NAPI_CB); + Napi::Value GetPacketLoss(NAPI_CB); + Napi::Value GetTotalWaitingData(NAPI_CB); + Napi::Value GetAddress(NAPI_CB); + + ENetPeer *peer; +}; \ No newline at end of file diff --git a/lib/main.cc b/lib/main.cc index 8bd0dbb..80a72f7 100644 --- a/lib/main.cc +++ b/lib/main.cc @@ -1,7 +1,9 @@ #include +#include Napi::Object init(Napi::Env env, Napi::Object exports) { + ClientPeer::Init(env, exports); return Client::Init(env, exports); } diff --git a/package.json b/package.json index c2ebfb9..d116db6 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "dev": "rimraf dist && npm run build && npm run build:ts && node test/basic-example/index.js", "dev:nonative": "rimraf dist && npm run build:ts", "docs:gen": "rimraf docs && typedoc", - "build": "prebuildify --napi", + "build:prebuild": "prebuildify --napi", + "build": "node-gyp-build", "build:ts": "tsc", "install": "node-gyp-build" }, diff --git a/prebuilds/win32-x64/growtopia.js.node b/prebuilds/win32-x64/growtopia.js.node index bec1aec..2fad281 100644 Binary files a/prebuilds/win32-x64/growtopia.js.node and b/prebuilds/win32-x64/growtopia.js.node differ diff --git a/src/structures/Client.ts b/src/structures/Client.ts index f83a05a..361de82 100644 --- a/src/structures/Client.ts +++ b/src/structures/Client.ts @@ -6,8 +6,15 @@ import { Peer } from "./Peer.js"; import type { ActionEvent, LoginInfo, PeerData } from "../../types"; import { TankPacket } from "../packets/TankPacket.js"; import { WebServer } from "./WebServer.js"; -import { createRequire } from "node:module"; -const Native = createRequire(import.meta.url)("../../build/Release/gtjs.node").Client; +import { dirname, join } from "path"; +import { fileURLToPath } from "url"; + +// @ts-expect-error @types/node-gyp-build not existed +import nodegyp from "node-gyp-build"; +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const Native = nodegyp(join(__dirname, "..", "..")).Client; +console.log({ Native }); class Client extends EventEmitter { public _client: ClientType; @@ -35,8 +42,6 @@ class Client extends EventEmitter { } }; - this.config.plugins; - this._client = new Native(this.config.enet?.ip, this.config.enet?.port) as ClientType; this.cache = { diff --git a/src/structures/Peer.ts b/src/structures/Peer.ts index 863340b..4ab102e 100644 --- a/src/structures/Peer.ts +++ b/src/structures/Peer.ts @@ -13,20 +13,6 @@ class Peer { this.client = client; } - /** - * Get ENetPeer Round Trip Time (RTT). - */ - public get ping() { - return this.client._client.getPeerRTT(this.data.netID); - } - - /** - * Get [ENetPeerState](http://enet.bespin.org/enet_8h.html#a058bc368c507eb86cb47f3946f38d558). - */ - public get state() { - return this.client._client.getPeerState(this.data.netID); - } - /** * Sends multiple packets to a single peer. * @param data An argument of packets that contains the `parse()` function or just an array of Buffers. diff --git a/test/basic-example/index.js b/test/basic-example/index.js index b70f583..26cbec5 100644 --- a/test/basic-example/index.js +++ b/test/basic-example/index.js @@ -17,6 +17,11 @@ client.on("error", (err) => { }); client.on("connect", (netID) => { + const enetPeer = client._client.getPeer(netID); + + console.log({ ping: enetPeer.getRTT() }); + console.log(enetPeer.getAddress()); + console.log(`Connected netID ${netID}`); const peer = new Peer(client, netID); peer.send(TextPacket.from(0x1)); @@ -29,7 +34,6 @@ client.on("disconnect", (netID) => { client.on("raw", (netID, data) => { const peer = new Peer(client, netID); console.log("raw", data); - console.log(peer.ping, peer.state); }); client.on("action", (peer, data) => { diff --git a/types/client.d.ts b/types/client.d.ts index 4ca21e6..dac4990 100644 --- a/types/client.d.ts +++ b/types/client.d.ts @@ -12,11 +12,9 @@ export interface ClientType { disconnectLater: (peerID: number) => void; disconnectNow: (peerID: number) => void; toggleNewPacket: () => void; - getPeerRTT: (peerID: number) => number; /** * Return [ENetPeerState](http://enet.bespin.org/enet_8h.html#a058bc368c507eb86cb47f3946f38d558) enum value */ - getPeerState: (peerID: number) => number; connect: (ipAddress: string, port: number, peerID: number) => boolean; } diff --git a/types/index.d.ts b/types/index.d.ts index 5d38778..0376f44 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,8 +1,5 @@ -export interface PeerData { - netID: number; -} - export * from "./client"; export * from "./packets"; export * from "./events"; export * from "./items"; +export * from "./peer"; diff --git a/types/peer.d.ts b/types/peer.d.ts new file mode 100644 index 0000000..350d701 --- /dev/null +++ b/types/peer.d.ts @@ -0,0 +1,22 @@ +export interface NativePeerMethod { + getRTT: () => number; + getState: () => number; + getChannelCount: () => number; + getConnectID: () => number; + getIncomingBandwidth: () => unknown; + getOutgoingBandwidth: () => number; + getPacketsLost: () => number; + getPacketsSent: () => number; + getTotalWaitingData: () => number; + getAddress: () => NativeAddress; +} + +export interface NativePeerAddress { + address: string; + host: number; +} + +export interface PeerData { + netID: number; + enet: NativePeerMethod; +}