mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
Implement a basic websockets server
This commit is contained in:
parent
5bfcef600f
commit
ebca112769
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -13,3 +13,6 @@
|
||||
[submodule "submodules/recastnavigation"]
|
||||
path = submodules/recastnavigation
|
||||
url = https://github.com/recastnavigation/recastnavigation.git
|
||||
[submodule "submodules/websocketpp"]
|
||||
path = submodules/websocketpp
|
||||
url = https://github.com/zaphoyd/websocketpp.git
|
||||
|
||||
@ -349,6 +349,7 @@ INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigat
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigation/DetourCrowd/Include")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigation/DetourTileCache/Include")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigation/Recast/Include")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/websocketpp")
|
||||
|
||||
IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS OR EQEMU_BUILD_HC)
|
||||
ADD_SUBDIRECTORY(common)
|
||||
|
||||
@ -86,6 +86,8 @@ SET(common_sources
|
||||
net/servertalk_server_connection.cpp
|
||||
net/tcp_connection.cpp
|
||||
net/tcp_server.cpp
|
||||
net/websocket_server.cpp
|
||||
net/websocket_server_connection.cpp
|
||||
patches/patches.cpp
|
||||
patches/sod.cpp
|
||||
patches/sod_limits.cpp
|
||||
@ -230,6 +232,8 @@ SET(common_headers
|
||||
net/servertalk_server_connection.h
|
||||
net/tcp_connection.h
|
||||
net/tcp_server.h
|
||||
net/websocket_server.h
|
||||
net/websocket_server_connection.h
|
||||
patches/patches.h
|
||||
patches/sod.h
|
||||
patches/sod_limits.h
|
||||
@ -309,6 +313,10 @@ SOURCE_GROUP(Net FILES
|
||||
net/tcp_connection.h
|
||||
net/tcp_server.cpp
|
||||
net/tcp_server.h
|
||||
net/websocket_server.cpp
|
||||
net/websocket_server.h
|
||||
net/websocket_server_connection.cpp
|
||||
net/websocket_server_connection.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Patches FILES
|
||||
|
||||
@ -95,6 +95,7 @@ enum GameChatColor {
|
||||
EQEmuLogSys::EQEmuLogSys()
|
||||
{
|
||||
on_log_gmsay_hook = [](uint16 log_type, const std::string &) {};
|
||||
on_log_console_hook = [](uint16 debug_level, uint16 log_type, const std::string &) {};
|
||||
bool file_logs_enabled = false;
|
||||
int log_platform = 0;
|
||||
}
|
||||
@ -346,6 +347,8 @@ void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category,
|
||||
#else
|
||||
std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl;
|
||||
#endif
|
||||
|
||||
on_log_console_hook(debug_level, log_category, message);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -505,4 +508,4 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
|
||||
std::ios_base::app | std::ios_base::out
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,7 +240,8 @@ public:
|
||||
*/
|
||||
uint16 GetGMSayColorFromCategory(uint16 log_category);
|
||||
|
||||
void OnLogHookCallBackZone(std::function<void(uint16 log_type, const std::string&)> f) { on_log_gmsay_hook = f; }
|
||||
void SetGMSayHandler(std::function<void(uint16 log_type, const std::string&)> f) { on_log_gmsay_hook = f; }
|
||||
void SetConsoleHandler(std::function<void(uint16 debug_level, uint16 log_type, const std::string&)> f) { on_log_console_hook = f; }
|
||||
|
||||
private:
|
||||
|
||||
@ -248,6 +249,7 @@ private:
|
||||
* Callback pointer to zone process for hooking logs to zone using GMSay
|
||||
*/
|
||||
std::function<void(uint16 log_category, const std::string&)> on_log_gmsay_hook;
|
||||
std::function<void(uint16 debug_level, uint16 log_category, const std::string&)> on_log_console_hook;
|
||||
|
||||
/**
|
||||
* Formats log messages like '[Category] This is a log message'
|
||||
|
||||
216
common/net/websocket_server.cpp
Normal file
216
common/net/websocket_server.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
#include "websocket_server.h"
|
||||
#include "../event/event_loop.h"
|
||||
#include "../event/timer.h"
|
||||
#include <fmt/format.h>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
struct MethodHandlerEntry
|
||||
{
|
||||
MethodHandlerEntry(EQ::Net::WebsocketServer::MethodHandler h, int s) {
|
||||
handler = h;
|
||||
status = s;
|
||||
}
|
||||
|
||||
EQ::Net::WebsocketServer::MethodHandler handler;
|
||||
int status;
|
||||
};
|
||||
|
||||
struct EQ::Net::WebsocketServer::Impl
|
||||
{
|
||||
std::unique_ptr<TCPServer> server;
|
||||
std::unique_ptr<EQ::Timer> ping_timer;
|
||||
std::map<std::shared_ptr<websocket_connection>, std::unique_ptr<WebsocketServerConnection>> connections;
|
||||
std::map<std::string, MethodHandlerEntry> methods;
|
||||
websocket_server websocket_server;
|
||||
LoginHandler login_handler;
|
||||
};
|
||||
|
||||
EQ::Net::WebsocketServer::WebsocketServer(const std::string &addr, int port)
|
||||
{
|
||||
_impl.reset(new Impl());
|
||||
_impl->server.reset(new EQ::Net::TCPServer());
|
||||
_impl->server->Listen(addr, port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
|
||||
auto wsc = _impl->websocket_server.get_connection();
|
||||
WebsocketServerConnection *c = new WebsocketServerConnection(this, connection, wsc);
|
||||
_impl->connections.insert(std::make_pair(wsc, std::unique_ptr<WebsocketServerConnection>(c)));
|
||||
});
|
||||
|
||||
_impl->websocket_server.set_write_handler(
|
||||
[this](websocketpp::connection_hdl hdl, char const *data, size_t size) -> websocketpp::lib::error_code {
|
||||
auto c = _impl->websocket_server.get_con_from_hdl(hdl);
|
||||
auto iter = _impl->connections.find(c);
|
||||
if (iter != _impl->connections.end()) {
|
||||
iter->second->GetTCPConnection()->Write(data, size);
|
||||
}
|
||||
|
||||
return websocketpp::lib::error_code();
|
||||
});
|
||||
|
||||
_impl->ping_timer.reset(new EQ::Timer(5000, true, [this](EQ::Timer *t) {
|
||||
auto iter = _impl->connections.begin();
|
||||
|
||||
while (iter != _impl->connections.end()) {
|
||||
try {
|
||||
auto &connection = iter->second;
|
||||
connection->GetWebsocketConnection()->ping("keepalive");
|
||||
}
|
||||
catch (std::exception) {
|
||||
iter->second->GetTCPConnection()->Disconnect();
|
||||
}
|
||||
|
||||
iter++;
|
||||
}
|
||||
}));
|
||||
|
||||
_impl->methods.insert(std::make_pair("login", MethodHandlerEntry(std::bind(&WebsocketServer::Login, this, std::placeholders::_1, std::placeholders::_2), 0)));
|
||||
_impl->methods.insert(std::make_pair("subscribe", MethodHandlerEntry(std::bind(&WebsocketServer::Subscribe, this, std::placeholders::_1, std::placeholders::_2), 0)));
|
||||
_impl->methods.insert(std::make_pair("unsubscribe", MethodHandlerEntry(std::bind(&WebsocketServer::Unsubscribe, this, std::placeholders::_1, std::placeholders::_2), 0)));
|
||||
_impl->login_handler = [](const WebsocketServerConnection* connection, const std::string& user, const std::string& pass) {
|
||||
WebsocketLoginStatus ret;
|
||||
ret.account_name = "admin";
|
||||
|
||||
if (connection->RemoteIP() == "127.0.0.1" || connection->RemoteIP() == "::") {
|
||||
ret.logged_in = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret.logged_in = false;
|
||||
return ret;
|
||||
};
|
||||
|
||||
_impl->websocket_server.clear_access_channels(websocketpp::log::alevel::all);
|
||||
}
|
||||
|
||||
EQ::Net::WebsocketServer::~WebsocketServer()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::WebsocketServer::ReleaseConnection(WebsocketServerConnection *connection)
|
||||
{
|
||||
//Clear any subscriptions here
|
||||
|
||||
_impl->connections.erase(connection->GetWebsocketConnection());
|
||||
}
|
||||
|
||||
Json::Value EQ::Net::WebsocketServer::HandleRequest(WebsocketServerConnection *connection, const std::string &method, const Json::Value ¶ms)
|
||||
{
|
||||
Json::Value err;
|
||||
if (method != "login") {
|
||||
if (!connection->IsAuthorized()) {
|
||||
throw WebsocketException("Not logged in");
|
||||
}
|
||||
}
|
||||
|
||||
auto iter = _impl->methods.find(method);
|
||||
if (iter != _impl->methods.end()) {
|
||||
auto &s = iter->second;
|
||||
if (s.status > connection->GetStatus()) {
|
||||
throw WebsocketException("Status too low");
|
||||
}
|
||||
|
||||
return s.handler(connection, params);
|
||||
}
|
||||
|
||||
throw WebsocketException("Unknown Method");
|
||||
}
|
||||
|
||||
void EQ::Net::WebsocketServer::SetMethodHandler(const std::string &method, MethodHandler handler, int required_status)
|
||||
{
|
||||
//Reserved method names
|
||||
if (method == "subscribe" ||
|
||||
method == "unsubscribe" ||
|
||||
method == "login") {
|
||||
return;
|
||||
}
|
||||
|
||||
_impl->methods.insert_or_assign(method, MethodHandlerEntry(handler, required_status));
|
||||
}
|
||||
|
||||
void EQ::Net::WebsocketServer::SetLoginHandler(LoginHandler handler)
|
||||
{
|
||||
_impl->login_handler = handler;
|
||||
}
|
||||
|
||||
void EQ::Net::WebsocketServer::DispatchEvent(const std::string &evt, Json::Value data, int required_status)
|
||||
{
|
||||
try {
|
||||
Json::Value event_obj;
|
||||
event_obj["type"] = "event";
|
||||
event_obj["event"] = evt;
|
||||
event_obj["data"] = data;
|
||||
|
||||
std::stringstream payload;
|
||||
payload << event_obj;
|
||||
|
||||
for (auto &iter : _impl->connections) {
|
||||
auto &c = iter.second;
|
||||
|
||||
//Might be better to get rid of subscriptions and just send everything and
|
||||
//let the client sort out what they want idk
|
||||
if (c->GetStatus() >= required_status && c->IsSubscribed(evt)) {
|
||||
c->GetWebsocketConnection()->send(payload.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception) {
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value EQ::Net::WebsocketServer::Login(WebsocketServerConnection *connection, const Json::Value ¶ms)
|
||||
{
|
||||
Json::Value ret;
|
||||
|
||||
try {
|
||||
Json::Value ret;
|
||||
|
||||
auto user = params[0].asString();
|
||||
auto pass = params[1].asString();
|
||||
|
||||
auto r = _impl->login_handler(connection, user, pass);
|
||||
|
||||
if (r.logged_in) {
|
||||
connection->SetAuthorized(true, r.account_name, r.account_id, 255);
|
||||
ret["status"] = "Ok";
|
||||
}
|
||||
else {
|
||||
connection->SetAuthorized(false, "", 0, 0);
|
||||
ret["status"] = "Not Authorized";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
catch (std::exception) {
|
||||
throw WebsocketException("Unable to process login request");
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value EQ::Net::WebsocketServer::Subscribe(WebsocketServerConnection *connection, const Json::Value ¶ms)
|
||||
{
|
||||
Json::Value ret;
|
||||
|
||||
try {
|
||||
auto evt = params[0].asString();
|
||||
connection->Subscribe(evt);
|
||||
ret["status"] = "Ok";
|
||||
return ret;
|
||||
}
|
||||
catch (std::exception) {
|
||||
throw WebsocketException("Unable to process subscribe request");
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value EQ::Net::WebsocketServer::Unsubscribe(WebsocketServerConnection *connection, const Json::Value ¶ms)
|
||||
{
|
||||
Json::Value ret;
|
||||
|
||||
try {
|
||||
auto evt = params[0].asString();
|
||||
connection->Unsubscribe(evt);
|
||||
ret["status"] = "Ok";
|
||||
return ret;
|
||||
}
|
||||
catch (std::exception) {
|
||||
throw WebsocketException("Unable to process unsubscribe request");
|
||||
}
|
||||
}
|
||||
63
common/net/websocket_server.h
Normal file
63
common/net/websocket_server.h
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include "websocket_server_connection.h"
|
||||
|
||||
#include "../json/json.h"
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <exception>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
struct WebsocketLoginStatus
|
||||
{
|
||||
bool logged_in;
|
||||
std::string account_name;
|
||||
uint32 account_id;
|
||||
int status;
|
||||
};
|
||||
|
||||
class WebsocketException : public std::exception
|
||||
{
|
||||
public:
|
||||
WebsocketException(const std::string &msg)
|
||||
: _msg(msg.empty() ? "Unknown Error" : msg) { }
|
||||
|
||||
~WebsocketException() throw() {}
|
||||
|
||||
virtual char const *what() const throw() {
|
||||
return _msg.c_str();
|
||||
}
|
||||
private:
|
||||
const std::string _msg;
|
||||
};
|
||||
|
||||
class WebsocketServer
|
||||
{
|
||||
public:
|
||||
typedef std::function<Json::Value(WebsocketServerConnection*, const Json::Value&)> MethodHandler;
|
||||
typedef std::function<WebsocketLoginStatus(WebsocketServerConnection*, const std::string&, const std::string&)> LoginHandler;
|
||||
|
||||
WebsocketServer(const std::string &addr, int port);
|
||||
~WebsocketServer();
|
||||
|
||||
void SetMethodHandler(const std::string& method, MethodHandler handler, int required_status);
|
||||
void SetLoginHandler(LoginHandler handler);
|
||||
void DispatchEvent(const std::string& evt, Json::Value data = Json::Value(), int required_status = 0);
|
||||
private:
|
||||
void ReleaseConnection(WebsocketServerConnection *connection);
|
||||
Json::Value HandleRequest(WebsocketServerConnection *connection, const std::string& method, const Json::Value ¶ms);
|
||||
|
||||
Json::Value Login(WebsocketServerConnection *connection, const Json::Value ¶ms);
|
||||
Json::Value Subscribe(WebsocketServerConnection *connection, const Json::Value ¶ms);
|
||||
Json::Value Unsubscribe(WebsocketServerConnection *connection, const Json::Value ¶ms);
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> _impl;
|
||||
|
||||
friend class WebsocketServerConnection;
|
||||
};
|
||||
}
|
||||
}
|
||||
189
common/net/websocket_server_connection.cpp
Normal file
189
common/net/websocket_server_connection.cpp
Normal file
@ -0,0 +1,189 @@
|
||||
#include "websocket_server_connection.h"
|
||||
#include "websocket_server.h"
|
||||
#include "../timer.h"
|
||||
#include "../util/uuid.h"
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
#include <fmt/format.h>
|
||||
|
||||
struct EQ::Net::WebsocketServerConnection::Impl {
|
||||
WebsocketServer *parent;
|
||||
std::shared_ptr<TCPConnection> connection;
|
||||
std::shared_ptr<websocket_connection> ws_connection;
|
||||
std::string id;
|
||||
bool authorized;
|
||||
std::string account_name;
|
||||
uint32 account_id;
|
||||
int status;
|
||||
std::unordered_set<std::string> subscribed;
|
||||
};
|
||||
|
||||
EQ::Net::WebsocketServerConnection::WebsocketServerConnection(WebsocketServer *parent,
|
||||
std::shared_ptr<TCPConnection> connection,
|
||||
std::shared_ptr<websocket_connection> ws_connection)
|
||||
{
|
||||
_impl.reset(new Impl());
|
||||
_impl->parent = parent;
|
||||
_impl->connection = connection;
|
||||
_impl->id = EQ::Util::UUID::Generate().ToString();
|
||||
_impl->authorized = false;
|
||||
_impl->account_id = 0;
|
||||
_impl->status = 0;
|
||||
_impl->ws_connection = ws_connection;
|
||||
_impl->ws_connection->set_message_handler(std::bind(&WebsocketServerConnection::OnMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
_impl->ws_connection->start();
|
||||
|
||||
connection->OnDisconnect([this](EQ::Net::TCPConnection *connection) {
|
||||
_impl->parent->ReleaseConnection(this);
|
||||
});
|
||||
|
||||
connection->OnRead([this](EQ::Net::TCPConnection *c, const unsigned char *buffer, size_t buffer_size) {
|
||||
_impl->ws_connection->read_all((const char*)buffer, buffer_size);
|
||||
});
|
||||
|
||||
connection->Start();
|
||||
}
|
||||
|
||||
EQ::Net::WebsocketServerConnection::~WebsocketServerConnection()
|
||||
{
|
||||
}
|
||||
|
||||
std::string EQ::Net::WebsocketServerConnection::GetID() const
|
||||
{
|
||||
return _impl->id;
|
||||
}
|
||||
|
||||
bool EQ::Net::WebsocketServerConnection::IsAuthorized() const
|
||||
{
|
||||
return _impl->authorized;
|
||||
}
|
||||
|
||||
std::string EQ::Net::WebsocketServerConnection::GetAccountName() const
|
||||
{
|
||||
return _impl->account_name;
|
||||
}
|
||||
|
||||
uint32 EQ::Net::WebsocketServerConnection::GetAccountID() const
|
||||
{
|
||||
return _impl->account_id;
|
||||
}
|
||||
|
||||
int EQ::Net::WebsocketServerConnection::GetStatus() const
|
||||
{
|
||||
return _impl->status;
|
||||
}
|
||||
|
||||
std::string EQ::Net::WebsocketServerConnection::RemoteIP() const
|
||||
{
|
||||
return _impl->connection->RemoteIP();
|
||||
}
|
||||
|
||||
int EQ::Net::WebsocketServerConnection::RemotePort() const
|
||||
{
|
||||
return _impl->connection->RemotePort();
|
||||
}
|
||||
|
||||
std::shared_ptr<EQ::Net::websocket_connection> EQ::Net::WebsocketServerConnection::GetWebsocketConnection()
|
||||
{
|
||||
return _impl->ws_connection;
|
||||
}
|
||||
|
||||
std::shared_ptr<EQ::Net::TCPConnection> EQ::Net::WebsocketServerConnection::GetTCPConnection()
|
||||
{
|
||||
return _impl->connection;
|
||||
}
|
||||
|
||||
void EQ::Net::WebsocketServerConnection::OnMessage(websocketpp::connection_hdl hdl, websocket_message_ptr msg)
|
||||
{
|
||||
BenchTimer timer;
|
||||
timer.reset();
|
||||
|
||||
if (msg->get_opcode() == websocketpp::frame::opcode::text) {
|
||||
try {
|
||||
auto &payload = msg->get_payload();
|
||||
|
||||
std::stringstream ss(payload);
|
||||
Json::Value root;
|
||||
|
||||
ss >> root;
|
||||
|
||||
auto method = root["method"].asString();
|
||||
auto params = root["params"];
|
||||
std::string id = "";
|
||||
|
||||
auto idNode = root["id"];
|
||||
if (!idNode.isNull() && idNode.isString()) {
|
||||
id = idNode.asString();
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
response["type"] = "method";
|
||||
response["data"] = _impl->parent->HandleRequest(this, method, params);
|
||||
response["method"] = method;
|
||||
if(id != "") {
|
||||
response["id"] = id;
|
||||
}
|
||||
|
||||
SendResponse(response, timer.elapsed());
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
Json::Value error;
|
||||
error["type"] = "method";
|
||||
error["error"] = fmt::format("{0}", ex.what());
|
||||
SendResponse(error, timer.elapsed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::WebsocketServerConnection::SendResponse(const Json::Value &response, double time_elapsed)
|
||||
{
|
||||
Json::Value root = response;
|
||||
root["execution_time"] = std::to_string(time_elapsed);
|
||||
|
||||
std::stringstream payload;
|
||||
payload << root;
|
||||
|
||||
_impl->ws_connection->send(payload.str());
|
||||
}
|
||||
|
||||
void EQ::Net::WebsocketServerConnection::SetAuthorized(bool v, const std::string account_name, uint32 account_id, int status)
|
||||
{
|
||||
_impl->authorized = v;
|
||||
_impl->account_name = account_name;
|
||||
_impl->account_id = account_id;
|
||||
_impl->status = status;
|
||||
}
|
||||
|
||||
void EQ::Net::WebsocketServerConnection::Subscribe(const std::string &evt)
|
||||
{
|
||||
if (evt == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
auto iter = _impl->subscribed.find(evt);
|
||||
if (iter == _impl->subscribed.end()) {
|
||||
_impl->subscribed.insert(evt);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::WebsocketServerConnection::Unsubscribe(const std::string &evt)
|
||||
{
|
||||
if (evt == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
auto iter = _impl->subscribed.find(evt);
|
||||
if (iter != _impl->subscribed.end()) {
|
||||
_impl->subscribed.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
bool EQ::Net::WebsocketServerConnection::IsSubscribed(const std::string &evt) const
|
||||
{
|
||||
auto iter = _impl->subscribed.find(evt);
|
||||
if (iter != _impl->subscribed.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
49
common/net/websocket_server_connection.h
Normal file
49
common/net/websocket_server_connection.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "tcp_server.h"
|
||||
#include "../types.h"
|
||||
#include "../json/json-forwards.h"
|
||||
#include <websocketpp/config/core.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
typedef websocketpp::server<websocketpp::config::core> websocket_server;
|
||||
typedef websocketpp::connection<websocketpp::config::core> websocket_connection;
|
||||
typedef websocket_server::message_ptr websocket_message_ptr;
|
||||
|
||||
class WebsocketServer;
|
||||
class WebsocketServerConnection
|
||||
{
|
||||
public:
|
||||
WebsocketServerConnection(WebsocketServer *parent,
|
||||
std::shared_ptr<TCPConnection> connection,
|
||||
std::shared_ptr<websocket_connection> ws_connection);
|
||||
~WebsocketServerConnection();
|
||||
|
||||
std::string GetID() const;
|
||||
bool IsAuthorized() const;
|
||||
std::string GetAccountName() const;
|
||||
uint32 GetAccountID() const;
|
||||
int GetStatus() const;
|
||||
std::string RemoteIP() const;
|
||||
int RemotePort() const;
|
||||
private:
|
||||
std::shared_ptr<websocket_connection> GetWebsocketConnection();
|
||||
std::shared_ptr<TCPConnection> GetTCPConnection();
|
||||
void OnMessage(websocketpp::connection_hdl hdl, websocket_message_ptr msg);
|
||||
void SendResponse(const Json::Value &response, double time_elapsed);
|
||||
void SetAuthorized(bool v, const std::string account_name, uint32 account_id, int status);
|
||||
void Subscribe(const std::string &evt);
|
||||
void Unsubscribe(const std::string &evt);
|
||||
bool IsSubscribed(const std::string &evt) const;
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> _impl;
|
||||
|
||||
friend class WebsocketServer;
|
||||
};
|
||||
}
|
||||
}
|
||||
1
submodules/websocketpp
Submodule
1
submodules/websocketpp
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c6d7e295bf5a0ab9b5f896720cc1a0e0fdc397a7
|
||||
@ -5,8 +5,9 @@ SET(zone_sources
|
||||
aa_ability.cpp
|
||||
aggro.cpp
|
||||
aggromanager.cpp
|
||||
aura.cpp
|
||||
api_service.cpp
|
||||
attack.cpp
|
||||
aura.cpp
|
||||
beacon.cpp
|
||||
bonuses.cpp
|
||||
bot.cpp
|
||||
@ -17,7 +18,6 @@ SET(zone_sources
|
||||
client_mods.cpp
|
||||
client_packet.cpp
|
||||
client_process.cpp
|
||||
console.cpp
|
||||
command.cpp
|
||||
corpse.cpp
|
||||
data_bucket.cpp
|
||||
@ -29,7 +29,6 @@ SET(zone_sources
|
||||
embxs.cpp
|
||||
encounter.cpp
|
||||
entity.cpp
|
||||
eqemu_api_zone_data_service.cpp
|
||||
exp.cpp
|
||||
fastmath.cpp
|
||||
fearpath.cpp
|
||||
@ -149,6 +148,7 @@ SET(zone_headers
|
||||
aa.h
|
||||
aa_ability.h
|
||||
aggromanager.h
|
||||
api_service.h
|
||||
aura.h
|
||||
basic_functions.h
|
||||
beacon.h
|
||||
@ -160,7 +160,6 @@ SET(zone_headers
|
||||
client_packet.h
|
||||
command.h
|
||||
common.h
|
||||
console.h
|
||||
corpse.h
|
||||
data_bucket.h
|
||||
doors.h
|
||||
@ -169,7 +168,6 @@ SET(zone_headers
|
||||
embxs.h
|
||||
encounter.h
|
||||
entity.h
|
||||
eqemu_api_zone_data_service.h
|
||||
errmsg.h
|
||||
event_codes.h
|
||||
fastmath.h
|
||||
|
||||
@ -18,10 +18,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include "../common/net/websocket_server.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "zonedb.h"
|
||||
#include "client.h"
|
||||
#include "entity.h"
|
||||
#include "corpse.h"
|
||||
#include "eqemu_api_zone_data_service.h"
|
||||
#include "api_service.h"
|
||||
#include "npc.h"
|
||||
#include "object.h"
|
||||
#include "zone.h"
|
||||
@ -30,8 +34,117 @@
|
||||
|
||||
extern Zone *zone;
|
||||
|
||||
void callGetNpcListDetail(Json::Value &response)
|
||||
{
|
||||
EQ::Net::WebsocketLoginStatus CheckLogin(EQ::Net::WebsocketServerConnection *connection, const std::string &username, const std::string &password) {
|
||||
EQ::Net::WebsocketLoginStatus ret;
|
||||
ret.logged_in = false;
|
||||
|
||||
ret.account_id = database.CheckLogin(username.c_str(), password.c_str());
|
||||
|
||||
if (ret.account_id == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
char account_name[64];
|
||||
database.GetAccountName(static_cast<uint32>(ret.account_id), account_name);
|
||||
ret.account_name = account_name;
|
||||
ret.logged_in = true;
|
||||
ret.status = database.CheckStatus(ret.account_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Json::Value ApiGetPacketStatistics(EQ::Net::WebsocketServerConnection *connection, Json::Value params) {
|
||||
if (zone->GetZoneID() == 0) {
|
||||
throw EQ::Net::WebsocketException("Zone must be loaded to invoke this call");
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
auto &list = entity_list.GetClientList();
|
||||
|
||||
for (auto &iter : list) {
|
||||
auto client = iter.second;
|
||||
auto connection = client->Connection();
|
||||
auto opts = connection->GetManager()->GetOptions();
|
||||
auto eqs_stats = connection->GetStats();
|
||||
auto &stats = eqs_stats.DaybreakStats;
|
||||
auto now = EQ::Net::Clock::now();
|
||||
auto sec_since_stats_reset = std::chrono::duration_cast<std::chrono::duration<double>>(
|
||||
now - stats.created
|
||||
).count();
|
||||
|
||||
Json::Value row;
|
||||
|
||||
row["client_id"] = client->GetID();
|
||||
row["client_name"] = client->GetCleanName();
|
||||
row["seconds_since_reset"] = sec_since_stats_reset;
|
||||
row["sent_bytes"] = stats.sent_bytes;
|
||||
row["receive_bytes"] = stats.recv_bytes;
|
||||
row["min_ping"] = stats.min_ping;
|
||||
row["max_ping"] = stats.max_ping;
|
||||
row["last_ping"] = stats.last_ping;
|
||||
row["average_ping"] = stats.avg_ping;
|
||||
row["realtime_receive_packets"] = stats.recv_packets;
|
||||
row["realtime_sent_packets"] = stats.sent_packets;
|
||||
row["sync_recv_packets"] = stats.sync_recv_packets;
|
||||
row["sync_sent_packets"] = stats.sync_sent_packets;
|
||||
row["sync_remote_recv_packets"] = stats.sync_remote_recv_packets;
|
||||
row["sync_remote_sent_packets"] = stats.sync_remote_sent_packets;
|
||||
row["packet_loss_in"] = (100.0 * (1.0 - static_cast<double>(stats.sync_recv_packets) /
|
||||
static_cast<double>(stats.sync_remote_sent_packets)));
|
||||
row["packet_loss_out"] = (100.0 * (1.0 - static_cast<double>(stats.sync_remote_recv_packets) /
|
||||
static_cast<double>(stats.sync_sent_packets)));
|
||||
row["resent_packets"] = stats.resent_packets;
|
||||
row["resent_fragments"] = stats.resent_fragments;
|
||||
row["resent_non_fragments"] = stats.resent_full;
|
||||
row["dropped_datarate_packets"] = stats.dropped_datarate_packets;
|
||||
|
||||
Json::Value sent_packet_types;
|
||||
|
||||
for (auto i = 0; i < _maxEmuOpcode; ++i) {
|
||||
auto count = eqs_stats.SentCount[i];
|
||||
if (count > 0) {
|
||||
sent_packet_types[OpcodeNames[i]] = count;
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value receive_packet_types;
|
||||
|
||||
for (auto i = 0; i < _maxEmuOpcode; ++i) {
|
||||
auto count = eqs_stats.RecvCount[i];
|
||||
if (count > 0) {
|
||||
receive_packet_types[OpcodeNames[i]] = count;
|
||||
}
|
||||
}
|
||||
|
||||
row["sent_packet_types"] = sent_packet_types;
|
||||
row["receive_packet_types"] = receive_packet_types;
|
||||
|
||||
response.append(row);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
Json::Value ApiGetOpcodeList(EQ::Net::WebsocketServerConnection *connection, Json::Value params) {
|
||||
if (zone->GetZoneID() == 0) {
|
||||
throw EQ::Net::WebsocketException("Zone must be loaded to invoke this call");
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
for (auto i = 0; i < _maxEmuOpcode; ++i) {
|
||||
Json::Value row = OpcodeNames[i];
|
||||
|
||||
response.append(row);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
Json::Value ApiGetNpcListDetail(EQ::Net::WebsocketServerConnection *connection, Json::Value params) {
|
||||
if (zone->GetZoneID() == 0) {
|
||||
throw EQ::Net::WebsocketException("Zone must be loaded to invoke this call");
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
auto &list = entity_list.GetNPCList();
|
||||
|
||||
for (auto &iter : list) {
|
||||
@ -115,10 +228,16 @@ void callGetNpcListDetail(Json::Value &response)
|
||||
|
||||
response.append(row);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
void callGetDoorListDetail(Json::Value &response)
|
||||
{
|
||||
Json::Value ApiGetDoorListDetail(EQ::Net::WebsocketServerConnection *connection, Json::Value params) {
|
||||
if (zone->GetZoneID() == 0) {
|
||||
throw EQ::Net::WebsocketException("Zone must be loaded to invoke this call");
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
auto &door_list = entity_list.GetDoorsList();
|
||||
|
||||
for (auto itr : door_list) {
|
||||
@ -152,10 +271,16 @@ void callGetDoorListDetail(Json::Value &response)
|
||||
|
||||
response.append(row);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
void callGetCorpseListDetail(Json::Value &response)
|
||||
{
|
||||
Json::Value ApiGetCorpseListDetail(EQ::Net::WebsocketServerConnection *connection, Json::Value params) {
|
||||
if (zone->GetZoneID() == 0) {
|
||||
throw EQ::Net::WebsocketException("Zone must be loaded to invoke this call");
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
auto &corpse_list = entity_list.GetCorpseList();
|
||||
|
||||
for (auto itr : corpse_list) {
|
||||
@ -185,10 +310,16 @@ void callGetCorpseListDetail(Json::Value &response)
|
||||
|
||||
response.append(row);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
void callGetObjectListDetail(Json::Value &response)
|
||||
{
|
||||
Json::Value ApiGetObjectListDetail(EQ::Net::WebsocketServerConnection *connection, Json::Value params) {
|
||||
if (zone->GetZoneID() == 0) {
|
||||
throw EQ::Net::WebsocketException("Zone must be loaded to invoke this call");
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
auto &list = entity_list.GetObjectList();
|
||||
|
||||
for (auto &iter : list) {
|
||||
@ -214,10 +345,16 @@ void callGetObjectListDetail(Json::Value &response)
|
||||
|
||||
response.append(row);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
void callGetMobListDetail(Json::Value &response)
|
||||
{
|
||||
Json::Value ApiGetMobListDetail(EQ::Net::WebsocketServerConnection *connection, Json::Value params) {
|
||||
if (zone->GetZoneID() == 0) {
|
||||
throw EQ::Net::WebsocketException("Zone must be loaded to invoke this call");
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
auto &list = entity_list.GetMobList();
|
||||
|
||||
for (auto &iter : list) {
|
||||
@ -414,10 +551,16 @@ void callGetMobListDetail(Json::Value &response)
|
||||
|
||||
response.append(row);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
void callGetClientListDetail(Json::Value &response)
|
||||
{
|
||||
Json::Value ApiGetClientListDetail(EQ::Net::WebsocketServerConnection *connection, Json::Value params) {
|
||||
if (zone->GetZoneID() == 0) {
|
||||
throw EQ::Net::WebsocketException("Zone must be loaded to invoke this call");
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
auto &list = entity_list.GetClientList();
|
||||
|
||||
for (auto &iter : list) {
|
||||
@ -607,10 +750,16 @@ void callGetClientListDetail(Json::Value &response)
|
||||
|
||||
response.append(row);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
void callGetZoneAttributes(Json::Value &response)
|
||||
{
|
||||
Json::Value ApiGetZoneAttributes(EQ::Net::WebsocketServerConnection *connection, Json::Value params) {
|
||||
if (zone->GetZoneID() == 0) {
|
||||
throw EQ::Net::WebsocketException("Zone must be loaded to invoke this call");
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
Json::Value row;
|
||||
|
||||
row["aggro_limit_reached"] = zone->AggroLimitReached();
|
||||
@ -648,129 +797,31 @@ void callGetZoneAttributes(Json::Value &response)
|
||||
row["zone_type"] = zone->GetZoneType();
|
||||
|
||||
response.append(row);
|
||||
return response;
|
||||
}
|
||||
|
||||
void callGetPacketStatistics(Json::Value &response)
|
||||
void RegisterApiLogEvent(std::unique_ptr<EQ::Net::WebsocketServer> &server)
|
||||
{
|
||||
auto &list = entity_list.GetClientList();
|
||||
|
||||
for (auto &iter : list) {
|
||||
auto client = iter.second;
|
||||
auto connection = client->Connection();
|
||||
auto opts = connection->GetManager()->GetOptions();
|
||||
auto eqs_stats = connection->GetStats();
|
||||
auto &stats = eqs_stats.DaybreakStats;
|
||||
auto now = EQ::Net::Clock::now();
|
||||
auto sec_since_stats_reset = std::chrono::duration_cast<std::chrono::duration<double>>(
|
||||
now - stats.created
|
||||
).count();
|
||||
|
||||
Json::Value row;
|
||||
|
||||
row["client_id"] = client->GetID();
|
||||
row["client_name"] = client->GetCleanName();
|
||||
row["seconds_since_reset"] = sec_since_stats_reset;
|
||||
row["sent_bytes"] = stats.sent_bytes;
|
||||
row["receive_bytes"] = stats.recv_bytes;
|
||||
row["min_ping"] = stats.min_ping;
|
||||
row["max_ping"] = stats.max_ping;
|
||||
row["last_ping"] = stats.last_ping;
|
||||
row["average_ping"] = stats.avg_ping;
|
||||
row["realtime_receive_packets"] = stats.recv_packets;
|
||||
row["realtime_sent_packets"] = stats.sent_packets;
|
||||
row["sync_recv_packets"] = stats.sync_recv_packets;
|
||||
row["sync_sent_packets"] = stats.sync_sent_packets;
|
||||
row["sync_remote_recv_packets"] = stats.sync_remote_recv_packets;
|
||||
row["sync_remote_sent_packets"] = stats.sync_remote_sent_packets;
|
||||
row["packet_loss_in"] = (100.0 * (1.0 - static_cast<double>(stats.sync_recv_packets) /
|
||||
static_cast<double>(stats.sync_remote_sent_packets)));
|
||||
row["packet_loss_out"] = (100.0 * (1.0 - static_cast<double>(stats.sync_remote_recv_packets) /
|
||||
static_cast<double>(stats.sync_sent_packets)));
|
||||
row["resent_packets"] = stats.resent_packets;
|
||||
row["resent_fragments"] = stats.resent_fragments;
|
||||
row["resent_non_fragments"] = stats.resent_full;
|
||||
row["dropped_datarate_packets"] = stats.dropped_datarate_packets;
|
||||
|
||||
Json::Value sent_packet_types;
|
||||
|
||||
for (auto i = 0; i < _maxEmuOpcode; ++i) {
|
||||
auto count = eqs_stats.SentCount[i];
|
||||
if (count > 0) {
|
||||
sent_packet_types[OpcodeNames[i]] = count;
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value receive_packet_types;
|
||||
|
||||
for (auto i = 0; i < _maxEmuOpcode; ++i) {
|
||||
auto count = eqs_stats.RecvCount[i];
|
||||
if (count > 0) {
|
||||
receive_packet_types[OpcodeNames[i]] = count;
|
||||
}
|
||||
}
|
||||
|
||||
row["sent_packet_types"] = sent_packet_types;
|
||||
row["receive_packet_types"] = receive_packet_types;
|
||||
|
||||
response.append(row);
|
||||
}
|
||||
LogSys.SetConsoleHandler([&](uint16 debug_level, uint16 log_category, const std::string &msg) {
|
||||
Json::Value data;
|
||||
data["debug_level"] = debug_level;
|
||||
data["log_category"] = log_category;
|
||||
data["msg"] = msg;
|
||||
server->DispatchEvent("log", data, 50);
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterApiService(std::unique_ptr<EQ::Net::WebsocketServer> &server) {
|
||||
server->SetLoginHandler(CheckLogin);
|
||||
server->SetMethodHandler("get_packet_statistics", &ApiGetPacketStatistics, 50);
|
||||
server->SetMethodHandler("get_opcode_list", &ApiGetOpcodeList, 50);
|
||||
server->SetMethodHandler("get_npc_list_detail", &ApiGetNpcListDetail, 50);
|
||||
server->SetMethodHandler("get_door_list_detail", &ApiGetDoorListDetail, 50);
|
||||
server->SetMethodHandler("get_corpse_list_detail", &ApiGetCorpseListDetail, 50);
|
||||
server->SetMethodHandler("get_object_list_detail", &ApiGetObjectListDetail, 50);
|
||||
server->SetMethodHandler("get_mob_list_detail", &ApiGetMobListDetail, 50);
|
||||
server->SetMethodHandler("get_client_list_detail", &ApiGetClientListDetail, 50);
|
||||
server->SetMethodHandler("get_zone_attributes", &ApiGetZoneAttributes, 50);
|
||||
|
||||
void callGetOpcodeList(Json::Value &response)
|
||||
{
|
||||
for (auto i = 0; i < _maxEmuOpcode; ++i) {
|
||||
Json::Value row = OpcodeNames[i];
|
||||
|
||||
response.append(row);
|
||||
}
|
||||
}
|
||||
|
||||
void EQEmuApiZoneDataService::get(Json::Value &response, const std::vector<std::string> &args)
|
||||
{
|
||||
std::string method = args[0];
|
||||
|
||||
if (zone->GetZoneID() == 0) {
|
||||
response["error"] = "Zone must be loaded to invoke calls";
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet statistics
|
||||
*/
|
||||
if (method == "get_packet_statistics") {
|
||||
callGetPacketStatistics(response);
|
||||
}
|
||||
if (method == "get_opcode_list") {
|
||||
callGetOpcodeList(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* List detail
|
||||
*/
|
||||
if (method == "get_npc_list_detail") {
|
||||
callGetNpcListDetail(response);
|
||||
}
|
||||
if (method == "get_client_list_detail") {
|
||||
callGetClientListDetail(response);
|
||||
}
|
||||
if (method == "get_mob_list_detail") {
|
||||
callGetMobListDetail(response);
|
||||
}
|
||||
if (method == "get_door_list_detail") {
|
||||
callGetDoorListDetail(response);
|
||||
}
|
||||
if (method == "get_corpse_list_detail") {
|
||||
callGetCorpseListDetail(response);
|
||||
}
|
||||
if (method == "get_object_list_detail") {
|
||||
callGetObjectListDetail(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zone attributes
|
||||
*/
|
||||
if (method == "get_zone_attributes") {
|
||||
callGetZoneAttributes(response);
|
||||
}
|
||||
RegisterApiLogEvent(server);
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -20,6 +20,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../common/net/console_server.h"
|
||||
#include <memory>
|
||||
#include "../common/net/websocket_server.h"
|
||||
|
||||
void RegisterConsoleFunctions(std::unique_ptr<EQ::Net::ConsoleServer> &console);
|
||||
void RegisterApiService(std::unique_ptr<EQ::Net::WebsocketServer> &server);
|
||||
122
zone/console.cpp
122
zone/console.cpp
@ -1,122 +0,0 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "console.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/md5.h"
|
||||
#include "../common/database.h"
|
||||
#include "../common/json/json.h"
|
||||
#include "zone.h"
|
||||
#include "npc.h"
|
||||
#include "entity.h"
|
||||
#include "eqemu_api_zone_data_service.h"
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* @param password
|
||||
* @return
|
||||
*/
|
||||
struct EQ::Net::ConsoleLoginStatus CheckLogin(const std::string &username, const std::string &password)
|
||||
{
|
||||
struct EQ::Net::ConsoleLoginStatus ret;
|
||||
ret.account_id = database.CheckLogin(username.c_str(), password.c_str());
|
||||
if (ret.account_id == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
char account_name[64];
|
||||
database.GetAccountName(static_cast<uint32>(ret.account_id), account_name);
|
||||
|
||||
ret.account_name = account_name;
|
||||
ret.status = database.CheckStatus(static_cast<uint32>(ret.account_id));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param connection
|
||||
* @param command
|
||||
* @param args
|
||||
*/
|
||||
void ConsoleApi(
|
||||
EQ::Net::ConsoleServerConnection *connection,
|
||||
const std::string &command,
|
||||
const std::vector<std::string> &args
|
||||
)
|
||||
{
|
||||
Json::Value root;
|
||||
Json::Value response;
|
||||
|
||||
BenchTimer timer;
|
||||
timer.reset();
|
||||
|
||||
EQEmuApiZoneDataService::get(response, args);
|
||||
|
||||
std::string method = args[0];
|
||||
|
||||
root["execution_time"] = std::to_string(timer.elapsed());
|
||||
root["method"] = method;
|
||||
root["data"] = response;
|
||||
|
||||
std::stringstream payload;
|
||||
payload << root;
|
||||
|
||||
connection->SendLine(payload.str());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param connection
|
||||
* @param command
|
||||
* @param args
|
||||
*/
|
||||
void ConsoleNull(
|
||||
EQ::Net::ConsoleServerConnection *connection,
|
||||
const std::string &command,
|
||||
const std::vector<std::string> &args
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param connection
|
||||
* @param command
|
||||
* @param args
|
||||
*/
|
||||
void ConsoleQuit(
|
||||
EQ::Net::ConsoleServerConnection *connection,
|
||||
const std::string &command,
|
||||
const std::vector<std::string> &args
|
||||
)
|
||||
{
|
||||
connection->SendLine("Exiting...");
|
||||
connection->Close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param console
|
||||
*/
|
||||
void RegisterConsoleFunctions(std::unique_ptr<EQ::Net::ConsoleServer> &console)
|
||||
{
|
||||
console->RegisterLogin(std::bind(CheckLogin, std::placeholders::_1, std::placeholders::_2));
|
||||
console->RegisterCall("api", 200, "api", std::bind(ConsoleApi, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("ping", 50, "ping", std::bind(ConsoleNull, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("quit", 50, "quit", std::bind(ConsoleQuit, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("exit", 50, "exit", std::bind(ConsoleQuit, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_API_ZONE_DATA_SERVICE_H
|
||||
#define EQEMU_API_ZONE_DATA_SERVICE_H
|
||||
|
||||
#include "../common/json/json.h"
|
||||
|
||||
class EQEmuApiZoneDataService {
|
||||
public:
|
||||
static void get(Json::Value &response, const std::vector<std::string> &args);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_API_ZONE_DATA_SERVICE_H
|
||||
14
zone/net.cpp
14
zone/net.cpp
@ -43,8 +43,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/eqemu_logsys_fmt.h"
|
||||
#include "../common/net/console_server.h"
|
||||
|
||||
#include "api_service.h"
|
||||
#include "zone_config.h"
|
||||
#include "masterentity.h"
|
||||
#include "worldserver.h"
|
||||
@ -93,9 +93,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include "../common/unix.h"
|
||||
#include "../common/net/console_server.h"
|
||||
#include "console.h"
|
||||
|
||||
#endif
|
||||
|
||||
volatile bool RunLoops = true;
|
||||
@ -121,7 +118,6 @@ double frame_time = 0.0;
|
||||
|
||||
void Shutdown();
|
||||
extern void MapOpcodes();
|
||||
void RegisterConsoleFunctions(std::unique_ptr<EQ::Net::ConsoleServer> &console);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
RegisterExecutablePlatform(ExePlatformZone);
|
||||
@ -255,7 +251,7 @@ int main(int argc, char** argv) {
|
||||
#endif
|
||||
|
||||
/* Register Log System and Settings */
|
||||
LogSys.OnLogHookCallBackZone(&Zone::GMSayHookCallBackProcess);
|
||||
LogSys.SetGMSayHandler(&Zone::GMSayHookCallBackProcess);
|
||||
database.LoadLogSettings(LogSys.log_settings);
|
||||
LogSys.StartFileLogs();
|
||||
|
||||
@ -463,7 +459,7 @@ int main(int argc, char** argv) {
|
||||
EQStreamInterface *eqsi;
|
||||
std::unique_ptr<EQ::Net::EQStreamManager> eqsm;
|
||||
std::chrono::time_point<std::chrono::system_clock> frame_prev = std::chrono::system_clock::now();
|
||||
std::unique_ptr<EQ::Net::ConsoleServer> console;
|
||||
std::unique_ptr<EQ::Net::WebsocketServer> ws_server;
|
||||
|
||||
auto loop_fn = [&](EQ::Timer* t) {
|
||||
//Advance the timer to our current point in time
|
||||
@ -488,8 +484,8 @@ int main(int argc, char** argv) {
|
||||
Config->TelnetIP.c_str(),
|
||||
Config->ZonePort
|
||||
);
|
||||
console.reset(new EQ::Net::ConsoleServer(Config->TelnetIP, Config->ZonePort));
|
||||
RegisterConsoleFunctions(console);
|
||||
ws_server.reset(new EQ::Net::WebsocketServer(Config->TelnetIP, Config->ZonePort));
|
||||
RegisterApiService(ws_server);
|
||||
telnet_server_opened = true;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user