From 40b555a55b155a99dcf62c21c6f4773f7e0173d8 Mon Sep 17 00:00:00 2001 From: KimLS Date: Fri, 1 Aug 2014 18:29:41 -0700 Subject: [PATCH] More work on subscription events, and relaying through world. --- common/servertalk.h | 4 +- web_interface/method_handler.cpp | 11 ++- web_interface/remote_call.cpp | 15 +++ web_interface/worldserver.cpp | 125 +++++++++++++++++++++--- world/remote_call.cpp | 70 +++++++------- world/remote_call.h | 2 +- world/web_interface.cpp | 22 +++++ world/zoneserver.cpp | 7 ++ zone/CMakeLists.txt | 4 + zone/client_logs.cpp | 2 - zone/mob.cpp | 47 ++++++--- zone/net.cpp | 9 +- zone/remote_call.cpp | 112 ++++++++++++++++++++++ zone/remote_call.h | 36 +++++++ zone/remote_call_subscribe.cpp | 159 +++++++++++++++++++++++++++++++ zone/remote_call_subscribe.h | 51 ++++++++++ zone/worldserver.cpp | 50 +++++++++- zone/zone.cpp | 3 + 18 files changed, 657 insertions(+), 72 deletions(-) create mode 100644 zone/remote_call.cpp create mode 100644 zone/remote_call.h create mode 100644 zone/remote_call_subscribe.cpp create mode 100644 zone/remote_call_subscribe.h diff --git a/common/servertalk.h b/common/servertalk.h index 48c7e4c7b..e7998362e 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -188,7 +188,9 @@ #define ServerOP_WIRemoteCall 0x5001 #define ServerOP_WIRemoteCallResponse 0x5002 -#define ServerOP_WIClientSession 0x5003 +#define ServerOP_WIRemoteCallToClient 0x5003 +#define ServerOP_WIClientSession 0x5004 +#define ServerOP_WIClientSessionResponse 0x5005 enum { QSG_LFGuild = 0 }; enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_RequestPlayerInfo, QSG_LFGuild_UpdateGuildInfo, QSG_LFGuild_GuildMatches, diff --git a/web_interface/method_handler.cpp b/web_interface/method_handler.cpp index 1238729c2..fc01538a5 100644 --- a/web_interface/method_handler.cpp +++ b/web_interface/method_handler.cpp @@ -8,15 +8,16 @@ extern std::map unauthorized_methods; void register_authorized_methods() { - authorized_methods["token_auth"] = std::make_pair(0, handle_method_token_auth); - authorized_methods["list_zones"] = std::make_pair(10, handle_method_no_args); - authorized_methods["get_zone_info"] = std::make_pair(10, handle_method_get_zone_info); - authorized_methods["subscribe"] = std::make_pair(10, handle_method_subscribe); + authorized_methods["WebInterface::Authorize"] = std::make_pair(0, handle_method_token_auth); + authorized_methods["World::ListZones"] = std::make_pair(10, handle_method_no_args); + authorized_methods["World::GetZoneDetails"] = std::make_pair(10, handle_method_get_zone_info); + authorized_methods["Zone::Subscribe"] = std::make_pair(10, handle_method_subscribe); + authorized_methods["Zone::Unsubscribe"] = std::make_pair(10, handle_method_subscribe); } void register_unauthorized_methods() { - unauthorized_methods["token_auth"] = handle_method_token_auth; + unauthorized_methods["WebInterface::Authorize"] = handle_method_token_auth; } void register_methods() diff --git a/web_interface/remote_call.cpp b/web_interface/remote_call.cpp index 79d6fa760..891490cea 100644 --- a/web_interface/remote_call.cpp +++ b/web_interface/remote_call.cpp @@ -13,8 +13,13 @@ void WriteWebCallResponseString(per_session_data_eqemu *session, rapidjson::Docu else { writer.String(doc["id"].GetString()); } + writer.String("result"); + writer.StartObject(); + writer.String("value"); writer.String(result.c_str()); + writer.EndObject(); + writer.String("error"); if (error) { writer.Bool(true); @@ -39,8 +44,13 @@ void WriteWebCallResponseInt(per_session_data_eqemu *session, rapidjson::Documen else { writer.String(doc["id"].GetString()); } + writer.String("result"); + writer.StartObject(); + writer.String("value"); writer.Int(result); + writer.EndObject(); + writer.String("error"); if (error) { writer.Bool(true); @@ -65,8 +75,13 @@ void WriteWebCallResponseBoolean(per_session_data_eqemu *session, rapidjson::Doc else { writer.String(doc["id"].GetString()); } + writer.String("result"); + writer.StartObject(); + writer.String("value"); writer.Bool(result); + writer.EndObject(); + writer.String("error"); if (error) { writer.Bool(true); diff --git a/web_interface/worldserver.cpp b/web_interface/worldserver.cpp index a4d4f9355..5f4206484 100644 --- a/web_interface/worldserver.cpp +++ b/web_interface/worldserver.cpp @@ -74,17 +74,24 @@ void WorldServer::Process(){ pack->ReadString(error); uint32 param_count = pack->ReadUInt32(); - std::vector params; + std::map params; for(uint32 i = 0; i < param_count; ++i) { - char *p = new char[pack->ReadUInt32() + 1]; - pack->ReadString(p); - params.push_back(p); - safe_delete_array(p); + char *first = new char[pack->ReadUInt32() + 1]; + pack->ReadString(first); + + char *second = new char[pack->ReadUInt32() + 1]; + pack->ReadString(second); + + params[first] = second; + + safe_delete_array(first); + safe_delete_array(second); } //send the response to client... rapidjson::StringBuffer s; rapidjson::Writer writer(s); + writer.StartObject(); writer.String("id"); if(strlen(id) == 0) { @@ -103,14 +110,15 @@ void WorldServer::Process(){ writer.String("error"); writer.Null(); writer.String("result"); - writer.StartArray(); - uint32 p_sz = (uint32)params.size(); - for(uint32 i = 0; i < p_sz; ++i) { - writer.String(params[i].c_str()); + writer.StartObject(); + auto iter = params.begin(); + while(iter != params.end()) { + writer.String(iter->first.c_str()); + writer.String(iter->second.c_str()); + ++iter; } - writer.EndArray(); + writer.EndObject(); } - writer.EndObject(); if(sessions.count(session_id) != 0) { @@ -123,6 +131,101 @@ void WorldServer::Process(){ safe_delete_array(error); break; } + + case ServerOP_WIRemoteCallToClient: + { + char *session_id = nullptr; + char *method = nullptr; + + DumpPacket(pack); + + session_id = new char[pack->ReadUInt32() + 1]; + pack->ReadString(session_id); + + method = new char[pack->ReadUInt32() + 1]; + pack->ReadString(method); + + uint32 param_count = pack->ReadUInt32(); + std::vector params(param_count); + for(uint32 i = 0; i < param_count; ++i) { + char *p = new char[pack->ReadUInt32() + 1]; + pack->ReadString(p); + params[i] = p; + + safe_delete_array(p); + } + + rapidjson::StringBuffer s; + rapidjson::Writer writer(s); + + writer.StartObject(); + writer.String("id"); + writer.Null(); + + writer.String("method"); + writer.String(method); + + writer.String("params"); + writer.StartArray(); + + for(uint32 i = 0; i < param_count; ++i) { + writer.String(params[i].c_str()); + } + + writer.EndArray(); + + writer.EndObject(); + + if(sessions.count(session_id) != 0) { + per_session_data_eqemu *session = sessions[session_id]; + session->send_queue->push_back(s.GetString()); + } + + safe_delete_array(session_id); + safe_delete_array(method); + break; + } + + case ServerOP_WIClientSession: + { + std::vector invalidate; + uint32 zone_id = pack->ReadUInt32(); + uint32 instance_id = pack->ReadUInt32(); + uint32 count = pack->ReadUInt32(); + for(uint32 i = 0; i < count; ++i) { + char *p = new char[pack->ReadUInt32() + 1]; + pack->ReadString(p); + + if(sessions.count(p) == 0) { + invalidate.push_back(p); + } + + safe_delete_array(p); + } + + if(invalidate.size() != 0) { + uint32 sz = 12; + size_t isz = invalidate.size(); + for(size_t i = 0; i < isz; ++i) { + sz += invalidate[i].size(); + sz += 5; + } + + ServerPacket *pack = new ServerPacket(ServerOP_WIClientSessionResponse, sz); + pack->WriteUInt32((uint32)zone_id); + pack->WriteUInt32((uint32)instance_id); + pack->WriteUInt32((uint32)invalidate.size()); + for(size_t i = 0; i < isz; ++i) { + pack->WriteUInt32((uint32)invalidate[i].size()); + pack->WriteString(invalidate[i].c_str()); + } + + SendPacket(pack); + safe_delete(pack); + } + + break; + } } } diff --git a/world/remote_call.cpp b/world/remote_call.cpp index b4d73e9c1..2a35dbc2e 100644 --- a/world/remote_call.cpp +++ b/world/remote_call.cpp @@ -16,11 +16,12 @@ extern ZSList zoneserver_list; extern WebInterfaceConnection WILink; std::map remote_call_methods; -void RemoteCallResponse(const std::string &connection_id, const std::string &request_id, const std::vector &res, const std::string &error) { +void RemoteCallResponse(const std::string &connection_id, const std::string &request_id, const std::map &res, const std::string &error) { uint32 sz = (uint32)(connection_id.size() + request_id.size() + error.size() + 3 + 16); - uint32 res_sz = (uint32)res.size(); - for(uint32 i = 0; i < res_sz; ++i) { - sz += (uint32)res[i].size() + 5; + auto iter = res.begin(); + while(iter != res.end()) { + sz += (uint32)iter->first.size() + (uint32)iter->second.size() + 10; + ++iter; } ServerPacket *pack = new ServerPacket(ServerOP_WIRemoteCallResponse, sz); @@ -30,30 +31,35 @@ void RemoteCallResponse(const std::string &connection_id, const std::string &req pack->WriteString(connection_id.c_str()); pack->WriteUInt32((uint32)error.size()); pack->WriteString(error.c_str()); - pack->WriteUInt32((uint32)res_sz); - for (uint32 i = 0; i < res_sz; ++i) { - auto &r = res[i]; - pack->WriteUInt32((uint32)r.size()); - pack->WriteString(r.c_str()); + pack->WriteUInt32((uint32)res.size()); + iter = res.begin(); + while(iter != res.end()) { + pack->WriteUInt32((uint32)iter->first.size()); + pack->WriteString(iter->first.c_str()); + pack->WriteUInt32((uint32)iter->second.size()); + pack->WriteString(iter->second.c_str()); + ++iter; } WILink.SendPacket(pack); + safe_delete(pack); } void register_remote_call_handlers() { - remote_call_methods["list_zones"] = handle_rc_list_zones; - remote_call_methods["get_zone_info"] = handle_rc_get_zone_info; - remote_call_methods["subscribe"] = handle_rc_relay; + remote_call_methods["World::ListZones"] = handle_rc_list_zones; + remote_call_methods["World::GetZoneDetails"] = handle_rc_get_zone_info; + remote_call_methods["Zone::Subscribe"] = handle_rc_relay; + remote_call_methods["Zone::Unsubscribe"] = handle_rc_relay; } void handle_rc_list_zones(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms) { std::vector zones; zoneserver_list.GetZoneIDList(zones); - std::vector res; + std::map res; uint32 sz = (uint32)zones.size(); for(uint32 i = 0; i < sz; ++i) { - res.push_back(itoa(zones[i])); + res[itoa(i)] = (itoa(zones[i])); } std::string error; @@ -62,7 +68,7 @@ void handle_rc_list_zones(const std::string &method, const std::string &connecti void handle_rc_get_zone_info(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms) { std::string error; - std::vector res; + std::map res; if(params.size() != 1) { error = "Expected only one zone_id."; RemoteCallResponse(connection_id, request_id, res, error); @@ -76,25 +82,25 @@ void handle_rc_get_zone_info(const std::string &method, const std::string &conne return; } - res.push_back(zs->IsStaticZone() ? "static" : "dynamic"); - res.push_back(itoa(zs->GetZoneID())); - res.push_back(itoa(zs->GetInstanceID())); - res.push_back(zs->GetLaunchName()); - res.push_back(zs->GetLaunchedName()); - res.push_back(zs->GetZoneName()); - res.push_back(zs->GetZoneLongName()); - res.push_back(itoa(zs->GetCPort())); - res.push_back(itoa(zs->NumPlayers())); + res["type"] = zs->IsStaticZone() ? "static" : "dynamic"; + res["zone_id"] = itoa(zs->GetZoneID()); + res["instance_id"] = itoa(zs->GetInstanceID()); + res["launch_name"] = zs->GetLaunchName(); + res["launched_name"] = zs->GetLaunchedName(); + res["short_name"] = zs->GetZoneName(); + res["long_name"] = zs->GetZoneLongName(); + res["port"] = itoa(zs->GetCPort()); + res["num_players"] = itoa(zs->NumPlayers()); RemoteCallResponse(connection_id, request_id, res, error); } void handle_rc_relay(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms) { std::string error; - std::vector res; + std::map res; uint32 zone_id = 0; uint32 instance_id = 0; ZoneServer *zs = nullptr; - + if(params.size() < 2) { error = "Missing zone relay params"; RemoteCallResponse(connection_id, request_id, res, error); @@ -108,8 +114,8 @@ void handle_rc_relay(const std::string &method, const std::string &connection_id RemoteCallResponse(connection_id, request_id, res, error); return; } - - + + if(instance_id) { zs = zoneserver_list.FindByInstanceID(instance_id); } else { @@ -121,7 +127,7 @@ void handle_rc_relay(const std::string &method, const std::string &connection_id RemoteCallResponse(connection_id, request_id, res, error); return; } - + uint32 sz = (uint32)(request_id.size() + connection_id.size() + method.size() + 3 + 16); uint32 p_sz = (uint32)params.size() - 2; for(uint32 i = 0; i < p_sz; ++i) { @@ -129,7 +135,7 @@ void handle_rc_relay(const std::string &method, const std::string &connection_id sz += (uint32)param.size(); sz += 5; } - + ServerPacket *pack = new ServerPacket(ServerOP_WIRemoteCall, sz); pack->WriteUInt32((uint32)request_id.size()); pack->WriteString(request_id.c_str()); @@ -138,13 +144,13 @@ void handle_rc_relay(const std::string &method, const std::string &connection_id pack->WriteUInt32((uint32)method.size()); pack->WriteString(method.c_str()); pack->WriteUInt32(p_sz); - + for(uint32 i = 0; i < p_sz; ++i) { auto ¶m = params[i + 2]; pack->WriteUInt32((uint32)param.size()); pack->WriteString(param.c_str()); } - + zs->SendPacket(pack); safe_delete(pack); } diff --git a/world/remote_call.h b/world/remote_call.h index fb10ba729..cfdf28e38 100644 --- a/world/remote_call.h +++ b/world/remote_call.h @@ -24,7 +24,7 @@ typedef void(*RemoteCallHandler)(const std::string&, const std::string&, const std::string&, const std::vector&); -void RemoteCallResponse(const std::string &connection_id, const std::string &request_id, const std::vector &res, const std::string &error); +void RemoteCallResponse(const std::string &connection_id, const std::string &request_id, const std::map &res, const std::string &error); void register_remote_call_handlers(); void handle_rc_list_zones(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms); diff --git a/world/web_interface.cpp b/world/web_interface.cpp index ec450e46c..d3349f9b3 100644 --- a/world/web_interface.cpp +++ b/world/web_interface.cpp @@ -3,6 +3,7 @@ #include "WorldConfig.h" #include "clientlist.h" #include "zonelist.h" +#include "zoneserver.h" #include "remote_call.h" #include "../common/logsys.h" #include "../common/logtypes.h" @@ -135,6 +136,27 @@ bool WebInterfaceConnection::Process() safe_delete_array(method); break; } + case ServerOP_WIClientSessionResponse: { + uint32 zone_id = pack->ReadUInt32(); + uint32 instance_id = pack->ReadUInt32(); + + ZoneServer *zs = nullptr; + if(instance_id != 0) { + zs = zoneserver_list.FindByInstanceID(instance_id); + } else { + zs = zoneserver_list.FindByZoneID(zone_id); + } + + if(zs) { + ServerPacket *npack = new ServerPacket(ServerOP_WIClientSessionResponse, pack->size - 8); + memcpy(npack->pBuffer, pack->pBuffer + 8, pack->size - 8); + + zs->SendPacket(npack); + safe_delete(npack); + } + + break; + } default: { _log(WEB_INTERFACE__ERROR, "Unknown ServerOPcode from WebInterface 0x%04x, size %d", pack->opcode, pack->size); diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 0d0d00745..abe548751 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1300,6 +1300,13 @@ bool ZoneServer::Process() { QSLink.SendPacket(pack); break; } + case ServerOP_WIRemoteCallResponse: + case ServerOP_WIClientSession: + case ServerOP_WIRemoteCallToClient: + { + WILink.SendPacket(pack); + break; + } case ServerOP_CZSignalClientByName: case ServerOP_CZMessagePlayer: case ServerOP_CZSignalClient: diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index 9f7250d4e..7afe9ddd4 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -97,6 +97,8 @@ SET(zone_sources QuestParserCollection.cpp raids.cpp RaycastMesh.cpp + remote_call.cpp + remote_call_subscribe.cpp spawn2.cpp spawn2.h spawngroup.cpp @@ -189,6 +191,8 @@ SET(zone_headers raid.h raids.h RaycastMesh.h + remote_call.h + remote_call_subscribe.h skills.h spawn2.cpp spawn2.h diff --git a/zone/client_logs.cpp b/zone/client_logs.cpp index e51a51996..c130cd698 100644 --- a/zone/client_logs.cpp +++ b/zone/client_logs.cpp @@ -40,12 +40,10 @@ void ClientLogs::subscribe(EQEMuLog::LogIDs id, Client *c) { end = entries[id].end(); for(; cur != end; ++cur) { if(*cur == c) { - printf("%s was allready subscribed to %d\n", c->GetName(), id); return; } } - printf("%s has been subscribed to %d\n", c->GetName(), id); entries[id].push_back(c); } diff --git a/zone/mob.cpp b/zone/mob.cpp index a62ce5995..877fe336a 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -18,10 +18,12 @@ #include "../common/debug.h" #include "masterentity.h" #include "../common/spdat.h" +#include "../common/StringUtil.h" #include "StringIDs.h" #include "worldserver.h" #include "QuestParserCollection.h" -#include "../common/StringUtil.h" +#include "remote_call.h" +#include "remote_call_subscribe.h" #include #include @@ -1213,19 +1215,34 @@ void Mob::MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct *spu){ spu->padding0014 =0x7f; spu->padding0018 =0x5df27; - ///* Testing */ - //if (IsNPC() && WS_Client_Connected.size() != 0){ - // std::string str = MakeJSON("ResponseType:PositionUpdate,entity:" + std::to_string(GetID()) + ",name:" + GetName() + ",x:" + std::to_string(x_pos) + ",y:" + std::to_string(y_pos) + ",z:" + std::to_string(z_pos) + ",h:" + std::to_string(heading)); - // char * writable = new char[str.size() + 1]; - // std::copy(str.begin(), str.end(), writable); - // ServerPacket* pack = new ServerPacket(ServerOP_WIWorldResponse, sizeof(WI_Client_Response_Struct)+str.length() + 1); - // WI_Client_Response_Struct* WICR = (WI_Client_Response_Struct*)pack->pBuffer; - // strn0cpy(WICR->Client_UUID, WS_Client_Connected.c_str(), 64); - // strn0cpy(WICR->JSON_Data, str.c_str(), str.length() + 1); - // if (worldserver.Connected()) { worldserver.SendPacket(pack); } - // safe_delete(pack); - // delete[] writable; - //} + if(IsNPC()) { + //zone_id + //instance_id + //entity_id + //x + //y + //z + //h + const auto &conns = RemoteCallSubscriptionHandler::Instance()->GetSubscribers("NPC::MakeSpawnUpdateNoDelta"); + if(conns.size() > 0) { + std::string method = "NPC::MakeSpawnUpdateNoDelta"; + std::vector params; + params.push_back(std::to_string((long)zone->GetZoneID())); + params.push_back(std::to_string((long)zone->GetInstanceID())); + params.push_back(std::to_string((long)GetID())); + params.push_back(GetName()); + params.push_back(std::to_string((double)x_pos)); + params.push_back(std::to_string((double)y_pos)); + params.push_back(std::to_string((double)z_pos)); + params.push_back(std::to_string((double)heading)); + + auto &iter = conns.begin(); + while(iter != conns.end()) { + RemoteCall((*iter), method, params); + ++iter; + } + } + } } // this is for SendPosUpdate() @@ -1245,7 +1262,7 @@ void Mob::MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu) { if(this->IsClient()) spu->animation = animation; else - spu->animation = pRunAnimSpeed;//animation; + spu->animation = pRunAnimSpeed; spu->delta_heading = NewFloatToEQ13(static_cast(delta_heading)); } diff --git a/zone/net.cpp b/zone/net.cpp index 15e108e42..cb88502c5 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -53,12 +53,13 @@ #include "titles.h" #include "guild_mgr.h" #include "tasks.h" - #include "QuestParserCollection.h" #include "embparser.h" #include "lua_parser.h" #include "client_logs.h" #include "questmgr.h" +#include "remote_call.h" +#include "remote_call_subscribe.h" #include #include @@ -111,6 +112,7 @@ extern void MapOpcodes(); int main(int argc, char** argv) { RegisterExecutablePlatform(ExePlatformZone); set_exception_handler(); + register_remote_call_handlers(); const char *zone_name; @@ -310,6 +312,7 @@ int main(int argc, char** argv) { } Timer InterserverTimer(INTERSERVER_TIMER); // does MySQL pings and auto-reconnect + Timer RemoteCallProcessTimer(5000); #ifdef EQPROFILE #ifdef PROFILE_DUMP_TIME Timer profile_dump_timer(PROFILE_DUMP_TIME*1000); @@ -403,6 +406,10 @@ int main(int argc, char** argv) { worldwasconnected = false; } + if(RemoteCallProcessTimer.Check()) { + RemoteCallSubscriptionHandler::Instance()->Process(); + } + if (ZoneLoaded && zoneupdate_timer.Check()) { { if(net.group_timer.Enabled() && net.group_timer.Check()) diff --git a/zone/remote_call.cpp b/zone/remote_call.cpp new file mode 100644 index 000000000..7f68e7ef9 --- /dev/null +++ b/zone/remote_call.cpp @@ -0,0 +1,112 @@ +#include "../common/debug.h" +#include "../common/logsys.h" +#include "../common/logtypes.h" +#include "../common/md5.h" +#include "../common/EmuTCPConnection.h" +#include "../common/packet_functions.h" +#include "../common/packet_dump.h" +#include "../common/servertalk.h" +#include "remote_call.h" +#include "remote_call_subscribe.h" +#include "worldserver.h" + +std::map remote_call_methods; +extern WorldServer worldserver; + +void RemoteCallResponse(const std::string &connection_id, const std::string &request_id, const std::map &res, const std::string &error) { + uint32 sz = (uint32)(connection_id.size() + request_id.size() + error.size() + 3 + 16); + auto iter = res.begin(); + while(iter != res.end()) { + sz += (uint32)iter->first.size() + (uint32)iter->second.size() + 10; + ++iter; + } + + ServerPacket *pack = new ServerPacket(ServerOP_WIRemoteCallResponse, sz); + pack->WriteUInt32((uint32)request_id.size()); + pack->WriteString(request_id.c_str()); + pack->WriteUInt32((uint32)connection_id.size()); + pack->WriteString(connection_id.c_str()); + pack->WriteUInt32((uint32)error.size()); + pack->WriteString(error.c_str()); + pack->WriteUInt32((uint32)res.size()); + iter = res.begin(); + while(iter != res.end()) { + pack->WriteUInt32((uint32)iter->first.size()); + pack->WriteString(iter->first.c_str()); + pack->WriteUInt32((uint32)iter->second.size()); + pack->WriteString(iter->second.c_str()); + ++iter; + } + + worldserver.SendPacket(pack); + safe_delete(pack); +} + +void RemoteCall(const std::string &connection_id, const std::string &method, const std::vector ¶ms) { + uint32 sz = (uint32)(connection_id.size() + method.size() + 14); + auto iter = params.begin(); + while(iter != params.end()) { + sz += (uint32)iter->size() + 5; + ++iter; + } + + ServerPacket *pack = new ServerPacket(ServerOP_WIRemoteCallToClient, sz); + pack->WriteUInt32((uint32)connection_id.size()); + pack->WriteString(connection_id.c_str()); + pack->WriteUInt32((uint32)method.size()); + pack->WriteString(method.c_str()); + pack->WriteUInt32((uint32)params.size()); + iter = params.begin(); + while(iter != params.end()) { + pack->WriteUInt32((uint32)iter->size()); + pack->WriteString(iter->c_str()); + ++iter; + } + + worldserver.SendPacket(pack); + safe_delete(pack); +} + +void register_remote_call_handlers() { + remote_call_methods["Zone::Subscribe"] = handle_rc_subscribe; + remote_call_methods["Zone::Unsubscribe"] = handle_rc_unsubscribe; +} + +void handle_rc_subscribe(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms) { + std::string error; + std::map res; + + if(params.size() != 1) { + error = "Missing event to subscribe to"; + RemoteCallResponse(connection_id, request_id, res, error); + return; + } + + if(RemoteCallSubscriptionHandler::Instance()->Subscribe(connection_id, params[0])) { + res["status"] = "subscribed"; + } else { + res["status"] = "failed to subscribe"; + } + + RemoteCallResponse(connection_id, request_id, res, error); +} + +void handle_rc_unsubscribe(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms) { + std::string error; + std::map res; + + if(params.size() != 1) { + error = "Missing event to unsubscribe from"; + RemoteCallResponse(connection_id, request_id, res, error); + return; + } + + if(RemoteCallSubscriptionHandler::Instance()->Subscribe(connection_id, params[0])) { + res["status"] = "unsubscribed"; + } + else { + res["status"] = "failed to unsubscribe"; + } + + RemoteCallResponse(connection_id, request_id, res, error); +} diff --git a/zone/remote_call.h b/zone/remote_call.h new file mode 100644 index 000000000..fa46c4471 --- /dev/null +++ b/zone/remote_call.h @@ -0,0 +1,36 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) + + 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 ZONE_REMOTE_CALL_H +#define ZONE_REMOTE_CALL_H + +#include +#include +#include + +typedef void(*RemoteCallHandler)(const std::string&, const std::string&, const std::string&, const std::vector&); + +void RemoteCallResponse(const std::string &connection_id, const std::string &request_id, const std::map &res, const std::string &error); +void RemoteCall(const std::string &connection_id, const std::string &method, const std::vector ¶ms); + +void register_remote_call_handlers(); + +void handle_rc_subscribe(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms); +void handle_rc_unsubscribe(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms); + +#endif + diff --git a/zone/remote_call_subscribe.cpp b/zone/remote_call_subscribe.cpp new file mode 100644 index 000000000..c39ac8b80 --- /dev/null +++ b/zone/remote_call_subscribe.cpp @@ -0,0 +1,159 @@ +#include "../common/debug.h" +#include "../common/logsys.h" +#include "../common/logtypes.h" +#include "../common/md5.h" +#include "../common/EmuTCPConnection.h" +#include "../common/packet_functions.h" +#include "../common/packet_dump.h" +#include "../common/servertalk.h" +#include "remote_call_subscribe.h" +#include "worldserver.h" +#include "zone.h" + +extern WorldServer worldserver; +extern Zone* zone; + +RemoteCallSubscriptionHandler* RemoteCallSubscriptionHandler::_instance = nullptr; + +RemoteCallSubscriptionHandler::RemoteCallSubscriptionHandler() { +} + +RemoteCallSubscriptionHandler::~RemoteCallSubscriptionHandler() { +} + +RemoteCallSubscriptionHandler *RemoteCallSubscriptionHandler::Instance() +{ + if(!_instance) { + _instance = new RemoteCallSubscriptionHandler(); + } + + return _instance; +} + +bool RemoteCallSubscriptionHandler::Subscribe(std::string connection_id, std::string event_name) { + if(registered_events.count(event_name) == 0) { + std::vector r; + r.push_back(connection_id); + registered_events[event_name] = r; + + if(connection_ids.count(connection_id) == 0) { + connection_ids[connection_id] = 1; + } else { + int count = connection_ids[connection_id]; + connection_ids[connection_id] = count + 1; + } + + return true; + } else { + std::vector& r = registered_events[event_name]; + + size_t sz = r.size(); + for(size_t i = 0; i < sz; ++i) { + if(connection_id.compare(r[i]) == 0) { + return false; + } + } + + r.push_back(connection_id); + registered_events[event_name] = r; + + if(connection_ids.count(connection_id) == 0) { + connection_ids[connection_id] = 1; + } + else { + int count = connection_ids[connection_id]; + connection_ids[connection_id] = count + 1; + } + + return true; + } +} + +bool RemoteCallSubscriptionHandler::Unsubscribe(std::string connection_id, std::string event_name) { + if(registered_events.count(event_name) == 0) { + return false; + } + + std::vector& r = registered_events[event_name]; + auto iter = r.begin(); + while(iter != r.end()) { + if(iter->compare(connection_id) == 0) { + r.erase(iter); + registered_events[event_name] = r; + + int count = connection_ids[connection_id]; + connection_ids[connection_id] = count - 1; + return true; + } + } + + return false; +} + +void RemoteCallSubscriptionHandler::Process() { + //create a check for all these connection ids packet + uint32 sz = 12; + auto iter = connection_ids.begin(); + while(iter != connection_ids.end()) { + sz += iter->first.size(); + sz += 5; + ++iter; + } + + ServerPacket *pack = new ServerPacket(ServerOP_WIClientSession, sz); + pack->WriteUInt32((uint32)zone->GetZoneID()); + pack->WriteUInt32((uint32)zone->GetInstanceID()); + pack->WriteUInt32((uint32)connection_ids.size()); + + iter = connection_ids.begin(); + while(iter != connection_ids.end()) { + pack->WriteUInt32((uint32)iter->first.size()); + pack->WriteString(iter->first.c_str()); + ++iter; + } + + worldserver.SendPacket(pack); + safe_delete(pack); +} + +const std::vector &RemoteCallSubscriptionHandler::GetSubscribers(std::string event_name) { + if(registered_events.count(event_name) == 0) { + return std::vector(); + } + + std::vector &r = registered_events[event_name]; + return r; +} + +void RemoteCallSubscriptionHandler::ClearConnection(std::string connection_id) { + if(connection_ids.count(connection_id) != 0) { + connection_ids.erase(connection_id); + } + + auto iter = registered_events.begin(); + while(iter != registered_events.end()) { + auto &conns = iter->second; + auto conn_iter = conns.begin(); + while(conn_iter != conns.end()) { + if(conn_iter->compare(connection_id) == 0) { + conns.erase(conn_iter); + registered_events[iter->first] = conns; + printf("Removing connection: %s from event %s\n", connection_id.c_str(), iter->first.c_str()); + break; + } + ++conn_iter; + } + + ++iter; + } +} + +void RemoteCallSubscriptionHandler::ClearAllConnections() { + // + //std::map> registered_events; + //std::map connection_ids; + + registered_events.clear(); + connection_ids.clear(); + +} diff --git a/zone/remote_call_subscribe.h b/zone/remote_call_subscribe.h new file mode 100644 index 000000000..f82928f78 --- /dev/null +++ b/zone/remote_call_subscribe.h @@ -0,0 +1,51 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) + + 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 ZONE_REMOTE_CALL_SUBSCRIBE_H +#define ZONE_REMOTE_CALL_SUBSCRIBE_H + +#include +#include +#include + +class RemoteCallSubscriptionHandler +{ +public: + ~RemoteCallSubscriptionHandler(); + + static RemoteCallSubscriptionHandler *Instance(); + bool Subscribe(std::string connection_id, std::string event_name); + bool Unsubscribe(std::string connection_id, std::string event_name); + const std::vector &GetSubscribers(std::string event_name); + + void Process(); + void ClearConnection(std::string connection_id); + void ClearAllConnections(); + +private: + RemoteCallSubscriptionHandler(); + RemoteCallSubscriptionHandler(RemoteCallSubscriptionHandler const&); + RemoteCallSubscriptionHandler& operator=(RemoteCallSubscriptionHandler const&); + + static RemoteCallSubscriptionHandler *_instance; + + std::map> registered_events; + std::map connection_ids; +}; + +#endif + diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 6c9c6f120..5bc6cb706 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -51,7 +51,8 @@ #include "../common/rulesys.h" #include "titles.h" #include "QGlobals.h" - +#include "remote_call.h" +#include "remote_call_subscribe.h" extern EntityList entity_list; extern Zone* zone; @@ -62,6 +63,7 @@ extern NetConnection net; extern PetitionList petition_list; extern uint32 numclients; extern volatile bool RunLoops; +extern std::map remote_call_methods; WorldServer::WorldServer() : WorldConnection(EmuTCPConnection::packetModeZone) @@ -1812,10 +1814,50 @@ void WorldServer::Process() { } break; } - case ServerOP_WIRemoteCall: - printf("Recv remote call from WI but atm doing anything with it is not yet implemented (BUT SOON)\n"); - DumpPacket(pack); + case ServerOP_WIRemoteCall: { + char *id = nullptr; + char *session_id = nullptr; + char *method = nullptr; + + id = new char[pack->ReadUInt32() + 1]; + pack->ReadString(id); + + session_id = new char[pack->ReadUInt32() + 1]; + pack->ReadString(session_id); + + method = new char[pack->ReadUInt32() + 1]; + pack->ReadString(method); + + uint32 param_count = pack->ReadUInt32(); + std::vector params; + for(uint32 i = 0; i < param_count; ++i) { + char *p = new char[pack->ReadUInt32() + 1]; + pack->ReadString(p); + params.push_back(p); + safe_delete_array(p); + } + + if(remote_call_methods.count(method) != 0) { + auto f = remote_call_methods[method]; + f(method, session_id, id, params); + } + + safe_delete_array(id); + safe_delete_array(session_id); + safe_delete_array(method); break; + } + case ServerOP_WIClientSessionResponse: { + uint32 count = pack->ReadUInt32(); + for(uint32 i = 0; i < count; ++i) { + char *p = new char[pack->ReadUInt32() + 1]; + pack->ReadString(p); + RemoteCallSubscriptionHandler::Instance()->ClearConnection(p); + safe_delete_array(p); + } + + break; + } default: { std::cout << " Unknown ZSopcode:" << (int)pack->opcode; std::cout << " size:" << pack->size << std::endl; diff --git a/zone/zone.cpp b/zone/zone.cpp index 4124ba7d3..e1e3f68b2 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -58,6 +58,8 @@ #include "../common/rulesys.h" #include "guild_mgr.h" #include "QuestParserCollection.h" +#include "remote_call.h" +#include "remote_call_subscribe.h" #ifdef _WINDOWS #define snprintf _snprintf @@ -790,6 +792,7 @@ void Zone::Shutdown(bool quite) LogFile->write(EQEMuLog::Normal, "Zone shutdown: going to sleep"); ZoneLoaded = false; + RemoteCallSubscriptionHandler::Instance()->ClearAllConnections(); zone->ResetAuth(); safe_delete(zone); dbasync->CommitWrites();