Utils moved to subdirectories Task activation have been moved to static member of the Task class, instead of being manually activated.
119 lines
3.9 KiB
C++
119 lines
3.9 KiB
C++
#include "UndefinedTask.hpp"
|
|
#include "../types.hpp"
|
|
|
|
#include <chrono>
|
|
#include <cstring>
|
|
#include <iostream>
|
|
#include <thread>
|
|
#include <algorithm>
|
|
#include <sys/socket.h>
|
|
#include <ifaddrs.h>
|
|
|
|
#include "Context.hpp"
|
|
#include "behavior/tasks/client/ClientTask.hpp"
|
|
#include "behavior/tasks/server/ServerTask.hpp"
|
|
#include "packets/base/Packet.hpp"
|
|
#include "packets/base/SecurityMode.hpp"
|
|
#include "packets/search/SearchPacketData.hpp"
|
|
#include "utils/network/network.hpp"
|
|
|
|
|
|
namespace drp::task {
|
|
|
|
|
|
void UndefinedTask::use(Context &context) {
|
|
context.me.status = TaskType::UNDEFINED;
|
|
context.server = nullptr;
|
|
context.remotePeers.clear();
|
|
}
|
|
|
|
|
|
void UndefinedTask::handle(Context& context) {
|
|
std::cout << "[Task - Undefined] List of peers: " << std::endl;
|
|
for (const auto& remotePeer : context.remotePeers)
|
|
std::cout <<
|
|
"\tPeer(id=" << remotePeer->information.id << ", " <<
|
|
"status=" << std::to_string(static_cast<std::uint8_t>(remotePeer->information.status)) << ")" <<
|
|
std::endl;
|
|
|
|
// search if a server is available among the peer.
|
|
const auto& server = std::ranges::find_if(
|
|
context.remotePeers,
|
|
[&](const auto& peer) { return peer->information.status == TaskType::SERVER; }
|
|
);
|
|
// if a server have been found, use it
|
|
if (server != context.remotePeers.end()) {
|
|
// go into client mode
|
|
ClientTask::use(context, *server);
|
|
return;
|
|
}
|
|
|
|
// wait that no more new peers are being discovered
|
|
if (
|
|
std::chrono::high_resolution_clock::now() - context.latestPeerDiscovery >
|
|
std::chrono::milliseconds(5000)
|
|
) {
|
|
std::cout << "No more peers discovered." << std::endl;
|
|
|
|
// otherwise, become the server if we have the highest ID.
|
|
// TODO(Faraphel): should use the machine with the lowest average ping
|
|
if (context.me.serverEnabled) {
|
|
// find the remote peer with the highest id that can be a server
|
|
const std::shared_ptr<RemotePeer> serverCandidate = *std::ranges::max_element(
|
|
context.remotePeers,
|
|
[&](auto& remotePeer1, auto& remotePeer2) {
|
|
return (
|
|
(remotePeer1->information.serverEnabled ? remotePeer1->information.id : 0) <
|
|
(remotePeer2->information.serverEnabled ? remotePeer2->information.id : 0)
|
|
);
|
|
}
|
|
);
|
|
|
|
// check if we are this peer
|
|
if (util::network::is_localhost(serverCandidate->address, serverCandidate->addressLength)) {
|
|
std::cout << "[Task - Undefined] Becoming server..." << std::endl;
|
|
// go into server mode
|
|
ServerTask::use(context, serverCandidate);
|
|
return;
|
|
}
|
|
}
|
|
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
}
|
|
|
|
// prepare a search message
|
|
packet::base::Packet packet {};
|
|
packet::base::PacketContent packetContent {};
|
|
packet::search::SearchPacketData packetData {};
|
|
|
|
// broadcast message
|
|
packet.channel = 0;
|
|
|
|
// search message with the time of the message being sent
|
|
packetData.timestamp = std::chrono::high_resolution_clock::now();
|
|
|
|
packetContent.eventType = event::EventType::SEARCH;
|
|
packetContent.data = packetData.serialize();
|
|
|
|
packet.setContent(context, packet::base::SecurityMode::PLAIN, packetContent);
|
|
|
|
std::cout << "[Task - Undefined] Looking for new peers." << std::endl;
|
|
|
|
const auto serializedPacket = packet.serialize();
|
|
|
|
// send the search message
|
|
if (sendto(
|
|
context.socket,
|
|
serializedPacket.data(),
|
|
serializedPacket.size(),
|
|
0,
|
|
context.broadcastAddressInfo->ai_addr,
|
|
context.broadcastAddressInfo->ai_addrlen
|
|
) == -1)
|
|
std::cerr << "[Task - Undefined] Could not send search event: " << strerror(errno) << std::endl;
|
|
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
}
|
|
|
|
|
|
}
|