<commit_before>#include "tools/log.hpp"
#include "hardware/FWiegandReader.hpp"
#include "RplethModule.hpp"
#include "rplethprotocol.hpp"
#include <boost/property_tree/ptree_serialization.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>

using namespace Leosac::Module::Rpleth;

RplethModule::RplethModule(zmqpp::context &ctx,
        zmqpp::socket *pipe,
        const boost::property_tree::ptree &cfg) :
        BaseModule(ctx, pipe, cfg),
        ctx_(ctx),
        server_(ctx, zmqpp::socket_type::stream),
        bus_sub_(ctx, zmqpp::socket_type::sub),
        core_(ctx, zmqpp::socket_type::req),
        reader_(nullptr),
        stream_mode_(false)
{
    core_.connect("inproc://leosac-kernel");
    process_config();
    bus_sub_.connect("inproc://zmq-bus-pub");
    bus_sub_.subscribe("S_" + reader_->name());
    reactor_.add(server_, std::bind(&RplethModule::handle_socket, this));
    reactor_.add(bus_sub_, std::bind(&RplethModule::handle_wiegand_event, this));
}

RplethModule::~RplethModule()
{
}

void RplethModule::process_config()
{
    boost::property_tree::ptree module_config = config_.get_child("module_config");

    uint16_t port = module_config.get<uint16_t>("port", 4242);
    std::string reader_name = module_config.get_child("reader").data();
    stream_mode_ = module_config.get<bool>("stream_mode", true);

    INFO("Rpleth module will bind to " << port << " and will control the device nammed " << reader_name
            << "Stream mode = " << stream_mode_);
    reader_ = std::unique_ptr<Hardware::FWiegandReader>(new Hardware::FWiegandReader(ctx_, reader_name));
    server_.bind("tcp://*:" + std::to_string(port));
}

void RplethModule::handle_socket()
{
    zmqpp::message msg;
    std::string identity;
    std::string content;

    server_.receive(msg);
    msg >> identity >> content;

    if (content.size() == 0)
    {
        // handle special 0 length message that indicates connection / disconnection.
        if (client_connected(identity)) // client exists so this is a disconnection message.
        {
            INFO("client disconnected");
            clients_.erase(identity);
            if (client_failed(identity))
                failed_clients_.erase(std::remove(failed_clients_.begin(), failed_clients_.end(), identity), failed_clients_.end());
        }
        else
        {
            INFO("Client connected");
            clients_[identity];
        }
        return;
    }
    if (client_failed(identity))
        return;
    assert(clients_.count(identity) && !client_failed(identity));
    clients_[identity].write(reinterpret_cast<const uint8_t *> (content.c_str()), content.size());
    if (handle_client_msg(identity, clients_[identity]) == false)
        failed_clients_.push_back(identity);
}

bool RplethModule::handle_client_msg(const std::string &client_identity, CircularBuffer &buf)
{
    RplethPacket packet(RplethPacket::Sender::Client);

    do
    {
        std::array<uint8_t, buffer_size> buffer;
        packet = RplethProtocol::decodeCommand(buf);
        if (!packet.isGood)
            break;
        RplethPacket response = handle_client_packet(packet);
        if (response.command == RplethProtocol::HIDCommands::Greenled ||
                response.command == RplethProtocol::HIDCommands::Beep)
            continue;
        std::size_t size = RplethProtocol::encodeCommand(response, &buffer[0], buffer_size);

        zmqpp::message msg;
        msg << client_identity;
        msg.add_raw(&buffer[0], size);
        if (!server_.send(msg, true))
        {
            // would block: peer is probably disconnected already.
            return false;
        }
    }
    while (packet.isGood && buf.toRead());
    return true;
}

