648 lines
25 KiB
C++
648 lines
25 KiB
C++
#include "network/Network.h"
|
|
#include "data/ByteData.h"
|
|
#include "network/Channel.h"
|
|
#include "network/HttpRequest.h"
|
|
#include "network/NetHost.h"
|
|
#include "network/NetRpc.h"
|
|
#include "network/NetStream.h"
|
|
#include "network/NetWorker.h"
|
|
#include "network/Session.h"
|
|
#include "network/TcpSocket.h"
|
|
#include "network/UdpLink.h"
|
|
#include "network/UdpSocket.h"
|
|
#include "platform_event/PlatformEvent.h"
|
|
|
|
#include <Poco/Net/StreamSocket.h>
|
|
#include <Poco/Net/ServerSocket.h>
|
|
#include <Poco/Net/DatagramSocket.h>
|
|
#include <Poco/Net/SocketAddress.h>
|
|
#include <Poco/Net/NetException.h>
|
|
#include <Poco/Exception.h>
|
|
|
|
#include <simplesquirrel/simplesquirrel.hpp>
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <functional>
|
|
#include <thread>
|
|
|
|
namespace eve::network {
|
|
|
|
namespace {
|
|
|
|
void callScript2(const ssq::Object& obj, int64_t a, const std::string& s) {
|
|
if (obj.isEmpty()) return;
|
|
ssq::Function f = obj.toFunction();
|
|
if (f.isEmpty()) return;
|
|
HSQUIRRELVM raw = f.getHandle();
|
|
SQInteger top = sq_gettop(raw);
|
|
sq_pushobject(raw, f.getRaw());
|
|
sq_pushroottable(raw);
|
|
ssq::detail::pushValue(raw, a);
|
|
ssq::detail::pushValue(raw, s);
|
|
sq_call(raw, 3, SQFalse, SQTrue);
|
|
sq_settop(raw, top);
|
|
}
|
|
|
|
void callScript3(const ssq::Object& obj, int64_t a, int64_t b, const std::string& s) {
|
|
if (obj.isEmpty()) return;
|
|
ssq::Function f = obj.toFunction();
|
|
if (f.isEmpty()) return;
|
|
HSQUIRRELVM raw = f.getHandle();
|
|
SQInteger top = sq_gettop(raw);
|
|
sq_pushobject(raw, f.getRaw());
|
|
sq_pushroottable(raw);
|
|
ssq::detail::pushValue(raw, a);
|
|
ssq::detail::pushValue(raw, b);
|
|
ssq::detail::pushValue(raw, s);
|
|
sq_call(raw, 4, SQFalse, SQTrue);
|
|
sq_settop(raw, top);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Module_IMPL(Network, new Network());
|
|
|
|
Network::Network() {
|
|
worker_ = std::make_unique<NetWorker>(this);
|
|
worker_->start();
|
|
eve::cap::provide<eve::service::INetwork>(this);
|
|
}
|
|
|
|
Network::~Network() {
|
|
if (worker_) worker_->stop();
|
|
worker_.reset();
|
|
}
|
|
|
|
std::unique_ptr<TcpSocket> Network::makeTcp() { return std::make_unique<TcpSocket>(this); }
|
|
TcpSocket* Network::newTcp() { return makeTcp().release(); }
|
|
|
|
std::unique_ptr<UdpSocket> Network::makeUdp() { return std::make_unique<UdpSocket>(this); }
|
|
UdpSocket* Network::newUdp() { return makeUdp().release(); }
|
|
|
|
std::unique_ptr<HttpRequest> Network::makeHttp(std::string method, std::string url) {
|
|
return std::make_unique<HttpRequest>(this, std::move(method), std::move(url));
|
|
}
|
|
HttpRequest* Network::newHttp(std::string method, std::string url) {
|
|
return makeHttp(std::move(method), std::move(url)).release();
|
|
}
|
|
|
|
bool Network::httpRequest(const std::string& method, const std::string& url,
|
|
const std::string& body, int timeoutMs, int& status,
|
|
std::string& responseBody) {
|
|
auto ownedRequest = makeHttp(method, url);
|
|
HttpRequest* req = ownedRequest.get();
|
|
if (!body.empty()) req->setBodyString(body);
|
|
req->setTimeout(timeoutMs > 0 ? timeoutMs : 10000);
|
|
if (!req->submit()) return false;
|
|
|
|
const auto deadline = std::chrono::steady_clock::now() +
|
|
std::chrono::milliseconds(timeoutMs > 0 ? timeoutMs : 1);
|
|
while (std::chrono::steady_clock::now() < deadline) {
|
|
std::vector<NetCompletion> out;
|
|
drainCompletions(out);
|
|
for (const auto& c : out) {
|
|
if (c.handle != req) continue;
|
|
if (c.type == NetEvType::HttpResp) {
|
|
status = c.status;
|
|
if (c.bytes) responseBody.assign(c.bytes->begin(), c.bytes->end());
|
|
return true;
|
|
}
|
|
if (c.type == NetEvType::Err) return false;
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::unique_ptr<Channel> Network::makeChannel(TcpSocket* socket) {
|
|
if (!socket) return nullptr;
|
|
auto ch = std::make_unique<Channel>(socket);
|
|
bindChannel(socket, ch.get());
|
|
return ch;
|
|
}
|
|
Channel* Network::newChannel(TcpSocket* socket) { return makeChannel(socket).release(); }
|
|
|
|
std::unique_ptr<Session> Network::makeSession() { return std::make_unique<Session>(); }
|
|
Session* Network::newSession() { return makeSession().release(); }
|
|
|
|
std::unique_ptr<NetWriter> Network::makeWriter() { return std::make_unique<NetWriter>(); }
|
|
NetWriter* Network::newWriter() { return makeWriter().release(); }
|
|
|
|
std::unique_ptr<NetReader> Network::makeReader(std::string bytes) {
|
|
auto r = std::make_unique<NetReader>();
|
|
r->setBytes(std::move(bytes));
|
|
return r;
|
|
}
|
|
NetReader* Network::newReader(std::string bytes) { return makeReader(std::move(bytes)).release(); }
|
|
|
|
std::unique_ptr<UdpLink> Network::makeUdpLink(UdpSocket* socket) {
|
|
if (!socket) return nullptr;
|
|
auto link = std::make_unique<UdpLink>(this, socket);
|
|
bindUdpLink(socket, link.get());
|
|
return link;
|
|
}
|
|
UdpLink* Network::newUdpLink(UdpSocket* socket) { return makeUdpLink(socket).release(); }
|
|
|
|
std::unique_ptr<NetRpc> Network::makeRpc(UdpLink* link) {
|
|
return link ? std::make_unique<NetRpc>(link) : nullptr;
|
|
}
|
|
NetRpc* Network::newRpc(UdpLink* link) { return makeRpc(link).release(); }
|
|
|
|
std::unique_ptr<NetHost> Network::makeHost() { return std::make_unique<NetHost>(this); }
|
|
NetHost* Network::newHost() { return makeHost().release(); }
|
|
|
|
void Network::bindUdpLink(UdpSocket* sock, UdpLink* link) {
|
|
if (sock) udpLinks_[sock] = link;
|
|
}
|
|
|
|
void Network::unbindUdpLink(UdpSocket* sock) {
|
|
if (sock) udpLinks_.erase(sock);
|
|
}
|
|
|
|
void Network::bindUdpHost(UdpSocket* sock, NetHost* host) {
|
|
if (sock) udpHosts_[sock] = host;
|
|
}
|
|
|
|
void Network::unbindUdpHost(UdpSocket* sock) {
|
|
if (sock) udpHosts_.erase(sock);
|
|
}
|
|
|
|
void Network::setTimeout(int ms) {
|
|
timeoutMs_ = ms;
|
|
}
|
|
|
|
int Network::getTimeout() const {
|
|
return timeoutMs_;
|
|
}
|
|
|
|
void Network::setVerifySsl(bool verify) {
|
|
verifySsl_ = verify;
|
|
}
|
|
|
|
bool Network::getVerifySsl() const {
|
|
return verifySsl_;
|
|
}
|
|
|
|
void Network::post(NetCompletion c) {
|
|
++completions_;
|
|
++telemetryRevision_;
|
|
if (c.bytes && (c.type == NetEvType::Data || c.type == NetEvType::HttpResp))
|
|
receivedBytes_ += c.bytes->size();
|
|
if (c.type == NetEvType::Err) ++errors_;
|
|
if (c.type == NetEvType::Conn && c.reason == "ok") ++connections_;
|
|
if (worker_) worker_->post(std::move(c));
|
|
}
|
|
|
|
void Network::recordSent(size_t bytes) {
|
|
sentBytes_ += bytes;
|
|
++telemetryRevision_;
|
|
}
|
|
|
|
NetTelemetrySnapshot Network::telemetrySnapshot() const {
|
|
NetTelemetrySnapshot result;
|
|
result.revision = telemetryRevision_.load();
|
|
result.sentBytes = sentBytes_.load();
|
|
result.receivedBytes = receivedBytes_.load();
|
|
result.completions = completions_.load();
|
|
result.errors = errors_.load();
|
|
result.connections = connections_.load();
|
|
{
|
|
std::lock_guard<std::mutex> lock(watchMu_);
|
|
result.watchedTcp = watchedTcp_.size();
|
|
result.watchedUdp = watchedUdp_.size();
|
|
for (const auto* socket : watchedTcp_) if (socket) result.queuedTcpBytes += socket->pendingSendBytes();
|
|
}
|
|
{
|
|
std::lock_guard<std::mutex> lock(channelMu_);
|
|
result.channels = channels_.size();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void Network::resetTelemetry() {
|
|
sentBytes_ = receivedBytes_ = completions_ = errors_ = connections_ = 0;
|
|
++telemetryRevision_;
|
|
}
|
|
|
|
void Network::drainCompletions(std::vector<NetCompletion>& out) {
|
|
if (worker_) worker_->drain(out);
|
|
}
|
|
|
|
void Network::watchTcp(TcpSocket* sock) {
|
|
std::lock_guard<std::mutex> lock(watchMu_);
|
|
if (std::find(watchedTcp_.begin(), watchedTcp_.end(), sock) == watchedTcp_.end()) {
|
|
watchedTcp_.push_back(sock);
|
|
++telemetryRevision_;
|
|
}
|
|
}
|
|
|
|
void Network::unwatchTcp(TcpSocket* sock) {
|
|
std::lock_guard<std::mutex> lock(watchMu_);
|
|
const auto before=watchedTcp_.size();
|
|
watchedTcp_.erase(std::remove(watchedTcp_.begin(), watchedTcp_.end(), sock), watchedTcp_.end());
|
|
if(before!=watchedTcp_.size())++telemetryRevision_;
|
|
}
|
|
|
|
void Network::watchUdp(UdpSocket* sock) {
|
|
std::lock_guard<std::mutex> lock(watchMu_);
|
|
if (std::find(watchedUdp_.begin(), watchedUdp_.end(), sock) == watchedUdp_.end()) {
|
|
watchedUdp_.push_back(sock);
|
|
++telemetryRevision_;
|
|
}
|
|
}
|
|
|
|
void Network::unwatchUdp(UdpSocket* sock) {
|
|
std::lock_guard<std::mutex> lock(watchMu_);
|
|
const auto before=watchedUdp_.size();
|
|
watchedUdp_.erase(std::remove(watchedUdp_.begin(), watchedUdp_.end(), sock), watchedUdp_.end());
|
|
if(before!=watchedUdp_.size())++telemetryRevision_;
|
|
}
|
|
|
|
void Network::bindChannel(TcpSocket* sock, Channel* ch) {
|
|
std::lock_guard<std::mutex> lock(channelMu_);
|
|
channels_[sock] = ch;
|
|
++telemetryRevision_;
|
|
}
|
|
|
|
void Network::unbindChannel(TcpSocket* sock) {
|
|
std::lock_guard<std::mutex> lock(channelMu_);
|
|
if(channels_.erase(sock))++telemetryRevision_;
|
|
}
|
|
|
|
Channel* Network::channelFor(TcpSocket* sock) const {
|
|
std::lock_guard<std::mutex> lock(channelMu_);
|
|
auto it = channels_.find(sock);
|
|
return it == channels_.end() ? nullptr : it->second;
|
|
}
|
|
|
|
void Network::pollSockets() {
|
|
std::vector<TcpSocket*> tcpCopy;
|
|
std::vector<UdpSocket*> udpCopy;
|
|
{
|
|
std::lock_guard<std::mutex> lock(watchMu_);
|
|
tcpCopy = watchedTcp_;
|
|
udpCopy = watchedUdp_;
|
|
}
|
|
for (TcpSocket* sock : tcpCopy) {
|
|
if (!sock) continue;
|
|
if (sock->isListening() && sock->server()) {
|
|
try {
|
|
Poco::Net::StreamSocket ss = sock->server()->acceptConnection();
|
|
ss.setBlocking(false);
|
|
auto peer = std::make_unique<TcpSocket>(this);
|
|
auto stream = std::make_unique<Poco::Net::StreamSocket>(ss);
|
|
peer->setConnectedSocket(std::move(stream));
|
|
TcpSocket* raw = peer.get();
|
|
sock->pushAccepted(std::move(peer));
|
|
watchTcp(raw);
|
|
NetCompletion c;
|
|
c.type = NetEvType::Conn;
|
|
c.kind = NetKind::Tcp;
|
|
c.handle = raw;
|
|
c.reason = "ok";
|
|
c.peer = raw->getPeer();
|
|
post(std::move(c));
|
|
} catch (...) {
|
|
}
|
|
}
|
|
if (sock->isConnected() && sock->stream()) {
|
|
sock->flushSend();
|
|
try {
|
|
char buf[64 * 1024];
|
|
int n = sock->stream()->receiveBytes(buf, sizeof(buf));
|
|
if (n > 0) {
|
|
NetCompletion c;
|
|
c.type = NetEvType::Data;
|
|
c.kind = NetKind::Tcp;
|
|
c.handle = sock;
|
|
c.bytes = std::make_shared<std::vector<char>>(buf, buf + n);
|
|
c.peer = sock->getPeer();
|
|
post(std::move(c));
|
|
} else if (n == 0) {
|
|
NetCompletion c;
|
|
c.type = NetEvType::Err;
|
|
c.kind = NetKind::Tcp;
|
|
c.handle = sock;
|
|
c.reason = "closed";
|
|
post(std::move(c));
|
|
unwatchTcp(sock);
|
|
}
|
|
} catch (const Poco::Exception&) {
|
|
} catch (...) {
|
|
}
|
|
}
|
|
}
|
|
for (UdpSocket* sock : udpCopy) {
|
|
if (!sock || !sock->datagram()) continue;
|
|
for (int i = 0; i < 64; ++i) {
|
|
try {
|
|
char buf[64 * 1024];
|
|
Poco::Net::SocketAddress sender;
|
|
int n = sock->datagram()->receiveFrom(buf, sizeof(buf), sender);
|
|
if (n <= 0) break; // would-block
|
|
NetCompletion c;
|
|
c.type = NetEvType::Data;
|
|
c.kind = NetKind::Udp;
|
|
c.handle = sock;
|
|
c.bytes = std::make_shared<std::vector<char>>(buf, buf + n);
|
|
c.peer = sender.toString();
|
|
post(std::move(c));
|
|
} catch (const Poco::Exception&) {
|
|
break;
|
|
} catch (...) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Network::emitCompletion(const NetCompletion& c) {
|
|
auto* ev = eve::ModuleManager::getInstance<eve::platform_event::PlatformEvent>("PlatformEvent");
|
|
if (!ev) return;
|
|
|
|
using eve::platform_event::Message;
|
|
using eve::platform_event::Variant;
|
|
|
|
std::vector<Variant> args;
|
|
switch (c.type) {
|
|
case NetEvType::Conn:
|
|
args.push_back(Variant::makePtr(c.handle));
|
|
args.push_back(Variant::makeString(c.reason.empty() ? "ok" : c.reason));
|
|
ev->push(std::make_unique<Message>("netconn", args));
|
|
break;
|
|
case NetEvType::Data: {
|
|
Channel* ch = channelFor(static_cast<TcpSocket*>(c.handle));
|
|
if (ch && c.bytes) {
|
|
ch->feed(*c.bytes);
|
|
return;
|
|
}
|
|
eve::data::ByteData* bd = nullptr;
|
|
if (c.bytes && !c.bytes->empty())
|
|
bd = new eve::data::ByteData(c.bytes->data(), c.bytes->size());
|
|
args.push_back(Variant::makePtr(c.handle));
|
|
args.push_back(Variant::makeOwnedPtr(bd));
|
|
args.push_back(Variant::makeString(c.peer));
|
|
ev->push(std::make_unique<Message>("netdata", args));
|
|
break;
|
|
}
|
|
case NetEvType::Err: {
|
|
Channel* ch = channelFor(static_cast<TcpSocket*>(c.handle));
|
|
if (ch) {
|
|
args.push_back(Variant::makePtr(ch));
|
|
args.push_back(Variant::makeString(c.reason));
|
|
ev->push(std::make_unique<Message>("chclose", args));
|
|
}
|
|
args.clear();
|
|
args.push_back(Variant::makePtr(c.handle));
|
|
args.push_back(Variant::makeString(c.reason));
|
|
ev->push(std::make_unique<Message>("neterr", args));
|
|
break;
|
|
}
|
|
case NetEvType::HttpResp: {
|
|
eve::data::ByteData* bd = nullptr;
|
|
if (c.bytes && !c.bytes->empty())
|
|
bd = new eve::data::ByteData(c.bytes->data(), c.bytes->size());
|
|
args.push_back(Variant::makePtr(c.handle));
|
|
args.push_back(Variant::makeInt(c.status));
|
|
args.push_back(Variant::makeOwnedPtr(bd));
|
|
ev->push(std::make_unique<Message>("httpresp", args));
|
|
break;
|
|
}
|
|
case NetEvType::ChMsg: {
|
|
eve::data::ByteData* bd = nullptr;
|
|
if (c.bytes && !c.bytes->empty())
|
|
bd = new eve::data::ByteData(c.bytes->data(), c.bytes->size());
|
|
args.push_back(Variant::makePtr(c.handle));
|
|
args.push_back(Variant::makeOwnedPtr(bd));
|
|
ev->push(std::make_unique<Message>("chmsg", args));
|
|
break;
|
|
}
|
|
case NetEvType::ChClose:
|
|
args.push_back(Variant::makePtr(c.handle));
|
|
args.push_back(Variant::makeString(c.reason));
|
|
ev->push(std::make_unique<Message>("chclose", args));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Network::pump() {
|
|
std::vector<NetCompletion> batch;
|
|
if (worker_) worker_->drain(batch);
|
|
const int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
std::chrono::steady_clock::now().time_since_epoch())
|
|
.count();
|
|
for (auto& c : batch) {
|
|
if (c.type == NetEvType::Data && c.kind == NetKind::Udp) {
|
|
auto* sock = static_cast<UdpSocket*>(c.handle);
|
|
auto hit = udpHosts_.find(sock);
|
|
if (hit != udpHosts_.end()) {
|
|
if (c.bytes) hit->second->onDatagram(*c.bytes, c.peer);
|
|
continue;
|
|
}
|
|
auto lit = udpLinks_.find(sock);
|
|
if (lit != udpLinks_.end()) {
|
|
if (c.bytes) lit->second->onDatagram(*c.bytes, c.peer);
|
|
continue;
|
|
}
|
|
}
|
|
emitCompletion(c);
|
|
}
|
|
for (auto& kv : udpHosts_) kv.second->pump(now);
|
|
for (auto& kv : udpLinks_) kv.second->pump(now);
|
|
}
|
|
|
|
void Network::expose(ssq::Table& table) {
|
|
auto cls = table.addClass(name, Network::create, false);
|
|
expose(cls);
|
|
|
|
auto tcp = table.addClass<TcpSocket>(
|
|
"TcpSocket", std::function<TcpSocket*()>([]() { return new TcpSocket(Network::create()); }), true);
|
|
tcp.addFunc("connect", &TcpSocket::connect);
|
|
tcp.addFunc("listen", &TcpSocket::listen);
|
|
tcp.addFunc("accept", &TcpSocket::accept);
|
|
tcp.addFunc("send", &TcpSocket::send);
|
|
tcp.addFunc("sendString", &TcpSocket::sendString);
|
|
tcp.addFunc("close", &TcpSocket::close);
|
|
tcp.addFunc("isConnected", &TcpSocket::isConnected);
|
|
tcp.addFunc("getPeer", &TcpSocket::getPeer);
|
|
|
|
auto udp = table.addClass<UdpSocket>(
|
|
"UdpSocket", std::function<UdpSocket*()>([]() { return new UdpSocket(Network::create()); }), true);
|
|
udp.addFunc("bind", &UdpSocket::bind);
|
|
udp.addFunc("connect", &UdpSocket::connect);
|
|
udp.addFunc("sendTo", &UdpSocket::sendTo);
|
|
udp.addFunc("sendToString", &UdpSocket::sendToString);
|
|
udp.addFunc("send", &UdpSocket::send);
|
|
udp.addFunc("sendString", &UdpSocket::sendString);
|
|
udp.addFunc("close", &UdpSocket::close);
|
|
|
|
auto http = table.addClass<HttpRequest>(
|
|
"HttpRequest",
|
|
std::function<HttpRequest*()>(
|
|
[]() { return new HttpRequest(Network::create(), "GET", "http://127.0.0.1/"); }),
|
|
true);
|
|
http.addFunc("setHeader", &HttpRequest::setHeader);
|
|
http.addFunc("setBody", &HttpRequest::setBody);
|
|
http.addFunc("setBodyString", &HttpRequest::setBodyString);
|
|
http.addFunc("setTimeout", &HttpRequest::setTimeout);
|
|
http.addFunc("setVerifySsl", &HttpRequest::setVerifySsl);
|
|
http.addFunc("submit", &HttpRequest::submit);
|
|
|
|
auto ch = table.addClass<Channel>(
|
|
"Channel", std::function<Channel*()>([]() { return new Channel(nullptr); }), true);
|
|
ch.addFunc("sendMsg", &Channel::sendMsg);
|
|
ch.addFunc("sendMsgString", &Channel::sendMsgString);
|
|
ch.addFunc("getSocket", &Channel::getSocket);
|
|
|
|
auto sess = table.addClass<Session>(
|
|
"Session", std::function<Session*()>([]() { return new Session(); }), true);
|
|
sess.addFunc("add", &Session::add);
|
|
sess.addFunc("get", &Session::get);
|
|
sess.addFunc("remove", &Session::remove);
|
|
sess.addFunc("closeAll", &Session::closeAll);
|
|
|
|
auto writer = table.addClass<NetWriter>(
|
|
"NetWriter", std::function<NetWriter*()>([]() { return new NetWriter(); }), true);
|
|
writer.addFunc("writeU8", [](NetWriter* w, int64_t v) { w->writeU8(static_cast<uint8_t>(v)); });
|
|
writer.addFunc("writeI8", [](NetWriter* w, int64_t v) { w->writeI8(static_cast<int8_t>(v)); });
|
|
writer.addFunc("writeU16", [](NetWriter* w, int64_t v) { w->writeU16(static_cast<uint16_t>(v)); });
|
|
writer.addFunc("writeI16", [](NetWriter* w, int64_t v) { w->writeI16(static_cast<int16_t>(v)); });
|
|
writer.addFunc("writeU32", [](NetWriter* w, int64_t v) { w->writeU32(static_cast<uint32_t>(v)); });
|
|
writer.addFunc("writeI32", [](NetWriter* w, int64_t v) { w->writeI32(static_cast<int32_t>(v)); });
|
|
writer.addFunc("writeU64", [](NetWriter* w, int64_t v) { w->writeU64(static_cast<uint64_t>(v)); });
|
|
writer.addFunc("writeI64", [](NetWriter* w, int64_t v) { w->writeI64(static_cast<int64_t>(v)); });
|
|
writer.addFunc("writeF32", &NetWriter::writeF32);
|
|
writer.addFunc("writeF64", &NetWriter::writeF64);
|
|
writer.addFunc("writeBool", &NetWriter::writeBool);
|
|
writer.addFunc("writeString", &NetWriter::writeString);
|
|
writer.addFunc("writeBytes", [](NetWriter* w, eve::data::ByteData* d) {
|
|
if (d) w->writeBytes(d->getData(), d->getSize());
|
|
});
|
|
writer.addFunc("toString", [](NetWriter* w) { return w->toString(); });
|
|
writer.addFunc("size", [](NetWriter* w) { return static_cast<int64_t>(w->size()); });
|
|
|
|
auto reader = table.addClass<NetReader>(
|
|
"NetReader", std::function<NetReader*()>([]() { return new NetReader(); }), true);
|
|
reader.addFunc("init", [](NetReader* r, eve::data::ByteData* d) {
|
|
return d ? r->init(d->getData(), d->getSize()) : false;
|
|
});
|
|
reader.addFunc("initString", [](NetReader* r, const std::string& s) { return r->setBytes(s); });
|
|
reader.addFunc("u8", [](NetReader* r) { return static_cast<int64_t>(r->u8()); });
|
|
reader.addFunc("i8", [](NetReader* r) { return static_cast<int64_t>(r->i8()); });
|
|
reader.addFunc("u16", [](NetReader* r) { return static_cast<int64_t>(r->u16()); });
|
|
reader.addFunc("i16", [](NetReader* r) { return static_cast<int64_t>(r->i16()); });
|
|
reader.addFunc("u32", [](NetReader* r) { return static_cast<int64_t>(r->u32()); });
|
|
reader.addFunc("i32", [](NetReader* r) { return static_cast<int64_t>(r->i32()); });
|
|
reader.addFunc("u64", [](NetReader* r) { return static_cast<int64_t>(r->u64()); });
|
|
reader.addFunc("i64", [](NetReader* r) { return static_cast<int64_t>(r->i64()); });
|
|
reader.addFunc("f32", &NetReader::f32);
|
|
reader.addFunc("f64", &NetReader::f64);
|
|
reader.addFunc("bool", &NetReader::b);
|
|
reader.addFunc("str", [](NetReader* r) { return r->str(); });
|
|
reader.addFunc("bytes", [](NetReader* r, int64_t n) {
|
|
auto v = r->bytes(static_cast<size_t>(n));
|
|
return std::string(v.data(), v.size());
|
|
});
|
|
reader.addFunc("remaining", [](NetReader* r) { return static_cast<int64_t>(r->remaining()); });
|
|
reader.addFunc("pos", [](NetReader* r) { return static_cast<int64_t>(r->pos()); });
|
|
reader.addFunc("ok", [](NetReader* r) { return r->ok(); });
|
|
|
|
auto link = table.addClass<UdpLink>(
|
|
"UdpLink",
|
|
std::function<UdpLink*()>([]() { return new UdpLink(nullptr, nullptr); }), true);
|
|
link.addFunc("setRemote", &UdpLink::setRemote);
|
|
link.addFunc("setRemoteString", &UdpLink::setRemoteString);
|
|
link.addFunc("sendReliable", [](UdpLink* l, int64_t ch, const std::string& s) {
|
|
l->sendString(UdpLink::MsgType::Reliable, static_cast<uint8_t>(ch), s);
|
|
});
|
|
link.addFunc("sendUnreliable", [](UdpLink* l, int64_t ch, const std::string& s) {
|
|
l->sendString(UdpLink::MsgType::Unreliable, static_cast<uint8_t>(ch), s);
|
|
});
|
|
link.addFunc("sendOrdered", [](UdpLink* l, int64_t ch, const std::string& s) {
|
|
l->sendString(UdpLink::MsgType::UnreliableOrdered, static_cast<uint8_t>(ch), s);
|
|
});
|
|
link.addFunc("onMessage", [](UdpLink* l, ssq::Object fn) {
|
|
if (!l) return;
|
|
l->setMessageHandler(
|
|
[fn](UdpLink::MsgType, uint8_t ch, const char* d, size_t n) {
|
|
callScript2(fn, ch, std::string(d, n));
|
|
});
|
|
});
|
|
link.addFunc("setLossRate", &UdpLink::setLossRate);
|
|
link.addFunc("setTimeoutMs", &UdpLink::setTimeoutMs);
|
|
link.addFunc("isAlive", [](UdpLink* l) { return l && l->isAlive(); });
|
|
link.addFunc("peer", &UdpLink::peer);
|
|
link.addFunc("peerId", [](UdpLink* l) { return static_cast<int64_t>(l->peerId()); });
|
|
link.addFunc("pendingReliable",
|
|
[](UdpLink* l) { return static_cast<int64_t>(l->pendingReliable()); });
|
|
link.addFunc("pendingFragments",
|
|
[](UdpLink* l) { return static_cast<int64_t>(l->pendingFragments()); });
|
|
|
|
auto rpc = table.addClass<NetRpc>(
|
|
"NetRpc", std::function<NetRpc*()>([]() { return new NetRpc(nullptr); }), true);
|
|
rpc.addFunc("callRpc", [](NetRpc* r, int64_t msgId, const std::string& payload,
|
|
bool reliable) {
|
|
r->callString(static_cast<uint16_t>(msgId), payload, reliable);
|
|
});
|
|
rpc.addFunc("registerRpc", [](NetRpc* r, int64_t msgId, ssq::Object fn) {
|
|
r->registerScript(static_cast<uint16_t>(msgId), fn);
|
|
});
|
|
|
|
auto host = table.addClass<NetHost>(
|
|
"NetHost", std::function<NetHost*()>([]() { return new NetHost(nullptr); }), true);
|
|
host.addFunc("start", &NetHost::start);
|
|
host.addFunc("onMessage", [](NetHost* h, ssq::Object fn) {
|
|
if (!h) return;
|
|
h->setMessageHandler(
|
|
[fn](uint32_t peerId, UdpLink::MsgType, uint8_t ch, const char* d, size_t n) {
|
|
callScript3(fn, peerId, ch, std::string(d, n));
|
|
});
|
|
});
|
|
host.addFunc("onPeerConnected", [](NetHost* h, ssq::Object fn) {
|
|
if (!h) return;
|
|
h->setPeerConnectedHandler([fn](uint32_t id) { callScript2(fn, id, ""); });
|
|
});
|
|
host.addFunc("onPeerDisconnected", [](NetHost* h, ssq::Object fn) {
|
|
if (!h) return;
|
|
h->setPeerDisconnectedHandler([fn](uint32_t id) { callScript2(fn, id, ""); });
|
|
});
|
|
host.addFunc("sendReliable", [](NetHost* h, int64_t peerId, int64_t ch,
|
|
const std::string& s) {
|
|
h->sendStringTo(static_cast<uint32_t>(peerId), UdpLink::MsgType::Reliable,
|
|
static_cast<uint8_t>(ch), s);
|
|
});
|
|
host.addFunc("sendUnreliable", [](NetHost* h, int64_t peerId, int64_t ch,
|
|
const std::string& s) {
|
|
h->sendStringTo(static_cast<uint32_t>(peerId), UdpLink::MsgType::Unreliable,
|
|
static_cast<uint8_t>(ch), s);
|
|
});
|
|
host.addFunc("sendOrdered", [](NetHost* h, int64_t peerId, int64_t ch,
|
|
const std::string& s) {
|
|
h->sendStringTo(static_cast<uint32_t>(peerId), UdpLink::MsgType::UnreliableOrdered,
|
|
static_cast<uint8_t>(ch), s);
|
|
});
|
|
host.addFunc("link", &NetHost::linkByPeerId);
|
|
host.addFunc("peerCount", [](NetHost* h) { return static_cast<int64_t>(h->peerCount()); });
|
|
host.addFunc("setLossRate", &NetHost::setLossRate);
|
|
host.addFunc("setTimeoutMs", &NetHost::setTimeoutMs);
|
|
}
|
|
|
|
void Network::expose(ssq::Class& cls) {
|
|
cls.addFunc("getName", &Network::getName);
|
|
cls.addFunc("newTcp", &Network::newTcp);
|
|
cls.addFunc("newUdp", &Network::newUdp);
|
|
cls.addFunc("newHttp", &Network::newHttp);
|
|
cls.addFunc("newChannel", &Network::newChannel);
|
|
cls.addFunc("newSession", &Network::newSession);
|
|
cls.addFunc("newWriter", &Network::newWriter);
|
|
cls.addFunc("newReader", &Network::newReader);
|
|
cls.addFunc("newUdpLink", &Network::newUdpLink);
|
|
cls.addFunc("newRpc", &Network::newRpc);
|
|
cls.addFunc("newHost", &Network::newHost);
|
|
cls.addFunc("pump", &Network::pump);
|
|
cls.addFunc("setTimeout", &Network::setTimeout);
|
|
cls.addFunc("setVerifySsl", &Network::setVerifySsl);
|
|
}
|
|
|
|
} // namespace eve::network
|