Getting close to a release of generic server.
Nisse Server: Part 1 Helper Functions
Nisse Server: Part 2 Socket Layer
Nisse Server: Part 3 Stream Layer
Nisse Server: Part 4 Server
As I mentioned each connection is handled by a new handler object of specific type. These need to be derived from NisseHandler
. But you only need to worry about this if you are creating a handler for a specific protocol (like HTTP, I have started the HTTP handler (still some work to do)).
But this also defines the standard handler that waits for the connection and created you port specific handler.
NisseHandler.h
#ifndef THORSANVIL_NISSE_NISSE_HANDLER_H
#define THORSANVIL_NISSE_NISSE_HANDLER_H
#include "NisseEventUtil.h"
#include "Socket.h"
extern "C" void eventCB(ThorsAnvil::Nisse::LibSocketId socketId, short eventType, void* event);
namespace ThorsAnvil
{
namespace Nisse
{
using EventDeleter = decltype(&event_free);
using NisseEvent = std::unique_ptr<LibEvent, EventDeleter>;
class NisseService;
class NisseHandler
{
private:
NisseService& parent;
NisseEvent event;
public:
NisseHandler(NisseService& parent, LibEventBase* base, LibSocketId socketId, short eventType);
virtual ~NisseHandler() {}
virtual void eventActivate(LibSocketId sockId, short eventType);
protected:
void dropHandler();
template<typename H, typename... Args>
void addHandler(Args&&... args);
template<typename H, typename... Args>
void moveHandler(Args&&... args);
};
template<typename Handler, typename Param>
class ServerHandler: public NisseHandler
{
private:
ThorsAnvil::Socket::ServerSocket socket;
Param& param;
public:
ServerHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::ServerSocket&& so, Param& param);
virtual void eventActivate(LibSocketId sockId, short eventType) override;
};
template<typename Handler>
class ServerHandler<Handler, void>: public NisseHandler
{
private:
ThorsAnvil::Socket::ServerSocket socket;
public:
ServerHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::ServerSocket&& so);
virtual void eventActivate(LibSocketId sockId, short eventType) override;
};
}
}
#ifndef COVERAGE_TEST
#include "NisseHandler.tpp"
#endif
#endif
NisseHandler.tpp
#ifndef THORSANVIL_NISSE_NISSE_HANDLER_TPP
#define THORSANVIL_NISSE_NISSE_HANDLER_TPP
#include "NisseService.h"
namespace ThorsAnvil
{
namespace Nisse
{
template<typename H, typename... Args>
inline void NisseHandler::addHandler(Args&&... args)
{
parent.addHandler<H>(std::forward<Args>(args)...);
}
template<typename H, typename... Args>
inline void NisseHandler::moveHandler(Args&&... args)
{
dropHandler();
parent.addHandler<H>(std::forward<Args>(args)...);
}
template<typename Handler, typename Param>
inline ServerHandler<Handler, Param>::ServerHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::ServerSocket&& so, Param& param)
: NisseHandler(parent, base, so.getSocketId(), EV_READ)
, socket(std::move(so))
, param(param)
{}
template<typename Handler, typename Param>
inline void ServerHandler<Handler, Param>::eventActivate(LibSocketId /*sockId*/, short /*eventType*/)
{
ThorsAnvil::Socket::DataSocket accepted = socket.accept();
addHandler<Handler>(std::move(accepted), param);
}
template<typename Handler>
inline ServerHandler<Handler, void>::ServerHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::ServerSocket&& so)
: NisseHandler(parent, base, so.getSocketId(), EV_READ)
, socket(std::move(so))
{}
template<typename Handler>
inline void ServerHandler<Handler, void>::eventActivate(LibSocketId /*sockId*/, short /*eventType*/)
{
ThorsAnvil::Socket::DataSocket accepted = socket.accept();
addHandler<Handler>(std::move(accepted));
}
}
}
#endif
NisseHandler.cpp
#include "NisseHandler.h"
#include "NisseService.h"
#include "Utility.h"
#include <iostream>
using namespace ThorsAnvil::Nisse;
void eventCB(LibSocketId socketId, short eventType, void* event)
{
NisseHandler& handler = *reinterpret_cast<NisseHandler*>(event);
handler.eventActivate(socketId, eventType);
}
NisseHandler::NisseHandler(NisseService& parent, LibEventBase* base, LibSocketId socketId, short eventType)
: parent(parent)
, event(event_new(base, socketId, eventType | EV_PERSIST, eventCB, this), event_free)
{
if (event.get() == nullptr)
{
throw std::runtime_error(Socket::buildErrorMessage("ThorsAnvil::Nisse::NisseHandler::", __func__, ": event_new(): Failed"));
}
if (event_add(event.get(), nullptr) != 0)
{
throw std::runtime_error(Socket::buildErrorMessage("ThorsAnvil::Nisse::NisseHandler::", __func__, ": event_add(): Failed"));
}
}
void NisseHandler::eventActivate(LibSocketId sockId, short eventType)
{
std::cerr << "Callback made: " << sockId << " For " << eventType << "\n";
}
void NisseHandler::dropHandler()
{
if (event_del(event.get()) != 0)
{
throw std::runtime_error(Socket::buildErrorMessage("ThorsAnvil::Nisse::NisseEvent::", __func__, ": event_del(): Failed"));
}
parent.delHandler(this);
}
#ifdef COVERAGE_TEST
/*
* This code is only compiled into the unit tests for code coverage purposes
* It is not part of the live code.
*/
#include "NisseHandler.tpp"
#endif