RplethPacket RplethModule::handle_client_packet(RplethPacket packet)
{
    RplethPacket response = packet;
    try
    {
        response.sender = RplethPacket::Sender::Server;
        if (response.type == RplethProtocol::Rpleth && response.command == RplethProtocol::Ping)
        {
            response.status = RplethProtocol::Success;
        }
        else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::Greenled)
            rpleth_greenled(packet);
        else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::Beep)
            rpleth_beep(packet);
        else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::SendCards)
            rpleth_send_cards(packet);
        else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::ReceiveCardsWaited)
            response = rpleth_receive_cards(response);
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::DHCPState)
            response = get_dhcp_state();
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::SetDHCP)
            response = set_dhcp_state(response);
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::SetIP)
            response = set_reader_ip(response);
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::SetSubnet)
            response = set_reader_netmask(response);
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::SetGateway)
            response = set_reader_gw(response);
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::Reset)
            restart_reader();
        else
        {
            WARN("Unhandled packet.");
            response.status = RplethProtocol::Success; // Default response
        }
        return response;
    }
    catch (std::exception &e)
    {
        ERROR("Exception while handling rpleth packet: " << e.what());
    }
    response.status = RplethProtocol::Failed;
    return response;
}

void RplethModule::handle_wiegand_event()
{
    zmqpp::message msg;
    std::string card_id;
    int nb_bit_read;

    bus_sub_.receive(msg);
    msg >> card_id >> card_id >> nb_bit_read;

    DEBUG("Rpleth module registered card with id " << card_id << " and "
            << nb_bit_read << " significants bits");

    if (stream_mode_)
        cards_read_stream_.push_back(std::make_pair(card_id, nb_bit_read));

    card_id.erase(std::remove(card_id.begin(), card_id.end(), ':'), card_id.end());
    if (std::find(cards_pushed_.begin(), cards_pushed_.end(), card_id) != cards_pushed_.end())
    {
        cards_read_.push_back(card_id);
    }
    cards_read_.unique();<commit_msg>Rpleth bug when extracting wiegand data.<commit_after>#include "tools/log.hpp"
#include "hardware/FWiegandReader.hpp"
#include "RplethModule.hpp"
#include "rplethprotocol.hpp"
#include <boost/property_tree/ptree_serialization.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <core/auth/Auth.hpp>

using namespace Leosac::Module::Rpleth;

RplethModule::RplethModule(zmqpp::context &ctx,
        zmqpp::socket *pipe,
        const boost::property_tree::ptree &cfg) :
        BaseModule(ctx, pipe, cfg),
        ctx_(ctx),
        server_(ctx, zmqpp::socket_type::stream),
        bus_sub_(ctx, zmqpp::socket_type::sub),
        core_(ctx, zmqpp::socket_type::req),
        reader_(nullptr),
        stream_mode_(false)
{
    core_.connect("inproc://leosac-kernel");
    process_config();
    bus_sub_.connect("inproc://zmq-bus-pub");
    bus_sub_.subscribe("S_" + reader_->name());
    reactor_.add(server_, std::bind(&RplethModule::handle_socket, this));
    reactor_.add(bus_sub_, std::bind(&RplethModule::handle_wiegand_event, this));
}

RplethModule::~RplethModule()
{
}

void RplethModule::process_config()
{
    boost::property_tree::ptree module_config = config_.get_child("module_config");

    uint16_t port = module_config.get<uint16_t>("port", 4242);
    std::string reader_name = module_config.get_child("reader").data();
    stream_mode_ = module_config.get<bool>("stream_mode", true);

    INFO("Rpleth module will bind to " << port << " and will control the device nammed " << reader_name
            << "Stream mode = " << stream_mode_);
    reader_ = std::unique_ptr<Hardware::FWiegandReader>(new Hardware::FWiegandReader(ctx_, reader_name));
    server_.bind("tcp://*:" + std::to_string(port));
}

void RplethModule::handle_socket()
{
    zmqpp::message msg;
    std::string identity;
    std::string content;

    server_.receive(msg);
    msg >> identity >> content;

    if (content.size() == 0)
    {
        // handle special 0 length message that indicates connection / disconnection.
        if (client_connected(identity)) // client exists so this is a disconnection message.
        {
            INFO("client disconnected");
            clients_.erase(identity);
            if (client_failed(identity))
                failed_clients_.erase(std::remove(failed_clients_.begin(), failed_clients_.end(), identity), failed_clients_.end());
        }
        else
        {
            INFO("Client connected");
            clients_[identity];
        }
        return;
    }
    if (client_failed(identity))
        return;
    assert(clients_.count(identity) && !client_failed(identity));
    clients_[identity].write(reinterpret_cast<const uint8_t *> (content.c_str()), content.size());
    if (handle_client_msg(identity, clients_[identity]) == false)
        failed_clients_.push_back(identity);
}

bool RplethModule::handle_client_msg(const std::string &client_identity, CircularBuffer &buf)
{
    RplethPacket packet(RplethPacket::Sender::Client);

    do
    {
        std::array<uint8_t, buffer_size> buffer;
        packet = RplethProtocol::decodeCommand(buf);
        if (!packet.isGood)
            break;
        RplethPacket response = handle_client_packet(packet);
        if (response.command == RplethProtocol::HIDCommands::Greenled ||
                response.command == RplethProtocol::HIDCommands::Beep)
            continue;
        std::size_t size = RplethProtocol::encodeCommand(response, &buffer[0], buffer_size);

        zmqpp::message msg;
        msg << client_identity;
        msg.add_raw(&buffer[0], size);
        if (!server_.send(msg, true))
        {
            // would block: peer is probably disconnected already.
            return false;
        }
    }
    while (packet.isGood && buf.toRead());
    return true;
}

RplethPacket RplethModule::handle_client_packet(RplethPacket packet)
{
    RplethPacket response = packet;
    try
    {
        response.sender = RplethPacket::Sender::Server;
        if (response.type == RplethProtocol::Rpleth && response.command == RplethProtocol::Ping)
        {
            response.status = RplethProtocol::Success;
        }
        else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::Greenled)
            rpleth_greenled(packet);
        else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::Beep)
            rpleth_beep(packet);
        else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::SendCards)
            rpleth_send_cards(packet);
        else if (response.type == RplethProtocol::TypeCode::HID && response.command == RplethProtocol::HIDCommands::ReceiveCardsWaited)
            response = rpleth_receive_cards(response);
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::DHCPState)
            response = get_dhcp_state();
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::SetDHCP)
            response = set_dhcp_state(response);
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::SetIP)
            response = set_reader_ip(response);
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::SetSubnet)
            response = set_reader_netmask(response);
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::SetGateway)
            response = set_reader_gw(response);
        else if (response.type == RplethProtocol::TypeCode::Rpleth && response.command == RplethProtocol::RplethCommands::Reset)
            restart_reader();
        else
        {
            WARN("Unhandled packet.");
            response.status = RplethProtocol::Success; // Default response
        }
        return response;
    }
    catch (std::exception &e)
    {
        ERROR("Exception while handling rpleth packet: " << e.what());
    }
    response.status = RplethProtocol::Failed;
    return response;
}

