Commit 36be4887 authored by Roy de Goei's avatar Roy de Goei

TMSS-156: First implementation of TMSSBridge using jsoncpp and curl

parent 50293588
# - Try to find readline, a library for easy editing of command lines.
# Variables used by this module:
# CURLCPP_ROOT_DIR - curl root directory
# Variables defined by this module:
# CURL_FOUND - system has curl
# CURL_INCLUDE_DIR - the curl include directory (cached)
# CURL_INCLUDE_DIRS - the curl include directories
# (identical to CURLCPP_INCLUDE_DIR)
# CURL_LIBRARY - the curl library (cached)
# CURL_LIBRARIES - the curl library
# Copyright (C) 2009
# ASTRON (Netherlands Institute for Radio Astronomy)
# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
#
# This file is part of the LOFAR software suite.
# The LOFAR software suite is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# The LOFAR software suite 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>.
#
# $Id$
if(NOT CURL_FOUND)
find_path(CURL_INCLUDE_DIR curl/curl.h
HINTS ${CURL_ROOT_DIR} PATH_SUFFIXES include) # curl headers
find_library(CURL_LIBRARY curl) # libcurl
mark_as_advanced(CURL_INCLUDE_DIR CURL_LIBRARY CURL_LIBRARY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(curl DEFAULT_MSG
CURL_LIBRARY CURL_INCLUDE_DIR)
set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR})
set(CURL_LIBRARIES ${CURL_LIBRARY})
endif(NOT CURL_FOUND)
# $Id$
lofar_find_package(JsonCpp)
lofar_find_package(CurlCpp)
lofar_find_package(Curl)
lofar_add_bin_program(MACScheduler
MACSchedulerMain.cc
......
......@@ -22,17 +22,14 @@
#include "TMSSBridge.h"
#include <boost/property_tree/json_parser.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/algorithm/string.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
#include <curlpp/cURLpp.hpp>
#include <curl/curl.h>
#include <jsoncpp/json/json.h>
namespace pt = boost::property_tree;
using namespace std;
......@@ -43,10 +40,10 @@ namespace LOFAR {
// TMSSBridge Constructor
//
TMSSBridge::TMSSBridge():
itsUser ("test"),
itsPassword ("test"),
itsHost ("http://127.0.0.1"), // just to start with maybe user and password need
itsPort (8000)
itsUser("test"),
itsPassword("test"),
itsHost("http://127.0.0.1"), // just to start with maybe user and password need
itsPort(8000)
{
}
......@@ -71,7 +68,6 @@ vector<int> TMSSBridge::getSubTaskIDStartingInThreeMinutes(ptime currentTime, st
string queryStr = "/api/?start_time__lt=" + currentTimeStr + "&cluster__name==" + clusterName;
Json::Value result = httpGET(itsHost, itsPort, queryStr);
vector<string> urlList = translateHttpResultToSortedUrlList(result);
}
......@@ -83,38 +79,113 @@ vector<int> TMSSBridge::getSubTaskIDStartingInThreeMinutes(ptime currentTime, st
// json_response.get('count'))
// ... and results[idx].items('url)
// if multiple found sort on startTime !
vector<string> TMSSBridge::translateHttpResultToSortedUrlList(Json::Value jsonResult)
vector<string> TMSSBridge::translateHttpResultToSortedUrlList(Json::Value jsonRoot)
{
vector<string> urlList;
vector<string> urlList{};
// Read values
int nbrSubTasksFound = jsonResult["count"].asInt();
urlList.push_back("20000000000");
const int nbrTasksFound(jsonRoot["count"].asInt());
const Json::Value results = jsonRoot["results"];
for(int idx=0; idx<results.size(); ++idx) {
string urlStr = results[idx]["url"].asString();
string startTimeStr = results[idx]["start_time"].asString();
// Only interested in the subTaskID
vector<string>tmp;
boost::split(tmp, urlStr, boost::is_any_of("/subtask/"));
urlList.push_back(tmp.at(1).c_str());
// TODO: I am lazy now....sort on ascending starttime
}
return urlList;
}
std::size_t callback(const char* in,
std::size_t size,
std::size_t num,
std::string* out)
{
const std::size_t totalBytes(size * num);
out->append(in, totalBytes);
return totalBytes;
}
//
// Performs an HTTP GET and return the response body
// Need to check respons status code of http (200)
// Inspired by https://gist.github.com/connormanning/41efa6075515019e499c
// Example:
// httpGET("http://127.0.0.1", 8000, "/api/subtask/?start_time__lt=2020-03-04T12:03:00"
// results in a json string output
//
Json::Value TMSSBridge::httpGET(const string& host, const int port, const string& target)
{
// TODO Execute using curl stuff and endup with Json::Value
// Check for http result 200
Json::Value jsonResult("dummy");
return jsonResult;
Json::Value jsonData("");
const std::string url(host + target);
CURL* curl = curl_easy_init();
// Set remote URL.
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
// Don't bother trying IPv6, which would increase DNS resolution time.
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
// Don't wait forever, time out after 10 seconds.
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
// Follow HTTP redirects if necessary.
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
// Response information.
long httpCode(0);
std::unique_ptr<std::string> httpData(new std::string());
// Hook up data handling function.
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
// Hook up data container (will be passed as the last parameter to the
// callback handling function). Can be any pointer type, since it will
// internally be passed as a void pointer.
curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get());
// Run our HTTP GET command, capture the HTTP response code, and clean up.
curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
curl_easy_cleanup(curl);
if (httpCode == 200)
{
std::cout << "\nGot successful response from " << url << std::endl;
// Response looks good - done using Curl now. Try to parse the results
// and print them out.
Json::Reader jsonReader;
std::string httpResponse(*httpData.get());
if (jsonReader.parse(httpResponse, jsonData))
{
// TODO:
// How we deal with logging in Lofar C++ ?
// for now just do a stdout...
std::cout << "Successfully parsed JSON data" << std::endl;
std::cout << "\nJSON data received:" << std::endl;
std::cout << jsonData.toStyledString() << std::endl;
}
else
{
THROW(TMSSBridgeException, "Could not parse HTTP data as JSON. HTTP data was:\n" + httpResponse);
}
}
else
{
THROW(TMSSBridgeException, "Couldn't GET from " + url + " exiting with http code " + to_string(httpCode));
}
return jsonData;
}
};//MainCU
};//LOFAR
......@@ -23,6 +23,8 @@
#ifndef TMSSBRIDGE_H
#define TMSSBRIDGE_H
#include <Common/LofarTypes.h>
#include <Common/Exception.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <jsoncpp/json/json.h>
......@@ -43,22 +45,25 @@ public:
vector<int> getSubTaskIDStartingInThreeMinutes(ptime currentTime, string clusterName);
// Actually the next method is private, make it public to be able to use in UnitTest++
// Actually the next method are private, make it public to be able to use in UnitTest++
vector<string> translateHttpResultToSortedUrlList(Json::Value result);
// http request to TMSS
Json::Value httpGET(const string& host, int const port, const string& target);
private:
// Copying is not allowed
TMSSBridge(const TMSSBridge&);
TMSSBridge& operator=(const TMSSBridge&);
// http request to TMSS
Json::Value httpGET(const string& host, int const port, const string& target);
string itsUser;
string itsPassword;
string itsHost;
int itsPort;
};
EXCEPTION_CLASS(TMSSBridgeException, LOFAR::Exception);
};//MainCU
};//LOFAR
#endif
......@@ -27,7 +27,6 @@
#include <fstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <jsonccp/json/json.h>
......@@ -38,6 +37,7 @@ using namespace boost::property_tree;
using namespace LOFAR::MainCU;
// Helper funtion to retrieve json data from a file
Json::Value readFile(const std::string& jsonFile)
{
ifstream ifs(jsonFile.c_str());
......@@ -54,15 +54,17 @@ Json::Value readFile(const std::string& jsonFile)
}
// Check if given json data (read from file) results ins correct output vector
//
TEST(tmss_translate_http_result_ok)
{
// check if json read goes well as precondition for the test
// See jsoncpp https://github.com/open-source-parsers/jsoncpp/wiki
// Check if json read goes well as precondition for the test
Json::Value jsonData(readFile("test_response.json"));
int count = jsonData["count"];
// check if count is equal to 4 .... otherwise precond test did not match so will make no sense to continue
// Check if count is equal to 4, otherwise precondition of the test is not ok, so fail
CHECK_EQUAL(4, count);
std::cout << count;
TMSSBridge testTMSSBridge;
......@@ -74,18 +76,19 @@ TEST(tmss_translate_http_result_ok)
}
// An empty json file should result in an empty vector list
TEST(tmss_translate_http_empty_result)
{
Json::Value jsonData("{}");
TMSSBridge testTMSSBridge;
// Read file json
std::vector<string> testResult;
testResult = testTMSSBridge.translateHttpResultToSortedUrlList(jsonData);
// Do some check like CHECK_EQUAL
}
int main(int, const char *[])
{
return UnitTest::RunAllTests();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment