mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-10-31 04:32:06 +00:00 
			
		
		
		
	Final framework, now just cleanup
This commit is contained in:
		| @@ -450,7 +450,6 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) { | ||||
| 	 | ||||
| 	// build chat json data | ||||
| 	nlohmann::json data; | ||||
| 	data["action"] = "chat"; | ||||
| 	data["playerName"] = sender.playerName; | ||||
| 	data["message"] = message.GetAsString(); | ||||
| 	auto& zoneID = data["zone_id"]; | ||||
| @@ -460,7 +459,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) { | ||||
| 	 | ||||
| 	switch (channel) { | ||||
| 	case eChatChannel::LOCAL: { | ||||
| 		Game::web.SendWSMessage("WorldChat", data.dump()); | ||||
| 		Game::web.SendWSMessage("chat_local", data); | ||||
| 		break; | ||||
| 	} | ||||
| 	case eChatChannel::TEAM: { | ||||
| @@ -472,7 +471,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) { | ||||
| 			if (!otherMember) return; | ||||
| 			SendPrivateChatMessage(sender, otherMember, otherMember, message, eChatChannel::TEAM, eChatMessageResponseCode::SENT); | ||||
| 			data["teamID"] = team->teamID; | ||||
| 			Game::web.SendWSMessage("teamchat", data.dump()); | ||||
| 			Game::web.SendWSMessage("chat_team", data); | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| @@ -528,6 +527,14 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { | ||||
| 	// only freinds can whispr each other | ||||
| 	for (const auto& fr : receiver.friends) { | ||||
| 		if (fr.friendID == sender.playerID) { | ||||
| 			nlohmann::json data; | ||||
| 			data["sender"] = sender.playerName; | ||||
| 			data["receiver"] = receiverName; | ||||
| 			data["message"] = message.GetAsString(); | ||||
| 			data["zone_id"]["map_id"] = sender.zoneID.GetMapID(); | ||||
| 			data["zone_id"]["instance_id"] = sender.zoneID.GetInstanceID(); | ||||
| 			data["zone_id"]["clone_id"] = sender.zoneID.GetCloneID(); | ||||
| 			Game::web.SendWSMessage("chat_private", data); | ||||
| 			//To the sender: | ||||
| 			SendPrivateChatMessage(sender, receiver, sender, message, eChatChannel::PRIVATE_CHAT, eChatMessageResponseCode::SENT); | ||||
| 			//To the receiver: | ||||
|   | ||||
| @@ -69,36 +69,6 @@ void HandleWSChat(mg_connection* connection, json data) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void HandleWSSubscribe(mg_connection* connection, json data) { | ||||
| 	auto check = JSONUtils::CheckRequiredData(data, { "type" }); | ||||
| 	if (!check.empty()) { | ||||
| 		LOG_DEBUG("Received invalid websocket message: %s", check.c_str()); | ||||
| 	} else { | ||||
| 		const auto type = data["type"].get<std::string>(); | ||||
| 		LOG_DEBUG("type %s subscribed", type.c_str()); | ||||
| 		const auto sub =  magic_enum::enum_cast<eWSSubscription>(type).value_or(eWSSubscription::INVALID); | ||||
| 		if (sub != eWSSubscription::INVALID) { | ||||
| 			connection->data[GeneralUtils::ToUnderlying(sub)] = 1; | ||||
| 			mg_ws_send(connection, "{\"status\":\"subscribed\"}", 18, WEBSOCKET_OP_TEXT); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void HandleWSUnsubscribe(mg_connection* connection, json data) { | ||||
| 	auto check = JSONUtils::CheckRequiredData(data, { "type" }); | ||||
| 	if (!check.empty()) { | ||||
| 		LOG_DEBUG("Received invalid websocket message: %s", check.c_str()); | ||||
| 	} else { | ||||
| 		const auto type = data["type"].get<std::string>(); | ||||
| 		LOG_DEBUG("type %s unsubscribed", type.c_str()); | ||||
| 		const auto sub =  magic_enum::enum_cast<eWSSubscription>(type).value_or(eWSSubscription::INVALID); | ||||
| 		if (sub != eWSSubscription::INVALID) { | ||||
| 			connection->data[GeneralUtils::ToUnderlying(sub)] = 0; | ||||
| 			mg_ws_send(connection, "{\"status\":\"unsubscribed\"}", 18, WEBSOCKET_OP_TEXT); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void ChatWeb::RegisterRoutes() { | ||||
| 	// REST API v1 routes | ||||
| 	std::string v1_route = "/api/v1/"; | ||||
| @@ -120,19 +90,16 @@ void ChatWeb::RegisterRoutes() { | ||||
| 		.handle = HandleHTTPAnnounceRequest | ||||
| 	}); | ||||
|  | ||||
| 	// WebSocket Actions | ||||
| 	Game::web.RegisterWSAction({ | ||||
| 		.action = "subscribe", | ||||
| 		.handle = HandleWSSubscribe | ||||
| 	}); | ||||
|  | ||||
| 	Game::web.RegisterWSAction({ | ||||
| 		.action = "unsubscribe", | ||||
| 		.handle = HandleWSUnsubscribe | ||||
| 	}); | ||||
|  | ||||
| 	Game::web.RegisterWSAction({ | ||||
| 		.action = "chat", | ||||
| 	// WebSocket Events | ||||
| 	Game::web.RegisterWSEvent({ | ||||
| 		.name = "chat", | ||||
| 		.handle = HandleWSChat | ||||
| 	}); | ||||
|  | ||||
| 	// WebSocket subscriptions | ||||
| 	Game::web.RegisterWSSubscription("chat_local"); | ||||
| 	Game::web.RegisterWSSubscription("chat_team"); | ||||
| 	Game::web.RegisterWSSubscription("chat_private"); | ||||
| 	Game::web.RegisterWSSubscription("player"); | ||||
| 	Game::web.RegisterWSSubscription("team"); | ||||
| } | ||||
|   | ||||
| @@ -6,15 +6,6 @@ | ||||
|  | ||||
| #include "Web.h" | ||||
|  | ||||
| enum class eWSSubscription { | ||||
| 	WORLD_CHAT, | ||||
| 	PRIVATE_CHAT, | ||||
| 	TEAM_CHAT, | ||||
| 	TEAM, | ||||
| 	PLAYER, | ||||
| 	INVALID | ||||
| }; | ||||
|  | ||||
| namespace ChatWeb { | ||||
| 	void RegisterRoutes(); | ||||
| }; | ||||
|   | ||||
| @@ -70,7 +70,7 @@ void PlayerContainer::InsertPlayer(Packet* packet) { | ||||
| 	zoneID["map_id"] = data.zoneID.GetMapID(); | ||||
| 	zoneID["instance_id"] = data.zoneID.GetInstanceID(); | ||||
| 	zoneID["clone_id"] = data.zoneID.GetCloneID(); | ||||
| 	Game::web.SendWSMessage("player", wsdata.dump()); | ||||
| 	Game::web.SendWSMessage("player", wsdata); | ||||
| 	Database::Get()->UpdateActivityLog(data.playerID, eActivityType::PlayerLoggedIn, data.zoneID.GetMapID()); | ||||
| 	m_PlayersToRemove.erase(playerId); | ||||
| } | ||||
| @@ -130,7 +130,7 @@ void PlayerContainer::RemovePlayer(const LWOOBJID playerID) { | ||||
| 	wsdata["type"] = "remove"; | ||||
| 	wsdata["playerName"] = player.playerName; | ||||
| 	wsdata["playerID"] = player.playerID; | ||||
| 	Game::web.SendWSMessage("player", wsdata.dump()); | ||||
| 	Game::web.SendWSMessage("player", wsdata); | ||||
|  | ||||
| 	m_PlayerCount--; | ||||
| 	LOG("Removed user: %llu", playerID); | ||||
|   | ||||
							
								
								
									
										125
									
								
								dWeb/Web.cpp
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								dWeb/Web.cpp
									
									
									
									
									
								
							| @@ -14,7 +14,8 @@ namespace Game { | ||||
| namespace { | ||||
| 	const char * json_content_type = "application/json"; | ||||
| 	std::map<std::pair<eHTTPMethod, std::string>, HTTPRoute> g_HTTPRoutes; | ||||
| 	std::map<std::string, WSAction> g_WSactions; | ||||
| 	std::map<std::string, WSEvent> g_WSEvents; | ||||
| 	std::vector<std::string> g_WSSubscriptions; | ||||
| } | ||||
|  | ||||
| using json = nlohmann::json; | ||||
| @@ -80,17 +81,17 @@ void HandleWSMessage(mg_connection* connection, const mg_ws_message* ws_msg) { | ||||
| 		auto data = GeneralUtils::TryParse<json>(std::string(ws_msg->data.buf, ws_msg->data.len)); | ||||
| 		if (data) { | ||||
| 			const auto& good_data = data.value(); | ||||
| 			auto check = JSONUtils::CheckRequiredData(good_data, { "action" }); | ||||
| 			auto check = JSONUtils::CheckRequiredData(good_data, { "event" }); | ||||
| 			if (!check.empty()) { | ||||
| 				LOG_DEBUG("Received invalid websocket message: %s", check.c_str()); | ||||
| 			} else { | ||||
| 				const auto action = good_data["action"].get<std::string>(); | ||||
| 				const auto actionItr = g_WSactions.find(action); | ||||
| 				if (actionItr != g_WSactions.end()) { | ||||
| 					const auto& [_, action] = *actionItr; | ||||
| 					action.handle(connection, good_data); | ||||
| 				const auto event = good_data["event"].get<std::string>(); | ||||
| 				const auto eventItr = g_WSEvents.find(event); | ||||
| 				if (eventItr != g_WSEvents.end()) { | ||||
| 					const auto& [_, event] = *eventItr; | ||||
| 					event.handle(connection, good_data); | ||||
| 				} else { | ||||
| 					LOG_DEBUG("Received invalid websocket action: %s", action.c_str()); | ||||
| 					LOG_DEBUG("Received invalid websocket event: %s", event.c_str()); | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| @@ -99,6 +100,61 @@ void HandleWSMessage(mg_connection* connection, const mg_ws_message* ws_msg) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void HandleWSSubscribe(mg_connection* connection, json data) { | ||||
| 	auto check = JSONUtils::CheckRequiredData(data, { "subscription" }); | ||||
| 	if (!check.empty()) { | ||||
| 		LOG_DEBUG("Received invalid websocket message: %s", check.c_str()); | ||||
| 	} else { | ||||
| 		const auto subscription = data["subscription"].get<std::string>(); | ||||
| 		LOG_DEBUG("subscription %s subscribed", subscription.c_str()); | ||||
| 		// check subscription vector | ||||
| 		auto subItr = std::find(g_WSSubscriptions.begin(), g_WSSubscriptions.end(), subscription); | ||||
| 		if (subItr != g_WSSubscriptions.end()) { | ||||
| 			// get index of subscription | ||||
| 			auto index = std::distance(g_WSSubscriptions.begin(), subItr); | ||||
| 			connection->data[index] = 1; | ||||
| 			mg_ws_send(connection, "{\"status\":\"subscribed\"}", 23, WEBSOCKET_OP_TEXT); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void HandleWSUnsubscribe(mg_connection* connection, json data) { | ||||
| 	auto check = JSONUtils::CheckRequiredData(data, { "subscription" }); | ||||
| 	if (!check.empty()) { | ||||
| 		LOG_DEBUG("Received invalid websocket message: %s", check.c_str()); | ||||
| 	} else { | ||||
| 		const auto subscription = data["subscription"].get<std::string>(); | ||||
| 		LOG_DEBUG("subscription %s unsubscribed", subscription.c_str()); | ||||
| 		// check subscription vector | ||||
| 		auto subItr = std::find(g_WSSubscriptions.begin(), g_WSSubscriptions.end(), subscription); | ||||
| 		if (subItr != g_WSSubscriptions.end()) { | ||||
| 			// get index of subscription | ||||
| 			auto index = std::distance(g_WSSubscriptions.begin(), subItr); | ||||
| 			connection->data[index] = 0; | ||||
| 			mg_ws_send(connection, "{\"status\":\"unsubscribed\"}", 25, WEBSOCKET_OP_TEXT); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void HandleWSGetSubscriptions(mg_connection* connection, json data) { | ||||
| 	// list subscribed and non subscribed subscriptions | ||||
| 	json response; | ||||
| 	// check subscription vector | ||||
| 	for (const auto& sub : g_WSSubscriptions) { | ||||
| 		auto subItr = std::find(g_WSSubscriptions.begin(), g_WSSubscriptions.end(), sub); | ||||
| 		if (subItr != g_WSSubscriptions.end()) { | ||||
| 			// get index of subscription | ||||
| 			auto index = std::distance(g_WSSubscriptions.begin(), subItr); | ||||
| 			if (connection->data[index] == 1) { | ||||
| 				response["subscribed"].push_back(sub); | ||||
| 			} else { | ||||
| 				response["unsubscribed"].push_back(sub); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	mg_ws_send(connection, response.dump().c_str(), response.dump().size(), WEBSOCKET_OP_TEXT); | ||||
| } | ||||
|  | ||||
| void HandleMessages(mg_connection* connection, int message, void* message_data) { | ||||
| 	switch (message) { | ||||
| 		case MG_EV_HTTP_MSG: | ||||
| @@ -121,12 +177,23 @@ void Web::RegisterHTTPRoute(HTTPRoute route) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void Web::RegisterWSAction(WSAction action) { | ||||
| 	auto [_, success] = g_WSactions.try_emplace(action.action, action); | ||||
| void Web::RegisterWSEvent(WSEvent event) { | ||||
| 	auto [_, success] = g_WSEvents.try_emplace(event.name, event); | ||||
| 	if (!success) { | ||||
| 		LOG_DEBUG("Failed to register WS action %s", action.action.c_str()); | ||||
| 		LOG_DEBUG("Failed to register WS event %s", event.name.c_str()); | ||||
| 	} else { | ||||
| 		LOG_DEBUG("Registered WS action %s", action.action.c_str()); | ||||
| 		LOG_DEBUG("Registered WS event %s", event.name.c_str()); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void Web::RegisterWSSubscription(const std::string& subscription) { | ||||
| 	// check that subsction is not already in the vector | ||||
| 	auto subItr = std::find(g_WSSubscriptions.begin(), g_WSSubscriptions.end(), subscription); | ||||
| 	if (subItr != g_WSSubscriptions.end()) { | ||||
| 		LOG_DEBUG("Failed to register WS subscription %s: duplicate", subscription.c_str()); | ||||
| 	} else { | ||||
| 		LOG_DEBUG("Registered WS subscription %s", subscription.c_str()); | ||||
| 		g_WSSubscriptions.push_back(subscription); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -148,7 +215,24 @@ bool Web::Startup(const std::string& listen_ip, const uint32_t listen_port) { | ||||
| 	if (!mg_http_listen(&mgr, listen_address.c_str(), HandleMessages, NULL)) { | ||||
| 		LOG("Failed to create web server listener on %s", listen_address.c_str()); | ||||
| 		return false; | ||||
| 	}	 | ||||
| 	} | ||||
|  | ||||
| 	// WebSocket Events | ||||
| 	Game::web.RegisterWSEvent({ | ||||
| 		.name = "subscribe", | ||||
| 		.handle = HandleWSSubscribe | ||||
| 	}); | ||||
|  | ||||
| 	Game::web.RegisterWSEvent({ | ||||
| 		.name = "unsubscribe", | ||||
| 		.handle = HandleWSUnsubscribe | ||||
| 	}); | ||||
|  | ||||
| 	Game::web.RegisterWSEvent({ | ||||
| 		.name = "getSubscriptions", | ||||
| 		.handle = HandleWSGetSubscriptions | ||||
| 	}); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @@ -156,10 +240,19 @@ void Web::ReceiveRequests() { | ||||
| 	mg_mgr_poll(&mgr, 15); | ||||
| } | ||||
|  | ||||
| void Web::SendWSMessage(const std::string subscription, const std::string& message) { | ||||
| void Web::SendWSMessage(const std::string subscription, json& data) { | ||||
| 	// find subscription | ||||
| 	auto subItr = std::find(g_WSSubscriptions.begin(), g_WSSubscriptions.end(), subscription); | ||||
| 	if (subItr == g_WSSubscriptions.end()) { | ||||
| 		LOG_DEBUG("Failed to send WS message: subscription %s not found", subscription.c_str()); | ||||
| 		return; | ||||
| 	} | ||||
| 	// tell it the event type | ||||
| 	data["event"] = subscription; | ||||
| 	auto index = std::distance(g_WSSubscriptions.begin(), subItr); | ||||
| 	for (struct mg_connection *wc = Game::web.mgr.conns; wc != NULL; wc = wc->next) { | ||||
| 		if (wc->is_websocket /* && wc->data[GeneralUtils::ToUnderlying(sub)] == 1*/) { | ||||
| 			mg_ws_send(wc, message.c_str(), message.size(), WEBSOCKET_OP_TEXT); | ||||
| 		if (wc->is_websocket && wc->data[index] == 1) { | ||||
| 			mg_ws_send(wc, data.dump().c_str(), data.dump().size(), WEBSOCKET_OP_TEXT); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -28,8 +28,8 @@ struct HTTPRoute { | ||||
| 	std::function<void(HTTPReply&, const std::string&)> handle; | ||||
| }; | ||||
|  | ||||
| struct WSAction { | ||||
| 	std::string action; | ||||
| struct WSEvent { | ||||
| 	std::string name; | ||||
| 	std::function<void(mg_connection*, nlohmann::json)> handle; | ||||
| }; | ||||
|  | ||||
| @@ -44,10 +44,11 @@ public: | ||||
| 	Web(); | ||||
| 	~Web(); | ||||
| 	void ReceiveRequests(); | ||||
| 	void static SendWSMessage(std::string sub, const std::string& message); | ||||
| 	void static SendWSMessage(std::string sub, nlohmann::json& message); | ||||
| 	bool Startup(const std::string& listen_ip, const uint32_t listen_port); | ||||
| 	void RegisterHTTPRoute(HTTPRoute route); | ||||
| 	void RegisterWSAction(WSAction action); | ||||
| 	void RegisterWSEvent(WSEvent event); | ||||
| 	void RegisterWSSubscription(const std::string& subscription); | ||||
| private: | ||||
| 	mg_mgr mgr; | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Aaron Kimbre
					Aaron Kimbre