void RplethModule::handle_wiegand_event()
{
    zmqpp::message msg;
    std::string card_id;
    std::string src; // object that sent event
    Leosac::Auth::SourceType type;
    int nb_bit_read;

    bus_sub_.receive(msg);
    msg >> src >> type;
    assert(type == Leosac::Auth::SourceType::SIMPLE_WIEGAND);
    msg >> card_id >> nb_bit_read;

    DEBUG("Rpleth module registered card with id " << card_id << " and "
            << nb_bit_read << " significants bits");

    if (stream_mode_)
        cards_read_stream_.push_back(std::make_pair(card_id, nb_bit_read));

    card_id.erase(std::remove(card_id.begin(), card_id.end(), ':'), card_id.end());
    if (std::find(cards_pushed_.begin(), cards_pushed_.end(), card_id) != cards_pushed_.end())
    {
        cards_read_.push_back(card_id);
    }
    cards_read_.unique();
{'fraction_non_alphanumeric': 0.13278571428571428, 'fraction_numerical': 0.002, 'mean_word_length': 3.454661151765829, 'pattern_counts': {'":': 0, '<': 64, '<?xml version=': 0, '>': 44, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6797433', 'n_tokens_mistral': 4287, 'n_tokens_neox': 4272, 'n_words': 724}