diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index a3faf0ad6..4b82667bb 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -27,6 +27,7 @@ SET(common_sources eq_stream_ident.cpp eq_stream_proxy.cpp eqtime.cpp + event_sub.cpp extprofile.cpp faction.cpp guild_base.cpp @@ -139,6 +140,7 @@ SET(common_headers eq_stream_proxy.h eqtime.h errmsg.h + event_sub.h extprofile.h faction.h features.h diff --git a/common/event_sub.cpp b/common/event_sub.cpp new file mode 100644 index 000000000..d8c772df1 --- /dev/null +++ b/common/event_sub.cpp @@ -0,0 +1,22 @@ +#include "event_sub.h" +#include + +void EventSubscriptionWatcher::Subscribe(const std::string &event_name) +{ + m_subs[event_name] = 1; +} + +void EventSubscriptionWatcher::Unsubscribe(const std::string &event_name) +{ + m_subs[event_name] = 0; +} + +bool EventSubscriptionWatcher::IsSubscribed(const std::string &event_name) const +{ + auto iter = m_subs.find(event_name); + if (iter != m_subs.end()) { + return iter->second; + } + + return false; +} diff --git a/common/event_sub.h b/common/event_sub.h new file mode 100644 index 000000000..f19fbbc02 --- /dev/null +++ b/common/event_sub.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +class EventSubscriptionWatcher +{ +public: + ~EventSubscriptionWatcher(); + + void Subscribe(const std::string &event_name); + void Unsubscribe(const std::string &event_name); + bool IsSubscribed(const std::string &event_name) const; + + static EventSubscriptionWatcher *Get() { + static EventSubscriptionWatcher* inst = nullptr; + if(!inst) { + inst = new EventSubscriptionWatcher(); + } + + return inst; + } +private: + EventSubscriptionWatcher(); + EventSubscriptionWatcher(const EventSubscriptionWatcher&); + EventSubscriptionWatcher& operator=(const EventSubscriptionWatcher&); + + std::unordered_map m_subs; +}; diff --git a/common/servertalk.h b/common/servertalk.h index a79622099..8ff189b4f 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -89,6 +89,8 @@ #define ServerOP_RequestTellQueue 0x0066 // client asks for it's tell queues #define ServerOP_ChangeSharedMem 0x0067 #define ServerOP_WebInterfaceEvent 0x0068 +#define ServerOP_WebInterfaceSubscribe 0x0069 +#define ServerOP_WebInterfaceUnsubscribe 0x0070 #define ServerOP_RaidAdd 0x0100 //in use #define ServerOP_RaidRemove 0x0101 //in use diff --git a/wi/http/common.js b/wi/http/common.js new file mode 100644 index 000000000..c049520e9 --- /dev/null +++ b/wi/http/common.js @@ -0,0 +1,26 @@ +var auth = require('../core/jwt_auth.js').auth; + +function RegisterFunction(path, fn, app, api) { + app.post(path, auth, function (req, res) { + var params = req.body.params || []; + + api.Call(fn, params) + .then(function(value) { + res.send({ response: value }); + }) + .catch(function(reason) { + if(reason.message) { + res.send({ status: reason.message }); + } + else if(reason === 'Not connected to world server.') { + res.send({ status: 'ENCONNECTED' }); + } else { + res.sendStatus(500); + } + }); + }); +} + +module.exports = { + 'Register': RegisterFunction +} \ No newline at end of file diff --git a/wi/http/eqw.js b/wi/http/eqw.js index 45585abf5..9a72e6114 100644 --- a/wi/http/eqw.js +++ b/wi/http/eqw.js @@ -1,37 +1,16 @@ -var auth = require('../core/jwt_auth.js').auth; +const common = require('./common.js'); var RegisterEQW = function(app, api) { - app.post('/api/eqw/islocked', auth, function (req, res) { - api.Call('EQW::IsLocked', []) - .then(function(value) { - res.send({ response: value }); - }) - .catch(function(reason) { - res.sendStatus(500); - }); - }); - - app.post('/api/eqw/lock', auth, function (req, res) { - api.Call('EQW::Lock', []) - .then(function(value) { - res.send({ response: value }); - }) - .catch(function(reason) { - res.sendStatus(500); - }); - }); - - app.post('/api/eqw/unlock', auth, function (req, res) { - api.Call('EQW::Unlock', []) - .then(function(value) { - res.send({ response: value }); - }) - .catch(function(reason) { - res.sendStatus(500); - }); - }); + common.Register('/api/eqw/getconfig', 'EQW::GetConfig', app, api); + common.Register('/api/eqw/islocked', 'EQW::IsLocked', app, api); + common.Register('/api/eqw/lock', 'EQW::Lock', app, api); + common.Register('/api/eqw/unlock', 'EQW::Unlock', app, api); + common.Register('/api/eqw/getplayercount', 'EQW::GetPlayerCount', app, api); + common.Register('/api/eqw/getzonecount', 'EQW::GetZoneCount', app, api); + common.Register('/api/eqw/getlaunchercount', 'EQW::GetLauncherCount', app, api); + common.Register('/api/eqw/getloginservercount', 'EQW::GetLoginServerCount', app, api); }; module.exports = { 'Register': RegisterEQW -} \ No newline at end of file +} diff --git a/wi/network/servertalk_api.js b/wi/network/servertalk_api.js index 154c12b1e..be4220edf 100644 --- a/wi/network/servertalk_api.js +++ b/wi/network/servertalk_api.js @@ -113,20 +113,26 @@ class ServertalkAPI var subs = this.subscriptions[event_id]; if(subs) { - console.log('Subscribe', who.uuid, 'to', event_id); + //console.log('Subscribe', who.uuid, 'to', event_id); subs[who.uuid] = who; } else { - console.log('Subscribe', who.uuid, 'to', event_id); + //console.log('Subscribe', who.uuid, 'to', event_id); this.subscriptions[event_id] = { }; this.subscriptions[event_id][who.uuid] = who; + //Tell our server we have a subscription for event_id } } Unsubscribe(event_id, who) { var subs = this.subscriptions[event_id]; if(subs) { - console.log('Unsubscribe', who.uuid, 'from', event_id); + //console.log('Unsubscribe', who.uuid, 'from', event_id); delete subs[who.uuid]; + + if(Object.keys(subs).length === 0) { + delete this.subscriptions[event_id]; + //Tell our server we no longer have a subscription for event_id + } } } diff --git a/wi/test.js b/wi/test.js index 1ddca8cbf..0ede3b12c 100644 --- a/wi/test.js +++ b/wi/test.js @@ -2,8 +2,8 @@ const WebSocket = require('ws'); const ws = new WebSocket('ws://localhost:9080'); ws.on('open', function open() { - //ws.send(JSON.stringify({authorization: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IktTcHJpdGUxIiwiZXhwIjoxNDg0NzIzNDQxLCJpYXQiOjE0ODQxMTg2NDF9.Lmwm572yMWIu1DUrfer8JVvl1DGEkdnMsMFp5WDzp_A', method: 'EQW::ZoneUpdate::Subscribe'})); - ws.send(JSON.stringify({authorization: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IktTcHJpdGUxIiwiZXhwIjoxNDg0NzIzNDQxLCJpYXQiOjE0ODQxMTg2NDF9.Lmwm572yMWIu1DUrfer8JVvl1DGEkdnMsMFp5WDzp_A', method: 'EQW::ClientUpdate::Subscribe'})); + ws.send(JSON.stringify({authorization: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IktTcHJpdGUxIiwiZXhwIjoxNDg2MzI4MDI3LCJpYXQiOjE0ODU3MjMyMjd9.fJUeSQsxb5C13ICANox81YdE5yImkrVw-lRCP3O40-E', method: 'EQW::ZoneUpdate::Subscribe'})); + ws.send(JSON.stringify({authorization: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IktTcHJpdGUxIiwiZXhwIjoxNDg2MzI4MDI3LCJpYXQiOjE0ODU3MjMyMjd9.fJUeSQsxb5C13ICANox81YdE5yImkrVw-lRCP3O40-E', method: 'EQW::ClientUpdate::Subscribe'})); }); ws.on('message', function(data, flags) { diff --git a/wi/ws/eqw.js b/wi/ws/eqw.js index 00f9040d4..81d5c22f4 100644 --- a/wi/ws/eqw.js +++ b/wi/ws/eqw.js @@ -1,9 +1,14 @@ const common = require('./wi_common.js'); var RegisterEQW = function(wsi, api) { + common.Register('EQW::GetConfig', wsi, api); common.Register('EQW::IsLocked', wsi, api); common.Register('EQW::Lock', wsi, api); common.Register('EQW::Unlock', wsi, api); + common.Register('EQW::GetPlayerCount', wsi, api); + common.Register('EQW::GetZoneCount', wsi, api); + common.Register('EQW::GetLauncherCount', wsi, api); + common.Register('EQW::GetLoginServerCount', wsi, api); common.RegisterSubscription('EQW::ZoneUpdate', wsi, api); common.RegisterSubscription('EQW::ClientUpdate', wsi, api); }; diff --git a/wi/ws/wi_common.js b/wi/ws/wi_common.js index a823e7431..a2712783a 100644 --- a/wi/ws/wi_common.js +++ b/wi/ws/wi_common.js @@ -24,4 +24,4 @@ function RegisterSubscription(event, wsi, api) { module.exports = { 'Register': Register, 'RegisterSubscription': RegisterSubscription -} \ No newline at end of file +} diff --git a/world/clientlist.cpp b/world/clientlist.cpp index 73f78f683..8f7aa3705 100644 --- a/world/clientlist.cpp +++ b/world/clientlist.cpp @@ -30,6 +30,7 @@ #include "../common/misc.h" #include "../common/misc_functions.h" #include "../common/json/json.h" +#include "../common/event_sub.h" #include "web_interface.h" #include "wguild_mgr.h" #include @@ -1365,6 +1366,10 @@ void ClientList::SendClientVersionSummary(const char *Name) void ClientList::OnTick(EQ::Timer *t) { + if (!EventSubscriptionWatcher::Get()->IsSubscribed("EQW::ClientUpdate")) { + return; + } + Json::Value out; out["event"] = "EQW::ClientUpdate"; out["data"] = Json::Value(); diff --git a/world/login_server_list.cpp b/world/login_server_list.cpp index 297c3a343..d8951847a 100644 --- a/world/login_server_list.cpp +++ b/world/login_server_list.cpp @@ -52,112 +52,89 @@ LoginServerList::~LoginServerList() { void LoginServerList::Add(const char* iAddress, uint16 iPort, const char* Account, const char* Password, bool Legacy) { auto loginserver = new LoginServer(iAddress, iPort, Account, Password, Legacy); - list.Insert(loginserver); + m_list.push_back(std::unique_ptr(loginserver)); } bool LoginServerList::SendInfo() { - LinkedListIterator iterator(list); - - iterator.Reset(); - while(iterator.MoreElements()){ - iterator.GetData()->SendInfo(); - iterator.Advance(); + for (auto &iter : m_list) { + (*iter).SendInfo(); } + return true; } bool LoginServerList::SendNewInfo() { - LinkedListIterator iterator(list); - - iterator.Reset(); - while(iterator.MoreElements()){ - iterator.GetData()->SendNewInfo(); - iterator.Advance(); + for (auto &iter : m_list) { + (*iter).SendNewInfo(); } + return true; } bool LoginServerList::SendStatus() { - LinkedListIterator iterator(list); - - iterator.Reset(); - while(iterator.MoreElements()){ - iterator.GetData()->SendStatus(); - iterator.Advance(); + for (auto &iter : m_list) { + (*iter).SendStatus(); } + return true; } bool LoginServerList::SendPacket(ServerPacket* pack) { - LinkedListIterator iterator(list); - - iterator.Reset(); - while(iterator.MoreElements()){ - iterator.GetData()->SendPacket(pack); - iterator.Advance(); + for (auto &iter : m_list) { + (*iter).SendPacket(pack); } + return true; } bool LoginServerList::SendAccountUpdate(ServerPacket* pack) { - LinkedListIterator iterator(list); - Log.Out(Logs::Detail, Logs::World_Server, "Requested to send ServerOP_LSAccountUpdate packet to all loginservers"); - iterator.Reset(); - while(iterator.MoreElements()){ - if(iterator.GetData()->CanUpdate()) { - iterator.GetData()->SendAccountUpdate(pack); + for (auto &iter : m_list) { + if ((*iter).CanUpdate()) { + (*iter).SendAccountUpdate(pack); } - iterator.Advance(); } + return true; } bool LoginServerList::Connected() { - LinkedListIterator iterator(list); - - iterator.Reset(); - while(iterator.MoreElements()){ - if(iterator.GetData()->Connected()) + for (auto &iter : m_list) { + if ((*iter).Connected()) { return true; - iterator.Advance(); + } } + return false; } bool LoginServerList::AllConnected() { - LinkedListIterator iterator(list); - - iterator.Reset(); - while(iterator.MoreElements()){ - if(iterator.GetData()->Connected() == false) + for (auto &iter : m_list) { + if (!(*iter).Connected()) { return false; - iterator.Advance(); + } } + return true; } bool LoginServerList::MiniLogin() { - LinkedListIterator iterator(list); - - iterator.Reset(); - while(iterator.MoreElements()){ - if(iterator.GetData()->MiniLogin()) + for (auto &iter : m_list) { + if ((*iter).MiniLogin()) { return true; - iterator.Advance(); + } } + return false; } bool LoginServerList::CanUpdate() { - LinkedListIterator iterator(list); - - iterator.Reset(); - while(iterator.MoreElements()){ - if(iterator.GetData()->CanUpdate()) + for (auto &iter : m_list) { + if ((*iter).CanUpdate()) { return true; - iterator.Advance(); + } } + return false; } diff --git a/world/login_server_list.h b/world/login_server_list.h index 05bff76d5..56806f704 100644 --- a/world/login_server_list.h +++ b/world/login_server_list.h @@ -2,11 +2,11 @@ #define LOGINSERVERLIST_H_ #include "../common/servertalk.h" -#include "../common/linked_list.h" #include "../common/timer.h" #include "../common/queue.h" #include "../common/eq_packet_structs.h" #include "../common/mutex.h" +#include class LoginServer; @@ -27,9 +27,10 @@ public: bool AllConnected(); bool MiniLogin(); bool CanUpdate(); + size_t GetServerCount() const { return m_list.size(); } protected: - LinkedList list; + std::list> m_list; }; diff --git a/world/ucs.cpp b/world/ucs.cpp index 7830561ac..4208bc24a 100644 --- a/world/ucs.cpp +++ b/world/ucs.cpp @@ -21,7 +21,9 @@ void UCSConnection::SetConnection(std::shared_ptrOnMessage(std::bind(&UCSConnection::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2)); + if (Stream) { + Stream->OnMessage(std::bind(&UCSConnection::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2)); + } } void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p) diff --git a/world/web_interface.cpp b/world/web_interface.cpp index e2d14e62d..191d8cca1 100644 --- a/world/web_interface.cpp +++ b/world/web_interface.cpp @@ -65,7 +65,7 @@ void WebInterface::OnCall(uint16 opcode, EQ::Net::Packet &p) auto iter = m_calls.find(method); if (iter == m_calls.end()) { //if not exist then error - SendError("Invalid request: method not found"); + SendError("Invalid request: method not found", id); return; } @@ -99,6 +99,7 @@ void WebInterface::SendError(const std::string &message) void WebInterface::SendError(const std::string &message, const std::string &id) { Json::Value error; + error["id"] = id; error["error"] = Json::Value(); error["error"]["message"] = message; diff --git a/world/web_interface_eqw.cpp b/world/web_interface_eqw.cpp index 720947643..ad0cf6953 100644 --- a/world/web_interface_eqw.cpp +++ b/world/web_interface_eqw.cpp @@ -2,8 +2,29 @@ #include "web_interface.h" #include "world_config.h" #include "login_server_list.h" +#include "clientlist.h" +#include "zonelist.h" +#include "launcher_list.h" extern LoginServerList loginserverlist; +extern ClientList client_list; +extern ZSList zoneserver_list; +extern LauncherList launcher_list; + +void EQW__GetConfig(WebInterface *i, const std::string& method, const std::string& id, const Json::Value& params) { + if (params.isArray() && params.size() == 1) { + auto config_name = params[0]; + if (config_name.isString()) { + auto config = config_name.asString(); + + Json::Value ret = WorldConfig::get()->GetByName(config); + i->SendResponse(id, ret); + return; + } + } + + i->SendError("EBADPARAMS", id); +} void EQW__IsLocked(WebInterface *i, const std::string& method, const std::string& id, const Json::Value& params) { Json::Value ret = WorldConfig::get()->Locked; @@ -32,9 +53,34 @@ void EQW__Unlock(WebInterface *i, const std::string& method, const std::string& i->SendResponse(id, ret); } +void EQW__GetPlayerCount(WebInterface *i, const std::string& method, const std::string& id, const Json::Value& params) { + Json::Value ret = client_list.GetClientCount(); + i->SendResponse(id, ret); +} + +void EQW__GetZoneCount(WebInterface *i, const std::string& method, const std::string& id, const Json::Value& params) { + Json::Value ret = zoneserver_list.GetZoneCount(); + i->SendResponse(id, ret); +} + +void EQW__GetLauncherCount(WebInterface *i, const std::string& method, const std::string& id, const Json::Value& params) { + Json::Value ret = launcher_list.GetLauncherCount(); + i->SendResponse(id, ret); +} + +void EQW__GetLoginServerCount(WebInterface *i, const std::string& method, const std::string& id, const Json::Value& params) { + Json::Value ret = loginserverlist.GetServerCount(); + i->SendResponse(id, ret); +} + void RegisterEQW(WebInterface *i) { + i->AddCall("EQW::GetConfig", std::bind(EQW__GetConfig, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); i->AddCall("EQW::IsLocked", std::bind(EQW__IsLocked, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); i->AddCall("EQW::Lock", std::bind(EQW__Lock, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); i->AddCall("EQW::Unlock", std::bind(EQW__Unlock, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + i->AddCall("EQW::GetPlayerCount", std::bind(EQW__GetPlayerCount, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + i->AddCall("EQW::GetZoneCount", std::bind(EQW__GetZoneCount, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + i->AddCall("EQW::GetLauncherCount", std::bind(EQW__GetLauncherCount, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + i->AddCall("EQW::GetLoginServerCount", std::bind(EQW__GetLoginServerCount, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); } diff --git a/world/zonelist.cpp b/world/zonelist.cpp index 04fa15111..ae8f26e6f 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -25,6 +25,7 @@ #include "../common/string_util.h" #include "../common/random.h" #include "../common/json/json.h" +#include "../common/event_sub.h" #include "web_interface.h" extern uint32 numzones; @@ -657,7 +658,7 @@ void ZSList::SendLSZones(){ } int ZSList::GetZoneCount() { - return(numzones); + return(list.size()); } void ZSList::GetZoneIDList(std::vector &zones) { @@ -698,6 +699,10 @@ void ZSList::WorldShutDown(uint32 time, uint32 interval) void ZSList::OnTick(EQ::Timer *t) { + if (!EventSubscriptionWatcher::Get()->IsSubscribed("EQW::ZoneUpdate")) { + return; + } + Json::Value out; out["event"] = "EQW::ZoneUpdate"; out["data"] = Json::Value();