Skip to content

Commit

Permalink
Working create endpoint for Geolocation — Made Redis connection come …
Browse files Browse the repository at this point in the history
…from RedisConnectionPool
  • Loading branch information
kennymalac committed Jul 11, 2018
1 parent 601d7cb commit c3c1114
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 38 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ set(CMAKE_VERBOSE_MAKEFILE ON)

set(CMAKE_BUILD_TYPE Debug)

# TODO use PIE exe - fix HttpRouter linking issue
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -pthread -no-pie")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -pthread")

# Export a JSON file with information about our build for irony-mode
set(CMAKE_EXPORT_COMPILE_COMMANDS on)
Expand Down Expand Up @@ -48,6 +47,7 @@ ExternalProject_Get_Property(PocoHttpRouterProject install_dir)
include_directories(include ${CMAKE_CURRENT_BINARY_DIR}/include/PocoHttpRouter/src)

add_library(GeospaceServer_Base ${HEADERS} ${SOURCES})
target_link_libraries(GeospaceServer_Base PocoRedis)
add_executable(GeospaceServer src/main.cpp)

add_dependencies(GeospaceServer PocoHttpRouterProject)
Expand Down
24 changes: 15 additions & 9 deletions include/handlers.hpp
Original file line number Diff line number Diff line change
@@ -1,35 +1,41 @@
#include <memory>
#include <optional>

#include "Poco/ObjectPool.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Redis/Client.h"
#include "Poco/Redis/PoolableConnectionFactory.h"
#include "Poco/JSON/Parser.h"

namespace GeoSpaceServer {
using Poco::Net::HTTPServerRequest;
using Poco::Net::HTTPResponse;
using Poco::Net::HTTPServerResponse;
namespace Redis = Poco::Redis;

using RedisClient = Poco::Redis::Client;
using JSONParser = Poco::JSON::Parser;
using RedisConnectionPool = Poco::ObjectPool<Redis::Client, Redis::Client::Ptr>;


auto errorResponse(std::string text, std::string errorCode, HTTPResponse::HTTPStatus statusCode, HTTPServerResponse& response, std::ostream& output);

class GeoLocationHandler
{
protected:
std::shared_ptr<JSONParser> parser;
std::shared_ptr<RedisClient> redisClient;
JSONParser parser;
Redis::Client::Ptr redisClient;

public:
virtual void finishResponse(HTTPServerRequest& request,
HTTPServerResponse& response) = 0;

virtual void operator()(HTTPServerRequest& request, HTTPServerResponse& response);

inline GeoLocationHandler(std::shared_ptr<JSONParser> p, std::shared_ptr<RedisClient> rc)
: parser(p), redisClient(rc)
{}
inline GeoLocationHandler(RedisConnectionPool& rc)
{
redisClient = Redis::PooledConnection(rc);
}
inline ~GeoLocationHandler() {};
};

Expand All @@ -39,7 +45,7 @@ class GeoLocationCreateHandler : public GeoLocationHandler
void finishResponse(HTTPServerRequest& request,
HTTPServerResponse& response);

GeoLocationCreateHandler(std::shared_ptr<JSONParser> p, std::shared_ptr<RedisClient> rc);
GeoLocationCreateHandler(RedisConnectionPool& rc);

inline ~GeoLocationCreateHandler() {};
};
Expand All @@ -50,7 +56,7 @@ class GeoLocationDeleteHandler : public GeoLocationHandler
void finishResponse(HTTPServerRequest& request,
HTTPServerResponse& response);

GeoLocationDeleteHandler(std::shared_ptr<JSONParser> p, std::shared_ptr<RedisClient> rc);
GeoLocationDeleteHandler(RedisConnectionPool& rc);

inline ~GeoLocationDeleteHandler() {};
};
Expand All @@ -61,7 +67,7 @@ class GeoLocationDistanceHandler : public GeoLocationHandler
void finishResponse(HTTPServerRequest& request,
HTTPServerResponse& response);

GeoLocationDistanceHandler(std::shared_ptr<JSONParser> p, std::shared_ptr<RedisClient> rc);
GeoLocationDistanceHandler(RedisConnectionPool& rc);

inline ~GeoLocationDistanceHandler() {};
};
Expand Down
68 changes: 49 additions & 19 deletions src/handlers.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
#include <string>

#include "Poco/Redis/Array.h"
#include "include/handlers.hpp"

