M2-PT-DRP/source/managers/ReceiveManager.cpp

101 lines
3.3 KiB
C++

#include "ReceiveManager.hpp"
#include <cstring>
#include <iostream>
#include "behavior/events/audio/AudioEvent.hpp"
#include "behavior/events/info/InfoEvent.hpp"
#include "behavior/events/pong/PongEvent.hpp"
#include "behavior/events/search/SearchEvent.hpp"
namespace drp::managers {
ReceiveManager::ReceiveManager(const std::shared_ptr<Context>& context) {
this->context = context;
// register the different events type
this->registry = {
{event::EventType::PONG, std::make_shared<event::PongEvent>()},
{event::EventType::SEARCH, std::make_shared<event::SearchEvent>()},
{event::EventType::INFO, std::make_shared<event::InfoEvent>()},
{event::EventType::AUDIO, std::make_shared<event::AudioEvent>()},
};
}
void ReceiveManager::run() const {
// prepare space for the sender address
sockaddr_storage fromAddress {};
socklen_t fromAddressLength = sizeof(fromAddress);
std::array<std::uint8_t, packet::base::maxPacketLength> buffer {};
// receive new data
const ssize_t size = recvfrom(
this->context->socket,
buffer.data(),
buffer.size(),
0,
reinterpret_cast<sockaddr*>(&fromAddress),
&fromAddressLength
);
if (size == -1)
throw std::runtime_error("[Receiver] Could not receive the packet: " + std::string(strerror(errno)));
// deserialize the packet
std::vector data(buffer.begin(), buffer.end());
const auto packet = drp::packet::base::Packet::deserialize(data);
// if the packet channel is neither 0 (all) nor the current one, ignore it
if (packet.channel != 0 && packet.channel != this->context->me.channel)
return;
// decrypt the packet
// TODO(Faraphel): handle exception ?
drp::packet::base::PacketContent packetContent = packet.getContent(*this->context);
// look for a saved peer with the same address
auto remotePeer = std::ranges::find_if(
this->context->remotePeers,
[&](const std::shared_ptr<RemotePeer>& remotePeer) { return
remotePeer->addressLength == fromAddressLength and
std::memcmp(&fromAddress, &remotePeer->address, fromAddressLength) == 0;
}
);
// if found, update the latest connection date
if (remotePeer != this->context->remotePeers.end())
(*remotePeer)->latestConnection = std::chrono::high_resolution_clock::now();
// get the corresponding event class
std::shared_ptr<event::BaseEvent> event;
try {
event = this->registry.at(packetContent.eventType);
} catch (const std::out_of_range& exception) {
std::cerr << "[Receiver] Unsupported event type: " << std::to_string(static_cast<int>(packetContent.eventType)) << std::endl;
return;
}
std::cout << "[Receiver] handling event: " << std::to_string(static_cast<int>(packetContent.eventType)) << std::endl;
// ask the event class to handle the event
try {
event->handle(
*this->context,
packetContent.data,
fromAddress,
fromAddressLength
);
} catch (const std::exception& exception) {
std::cerr << "[Receiver] Unhandled exception: " << exception.what() << std::endl;
}
}
void ReceiveManager::loop() const {
while (true)
this->run();
}
}