Skip to content
Snippets Groups Projects
TMSSBridge.cc 6.12 KiB
Newer Older
//  TMSSBridge.cc: Implementation of the TMSS Bridge, interface between MAC Scheduler and TMSS
//
//  Copyright (C) 2020
//  ASTRON (Netherlands Foundation for Research in Astronomy)
//  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, softwaresupport@astron.nl
//
//  This program 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 2 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 General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  $Id$
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/algorithm/string.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
Jorrit Schaap's avatar
Jorrit Schaap committed
#include <format>

namespace LOFAR {
	namespace MainCU {

//
// TMSSBridge Constructor
//
TMSSBridge::TMSSBridge(const std::string &hostname, int port, const std::string &username, const std::string &password):
	itsUser(username),
	itsPassword(password),
	itsHost(hostname),
	itsPort(port)
{
}

//
// TMSSBridge Destructor
//
TMSSBridge::~TMSSBridge()
{

}


//
// get all subTaskIDS that should run within three minutes (ordered in time if multiple are found)
// for given cluster
//
vector<int> TMSSBridge::getSubTaskIDStartingInThreeMinutes(ptime currentTime, string clusterName)
{
    string currentTimeStr = to_iso_extended_string(currentTime);
    string queryStr = "/api/?start_time__lt=" + currentTimeStr + "&cluster__name==" + clusterName;
Jorrit Schaap's avatar
Jorrit Schaap committed
    Json::Value result = httpGET(queryStr);
    vector<string> urlList = translateHttpResultToSortedUrlList(result);
}
//
// Translate the HTTP result to json format and parse the json format
//     How to handle json structure in C++?
//     Get the number of taskIDs like python
//     json_response = response.json()
//     json_response.get('count'))
//     ... and results[idx].items('url)
//     if multiple found sort on startTime !
vector<string> TMSSBridge::translateHttpResultToSortedUrlList(Json::Value jsonRoot)
    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 
    }
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
//    httpGET("/api/subtask/?start_time__lt=2020-03-04T12:03:00"
Json::Value TMSSBridge::httpGET(const string& target)

    const std::string url(std::format("http://{}:{}/{}", itsHost, itsPort, target));
    // setup authentication
    curl_easy_setopt(curl, CURLOPT_USERNAME, itsUser.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, itsPassword.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);

    // 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;