namespace GeoSpaceServer {
namespace JSON = Poco::JSON;
namespace Redis = Poco::Redis;

auto errorResponse(std::string text, std::string errorCode, HTTPResponse::HTTPStatus statusCode, HTTPServerResponse& response) {
response.setStatusAndReason(statusCode);
auto& output = response.send();

auto errorResponse(std::string text, std::string errorCode, HTTPResponse::HTTPStatus statusCode, HTTPServerResponse& response, std::ostream& output) {
response.setStatus(statusCode);
auto errorData = new JSON::Object;
errorData->set("message", text);
errorData->set("error_code", errorCode);
Expand All @@ -14,27 +20,25 @@ auto errorResponse(std::string text, std::string errorCode, HTTPResponse::HTTPSt

void GeoLocationHandler::operator()(HTTPServerRequest& request,
HTTPServerResponse& response) {
auto& output = response.send();

try {
finishResponse(request, response);
response.setContentType("text/json");
finishResponse(request, response);
}
catch (Poco::InvalidAccessException e) {
errorResponse(e.displayText(), "MISSING_FIELDS", HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST, response, output);
errorResponse(e.displayText(), "MISSING_FIELDS", HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST, response);
}
catch (Poco::NotImplementedException e) {
errorResponse(e.displayText(), "INVALID_FIELDS", HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST, response, output);
errorResponse(e.displayText(), "INVALID_FIELDS", HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST, response);
}
catch (Poco::RangeException e) {
errorResponse(e.displayText(), "INVALID_FIELDS", HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST, response, output);
errorResponse(e.displayText(), "INVALID_FIELDS", HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST, response);
}
catch (Poco::JSON::JSONException e) {
errorResponse(e.displayText(), "INVALID_JSON", HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST, response, output);
errorResponse(e.displayText(), "INVALID_JSON", HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST, response);
}
catch (Poco::Redis::RedisException e) {
std::cout << e.displayText() << "\n";
errorResponse(e.displayText(), "REDIS", HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR, response, output);
errorResponse(e.displayText(), "REDIS", HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR, response);
}
}

Expand All @@ -53,26 +57,51 @@ auto getLocation(JSON::Object::Ptr data) {
return std::make_tuple(longitude, latitude);
}

GeoLocationCreateHandler::GeoLocationCreateHandler(std::shared_ptr<JSONParser> p, std::shared_ptr<RedisClient> rc)
: GeoLocationHandler(p, rc)
GeoLocationCreateHandler::GeoLocationCreateHandler(RedisConnectionPool& rc)
: GeoLocationHandler(rc)
{}

void GeoLocationCreateHandler::finishResponse(HTTPServerRequest& request,
HTTPServerResponse& response) {
/**
{
"user_id": 1,
"place_id": 1,
"latitude": 10.0,
"longitude": 10.0
}
*/
JSON::Object::Ptr data = parser->parse(request.stream()).extract<JSON::Object::Ptr>();
// std::string body(std::istreambuf_iterator<char>(request.stream()), {});
// std::cout << body;
JSON::Object::Ptr data = parser.parse(request.stream()).extract<JSON::Object::Ptr>();

auto [longitude, latitude] = getLocation(data);
int userId;
data->get("user_id").convert(userId);
int placeId;
data->get("place_id").convert(placeId);

Redis::Array command;
command << "GEOADD" << "USER-" + std::to_string(userId) <<
std::to_string(longitude) <<
std::to_string(latitude) <<
"PLACE-" + std::to_string(placeId) + "";

std::cout << command.toString() << "\n";

auto placesAddedAmount = redisClient->execute<signed long>(command);
std::cout << std::to_string(placesAddedAmount) << "\n";

Redis::Array getCommand;
getCommand << "GEOPOS" << "USER-" + std::to_string(userId) << "PLACE-" + std::to_string(placeId);
std::cout << "result: " << redisClient->execute<Redis::Array>(getCommand).toString() << "\n";

response.setStatus(HTTPResponse::HTTPStatus::HTTP_CREATED);
response.send();
}

GeoLocationDeleteHandler::GeoLocationDeleteHandler(std::shared_ptr<JSONParser> p, std::shared_ptr<RedisClient> rc)
: GeoLocationHandler(p, rc)
GeoLocationDeleteHandler::GeoLocationDeleteHandler(RedisConnectionPool& rc)
: GeoLocationHandler(rc)
{}

void GeoLocationDeleteHandler::finishResponse(HTTPServerRequest& request,
Expand All @@ -82,17 +111,18 @@ void GeoLocationDeleteHandler::finishResponse(HTTPServerRequest& request,
"place_id": "1"
}
*/
JSON::Object::Ptr data = parser->parse(request.stream()).extract<JSON::Object::Ptr>();
JSON::Object::Ptr data = parser.parse(request.stream()).extract<JSON::Object::Ptr>();

auto placeId = data->get("place_id");


// delete this place
// TODO
}


GeoLocationDistanceHandler::GeoLocationDistanceHandler(std::shared_ptr<JSONParser> p, std::shared_ptr<RedisClient> rc)
: GeoLocationHandler(p, rc)
GeoLocationDistanceHandler::GeoLocationDistanceHandler(RedisConnectionPool& rc)
: GeoLocationHandler(rc)
{}

void GeoLocationDistanceHandler::finishResponse(HTTPServerRequest& request,
Expand All @@ -110,7 +140,7 @@ void GeoLocationDistanceHandler::finishResponse(HTTPServerRequest& request,
"unit": "km"
}
*/
JSON::Object::Ptr data = parser->parse(request.stream()).extract<JSON::Object::Ptr>();
JSON::Object::Ptr data = parser.parse(request.stream()).extract<JSON::Object::Ptr>();

auto [longitude, latitude] = getLocation(data);

Expand Down
22 changes: 14 additions & 8 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include "Poco/Util/Application.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/ObjectPool.h"

#include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/SecureServerSocket.h"
Expand All @@ -10,8 +12,10 @@
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Redis/Client.h"
#include "Poco/Redis/PoolableConnectionFactory.h"
#include "Poco/JSON/Parser.h"
#include "Poco/StreamCopier.h"
#include "Poco/SharedPtr.h"

// TODO figure this out
#include "PocoHttpRouterProject/include/HttpRouter.h"
Expand All @@ -27,8 +31,9 @@ using Poco::Net::HTTPRequestHandlerFactory;
using Poco::ThreadPool;
using Poco::Dynamic::Var;

using RedisClient = Poco::Redis::Client;
namespace Redis = Poco::Redis;
using JSONParser = Poco::JSON::Parser;
using RedisConnectionPool = Poco::ObjectPool<Redis::Client, Redis::Client::Ptr>;


class MethodNotAllowedHandler : public Poco::Net::HTTPRequestHandler {
Expand All @@ -53,25 +58,26 @@ class GeospaceServer : public Poco::Util::ServerApplication {
auto port = static_cast<unsigned short>(config().getInt("GeospaceServer.port", 9980));
std::string hostname = config().getString("GeospaceServer.redis.hostname", "127.0.0.1");

auto redisPort = static_cast<unsigned short>(config().getInt("GeospaceServer.redis.port", 6380));
auto redisPort = static_cast<unsigned short>(config().getInt("GeospaceServer.redis.port", 6379));

//

// set-up a server socket
ServerSocket service(port);
auto parser = std::make_shared<JSONParser>();
// auto parser = std::make_shared<JSONParser>();
// hostname, redisPort
auto redisClient = std::make_shared<RedisClient>();
Poco::Net::SocketAddress redisAddress(hostname, redisPort);

RedisConnectionPool redisConnectionPool(Poco::PoolableObjectFactory<Redis::Client, Redis::Client::Ptr>(redisAddress), 4, 4);

auto* router = new HttpRouter();

auto locationCreateHandler = contextRequestHandler<GeoLocationCreateHandler, std::shared_ptr<JSONParser>, std::shared_ptr<RedisClient>>(parser, redisClient);
auto locationDeleteHandler = contextRequestHandler<GeoLocationDeleteHandler, std::shared_ptr<JSONParser>, std::shared_ptr<RedisClient>>(parser, redisClient);
auto locationDistanceHandler = contextRequestHandler<GeoLocationDistanceHandler, std::shared_ptr<JSONParser>, std::shared_ptr<RedisClient>>(parser, redisClient);
auto locationCreateHandler = contextRequestHandler<GeoLocationCreateHandler, RedisConnectionPool&>(redisConnectionPool);
auto locationDeleteHandler = contextRequestHandler<GeoLocationDeleteHandler, RedisConnectionPool&>(redisConnectionPool);
auto locationDistanceHandler = contextRequestHandler<GeoLocationDistanceHandler, RedisConnectionPool&>(redisConnectionPool);

//router->AddRoute("/location/", list, "GET");
router->AddRoute("/location/", locationCreateHandler, "CREATE");
router->AddRoute("/location/", locationCreateHandler, "PUT");
router->AddRoute("/location/", locationDeleteHandler, "DELETE");
router->AddRoute("/location/distance", locationDistanceHandler, "POST");

Expand Down
8 changes: 8 additions & 0 deletions tasks.org
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
* tasks
** DONE location create endpoint
CLOSED: [2018-07-11 Wed 12:23]
** TODO location delete endpoint
** TODO location distance calculation endpoint
** TODO use SecureServerSocket
** TODO fix HTTPRouter include issue
** TODO make JSONParser ObjectPool (?)

0 comments on commit c3c1114

Please sign in to comment.