RetroShare/libresapi/src/api/ResourceRouter.h

111 lines
4.7 KiB
C++

/*******************************************************************************
* libresapi/api/ResourceRouter.h *
* *
* LibResAPI: API for local socket server *
* *
* Copyright 2018 by Retroshare Team <retroshare.project@gmail.com> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include "ApiTypes.h"
#include <iostream>
namespace resource_api
{
// a base class for routing requests to handler methods
// nothing is thread safe here
class ResourceRouter
{
public:
virtual ~ResourceRouter();
// can return NULL, if the request was processed
// if the Response can not be created immediately,
// then return a object which implements the ResponseTask interface
ResponseTask* handleRequest(Request& req, Response& resp);
template <class T>
void addResourceHandler(std::string name, T* instance, ResponseTask* (T::*callback)(Request& req, Response& resp));
template <class T>
void addResourceHandler(std::string name, T* instance, void (T::*callback)(Request& req, Response& resp));
bool isNameUsed(std::string name);
private:
class HandlerBase
{
public:
virtual ~HandlerBase(){}
virtual ResponseTask* handleRequest(Request& req, Response& resp) = 0;
};
template <class T>
class Handler: public HandlerBase
{
public:
virtual ResponseTask* handleRequest(Request &req, Response &resp)
{
return (instance->*method)(req, resp);
}
T* instance;
ResponseTask* (T::*method)(Request& req, Response& resp);
};
template <class T>
class InstantResponseHandler: public HandlerBase
{
public:
virtual ResponseTask* handleRequest(Request &req, Response &resp)
{
(instance->*method)(req, resp);
return 0;
}
T* instance;
void (T::*method)(Request& req, Response& resp);
};
std::vector<std::pair<std::string, HandlerBase*> > mHandlers;
};
// the advantage of this approach is:
// the method name is arbitrary, one class can have many different handler methods
// with raw objects the name of the handler method would be fixed, and we would need one class for every handler
// the downside is complicated template magic
template <class T>
void ResourceRouter::addResourceHandler(std::string name, T* instance, ResponseTask* (T::*callback)(Request& req, Response& resp))
{
if(isNameUsed(name))
{
std::cerr << "ResourceRouter::addResourceHandler ERROR: name=" << name << " alerady in use. Not adding new Handler!" << std::endl;
}
Handler<T>* handler = new Handler<T>();
handler->instance = instance;
handler->method = callback;
mHandlers.push_back(std::make_pair(name, handler));
}
template <class T>
void ResourceRouter::addResourceHandler(std::string name, T* instance, void (T::*callback)(Request& req, Response& resp))
{
if(isNameUsed(name))
{
std::cerr << "ResourceRouter::addResourceHandler ERROR: name=" << name << " alerady in use. Not adding new Handler!" << std::endl;
}
InstantResponseHandler<T>* handler = new InstantResponseHandler<T>();
handler->instance = instance;
handler->method = callback;
mHandlers.push_back(std::make_pair(name, handler));
}
} // namespace resource_api