/* * Copyright (C) 2016-2018 Savoir-faire Linux Inc. * * Author: Simon Zeni <simon.zeni@savoirfairelinux.com> * * 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 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "restclient.h" RestClient::RestClient(int port, int flags, bool persistent) : service_() { configurationManager_.reset(new RestConfigurationManager()); videoManager_.reset(new RestVideoManager()); if (initLib(flags) < 0) throw std::runtime_error {"cannot initialize libring"}; // Fill the resources initResources(); // Initiate the rest service settings_ = std::make_shared<restbed::Settings>(); settings_->set_port(port); settings_->set_default_header( "Connection", "close" ); RING_INFO("Restclient running on port [%d]", port); // Make it run in a thread, because this is a blocking function restbed = std::thread([this](){ service_.start(settings_); }); } RestClient::~RestClient() { RING_INFO("destroying RestClient"); exit(); } int RestClient::event_loop() noexcept { // While the client is running, the events are polled every 10 milliseconds RING_INFO("Restclient starting to poll events"); while(!pollNoMore_) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } return 0; } int RestClient::exit() noexcept { try { // On exit, the client stop polling events pollNoMore_ = true; // The rest service is stopped service_.stop(); // And the thread running the service is joined restbed.join(); endLib(); } catch (const std::exception& err) { std::cerr << "quitting: " << err.what() << std::endl; return 1; } return 0; } int RestClient::initLib(int flags) { using namespace std::placeholders; using std::bind; using DRing::exportable_callback; using DRing::CallSignal; using DRing::ConfigurationSignal; using DRing::PresenceSignal; using DRing::AudioSignal; using SharedCallback = std::shared_ptr<DRing::CallbackWrapperBase>; auto confM = configurationManager_.get(); #ifdef RING_VIDEO using DRing::VideoSignal; #endif // Configuration event handlers // This is a short example of a callback using a lambda. In this case, this displays the incoming messages const std::map<std::string, SharedCallback> configEvHandlers = { exportable_callback<ConfigurationSignal::IncomingAccountMessage>([] (const std::string& accountID, const std::string& from, const std::map<std::string, std::string>& payloads){ RING_INFO("accountID : %s", accountID.c_str()); RING_INFO("from : %s", from.c_str()); RING_INFO("payloads"); for(auto& it : payloads) RING_INFO("%s : %s", it.first.c_str(), it.second.c_str()); }), }; if (!DRing::init(static_cast<DRing::InitFlag>(flags))) return -1; registerSignalHandlers(configEvHandlers); // Dummy callbacks are registered for the other managers registerSignalHandlers(std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>>()); registerSignalHandlers(std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>>()); #ifdef RING_VIDEO registerSignalHandlers(std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>>()); #endif if (!DRing::start()) return -1; return 0; } void RestClient::endLib() noexcept { DRing::fini(); } void RestClient::initResources() { // This is the function that initiates the resources. // Each resources is defined by a route and a void function with a shared pointer to the session as argument // In this case, here's an example of the default route. It will list all the managers available auto default_res = std::make_shared<restbed::Resource>(); default_res->set_path("/"); default_res->set_method_handler("GET", [](const std::shared_ptr<restbed::Session> session){ RING_INFO("[%s] GET /", session->get_origin().c_str()); std::string body = "Available routes are : \r\n/configurationManager\r\n/videoManager\r\n"; const std::multimap<std::string, std::string> headers { {"Content-Type", "text/html"}, {"Content-Length", std::to_string(body.length())} }; }); // And finally, we give the resource to the service to handle it service_.publish(default_res); // For the sake of convenience, each manager sends a vector of their resources for(auto& it : configurationManager_->getResources()) service_.publish(it); for(auto& it : videoManager_->getResources()) service_.publish(it); }