<commit_before>#ifndef RECURSE_HPP
#define RECURSE_HPP

#include <QCoreApplication>
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QHash>
#include <QStringBuilder>
#include <QVector>
#include "request.hpp"
#include "response.hpp"

#include <functional>
using std::function;
using std::bind;
using std::ref;

typedef function<void(Request &request, Response &response, function<void()> next)> next_f;

//!
//! \brief The Recurse class
//! main class of the app
//!
class Recurse : public QObject
{
public:

    Recurse(int & argc, char ** argv, QObject *parent = NULL);
    ~Recurse();

    bool listen(quint64 port, QHostAddress address = QHostAddress::Any);
    void use(next_f next);

private:
    QCoreApplication app;
    QTcpServer m_tcp_server;

    quint64 m_port;
    QVector<next_f> m_middleware;
    int current_middleware = 0;
    void m_next(int &socket_id);
    void http_parse(Request &request);
    QString http_build_header(const Response &response);

    struct Client {
        QTcpSocket *socket;
        Request request;
        Response response;
    };

    QHash<int, Client> connections;
};

Recurse::Recurse(int & argc, char ** argv, QObject *parent) : app(argc, argv)
{
    Q_UNUSED(parent);
};

Recurse::~Recurse()
{

};

//!
//! \brief Recurse::listen
//! listen for tcp requests
//!
//! \param port tcp server port
//! \param address tcp server listening address
//!
//! \return true on success
//!
bool Recurse::listen(quint64 port, QHostAddress address)
{
    m_port = port;
    int bound = m_tcp_server.listen(address, port);
    if (!bound)
        return false;

    connect(&m_tcp_server, &QTcpServer::newConnection, [this] {
        qDebug() << "client connected";
        int socket_id = rand();

        connections[socket_id] = {
             m_tcp_server.nextPendingConnection()
        };

        connect(connections[socket_id].socket, &QTcpSocket::readyRead, [this, socket_id] {
            connections[socket_id].request.data = connections[socket_id].socket->readAll();
            http_parse(connections[socket_id].request);

            qDebug() << "client request: " << connections[socket_id].request.data;

            if (m_middleware.count() > 0)
                m_middleware[current_middleware](
                    connections[socket_id].request,
                    connections[socket_id].response,
                    bind(&Recurse::m_next, this, socket_id));

            current_middleware = 0;
            QString header;

            connections[socket_id].response.method = connections[socket_id].request.method;
            connections[socket_id].response.proto = connections[socket_id].request.proto;

            if (connections[socket_id].response.status == 0)
                connections[socket_id].response.status = 200;

            header = http_build_header(connections[socket_id].response);
            QString response_data = header + connections[socket_id].response.body;

            // send response to the client
            qint64 check = connections[socket_id].socket->write(
                response_data.toStdString().c_str(),
                response_data.size());

            qDebug() << "socket write debug:" << check;
            connections[socket_id].socket->close();
        });
    });

    return app.exec();
};

//!
//! \brief Recurse::m_next
//! call next middleware
//!
void Recurse::m_next(int &socket_id)
{
    qDebug() << "calling next:" << current_middleware << " num:" << m_middleware.size();

    if (++current_middleware >= m_middleware.size()) {
        return;
    };

    m_middleware[current_middleware](
        connections[socket_id].request,
        connections[socket_id].response,
        bind(&Recurse::m_next, this, socket_id));
};

//!
//! \brief Recurse::use<commit_msg>remove Client instance on socket closure<commit_after>#ifndef RECURSE_HPP
#define RECURSE_HPP

#include <QCoreApplication>
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QHash>
#include <QStringBuilder>
#include <QVector>
#include "request.hpp"
#include "response.hpp"

#include <functional>
using std::function;
using std::bind;
using std::ref;

typedef function<void(Request &request, Response &response, function<void()> next)> next_f;

//!
//! \brief The Recurse class
//! main class of the app
//!
class Recurse : public QObject
{
public:

    Recurse(int & argc, char ** argv, QObject *parent = NULL);
    ~Recurse();

    bool listen(quint64 port, QHostAddress address = QHostAddress::Any);
    void use(next_f next);

private:
    QCoreApplication app;
    QTcpServer m_tcp_server;

    quint64 m_port;
    QVector<next_f> m_middleware;
    int current_middleware = 0;
    void m_next(int &socket_id);
    void http_parse(Request &request);
    QString http_build_header(const Response &response);

    struct Client {
        QTcpSocket *socket;
        Request request;
        Response response;
    };

    QHash<int, Client> connections;
};

Recurse::Recurse(int & argc, char ** argv, QObject *parent) : app(argc, argv)
{
    Q_UNUSED(parent);
};

Recurse::~Recurse()
{

};

//!
//! \brief Recurse::listen
//! listen for tcp requests
//!
//! \param port tcp server port
//! \param address tcp server listening address
//!
//! \return true on success
//!
bool Recurse::listen(quint64 port, QHostAddress address)
{
    m_port = port;
    int bound = m_tcp_server.listen(address, port);
    if (!bound)
        return false;

    connect(&m_tcp_server, &QTcpServer::newConnection, [this] {
        qDebug() << "client connected";
        int socket_id = rand();

        connections[socket_id] = {
             m_tcp_server.nextPendingConnection()
        };

        connect(connections[socket_id].socket, &QTcpSocket::readyRead, [this, socket_id] {
            connections[socket_id].request.data = connections[socket_id].socket->readAll();
            http_parse(connections[socket_id].request);

            qDebug() << "client request: " << connections[socket_id].request.data;

            if (m_middleware.count() > 0)
                m_middleware[current_middleware](
                    connections[socket_id].request,
                    connections[socket_id].response,
                    bind(&Recurse::m_next, this, socket_id));

            current_middleware = 0;
            QString header;

            connections[socket_id].response.method = connections[socket_id].request.method;
            connections[socket_id].response.proto = connections[socket_id].request.proto;

            if (connections[socket_id].response.status == 0)
                connections[socket_id].response.status = 200;

            header = http_build_header(connections[socket_id].response);
            QString response_data = header + connections[socket_id].response.body;

            // send response to the client
            qint64 check = connections[socket_id].socket->write(
                response_data.toStdString().c_str(),
                response_data.size());

            qDebug() << "socket write debug:" << check;
            connections[socket_id].socket->close();
            connections.remove(socket_id);
        });
    });

    return app.exec();
};

//!
//! \brief Recurse::m_next
//! call next middleware
//!
void Recurse::m_next(int &socket_id)
{
    qDebug() << "calling next:" << current_middleware << " num:" << m_middleware.size();

    if (++current_middleware >= m_middleware.size()) {
        return;
    };

    m_middleware[current_middleware](
        connections[socket_id].request,
        connections[socket_id].response,
        bind(&Recurse::m_next, this, socket_id));
};

//!
//! \brief Recurse::use
{'fraction_non_alphanumeric': 0.13088463528194516, 'fraction_numerical': 0.0038799793067770304, 'mean_word_length': 2.941386340468909, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 39, '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': '703776', 'n_tokens_mistral': 2410, 'n_tokens_neox': 2251, 'n_words': 493}