mirror of
https://git.jami.net/savoirfairelinux/jami-daemon.git
synced 2025-08-12 22:09:25 +08:00
add a restcpp API backend
This commit offers an alternative to the dbus client to communicate with a headless daemon. It uses restbed, a cpp framework for RESTful services. This commits wraps up: - The source of the restbed implementation (in bin/restcpp) - The integration of the target to the configure.ac - documentation - Add external restbed library to contrib: - rules.mak file, to download the version 4.0, and compile it - Patch for ASIO, a dependency of restbed - Patch for the CMakeLists.txt file, to correct the installation path [guillaume.roguez@savoirfairelinux.com: merged with Simon Zeni patch to support restbed into contrib] [guillaume.roguez@savoirfairelinux.com: add tuleap ticket number] [guillaume.roguez@savoirfairelinux.com: fixed configure.ac --without-restbed behavior] Change-Id: Id49a1a04b05aac1e803981833abe5564785fb801 Tuleap: #498 Reviewed-by: Alexandre Lision <alexandre.lision@savoirfairelinux.com> Signed-off-by: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
This commit is contained in:
23
README
23
README
@ -47,7 +47,7 @@ Short description of content of source tree
|
||||
- src/ is the core of DRing.
|
||||
- bin/ contains applications main code.
|
||||
- bin/dbus, the D-Bus xml interfaces, and c++ bindings
|
||||
|
||||
- bin/restcpp, the C++ REST API implemented with Restbed
|
||||
|
||||
About Savoir-faire Linux
|
||||
------------------------
|
||||
@ -133,6 +133,27 @@ interaction between daemon and client will not work; for each platform where
|
||||
dbus is not available the client should implement all the methods in the
|
||||
*_stub.cpp files.
|
||||
|
||||
How to compile with the REST API
|
||||
--------------------------------
|
||||
|
||||
Ring offers two REST API. One written in C++, and the other written in Cython.
|
||||
Up to this date, only the C++ API is available. The Cython API will soon follow.
|
||||
|
||||
To compile Ring-daemon with the C++ REST API, follow these two steps :
|
||||
|
||||
1) Compile the dependencies
|
||||
cd contrib
|
||||
mkdir native
|
||||
cd native
|
||||
../bootstrap
|
||||
make
|
||||
make .restbed
|
||||
|
||||
2) Then compile the daemon
|
||||
cd ../../
|
||||
./autogen.sh
|
||||
./configure --without-dbus --with-restcpp
|
||||
make
|
||||
|
||||
SIP accounts
|
||||
---------------------
|
||||
|
@ -31,3 +31,19 @@ dring_CXXFLAGS= -I$(top_srcdir)/src ${DBUSCPP_CFLAGS} \
|
||||
|
||||
dring_LDADD = dbus/libclient_dbus.la ${DBUSCPP_LIBS} $(top_builddir)/src/libring.la
|
||||
endif
|
||||
|
||||
if RING_RESTCPP
|
||||
SUBDIRS=restcpp
|
||||
|
||||
sbin_PROGRAMS = dring
|
||||
|
||||
dring_SOURCES = main.cpp
|
||||
|
||||
dring_CXXFLAGS= -g \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/src/dring \
|
||||
-DREST_API \
|
||||
-DTOP_BUILDDIR=\"$$(cd "$(top_builddir)"; pwd)\"
|
||||
|
||||
dring_LDADD = restcpp/libclient_rest.la $(top_builddir)/src/libring.la
|
||||
endif
|
||||
|
81
bin/main.cpp
81
bin/main.cpp
@ -4,6 +4,7 @@
|
||||
* Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
|
||||
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
|
||||
* Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
|
||||
* 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
|
||||
@ -25,12 +26,28 @@
|
||||
#include <cstring>
|
||||
#include <signal.h>
|
||||
#include <getopt.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "dring/dring.h"
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#if REST_API
|
||||
#include "restcpp/restclient.h"
|
||||
#else
|
||||
#include "dbus/dbusclient.h"
|
||||
#endif
|
||||
|
||||
#include "fileutils.h"
|
||||
|
||||
static int ringFlags = 0;
|
||||
static std::unique_ptr<DBusClient> dbusClient;
|
||||
static int port = 8080;
|
||||
|
||||
#if REST_API
|
||||
static std::unique_ptr<RestClient> restClient;
|
||||
#else
|
||||
static std::unique_ptr<DBusClient> dbusClient;
|
||||
#endif
|
||||
|
||||
static void
|
||||
print_title()
|
||||
@ -52,6 +69,7 @@ print_usage()
|
||||
"-c, --console \t- Log in console (instead of syslog)" << std::endl <<
|
||||
"-d, --debug \t- Debug mode (more verbose)" << std::endl <<
|
||||
"-p, --persistent \t- Stay alive after client quits" << std::endl <<
|
||||
"--port \t- Port to use for the rest API. Default is 8080" << std::endl <<
|
||||
"--auto-answer \t- Force automatic answer to incoming calls" << std::endl <<
|
||||
"-h, --help \t- Print help" << std::endl;
|
||||
}
|
||||
@ -76,6 +94,7 @@ parse_args(int argc, char *argv[], bool& persistent)
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{"auto-answer", no_argument, &autoAnswer, true},
|
||||
{"port", optional_argument, NULL, 'x'},
|
||||
{0, 0, 0, 0} /* Sentinel */
|
||||
};
|
||||
|
||||
@ -83,7 +102,7 @@ parse_args(int argc, char *argv[], bool& persistent)
|
||||
/* getopt_long stores the option index here. */
|
||||
int option_index = 0;
|
||||
|
||||
auto c = getopt_long(argc, argv, "dcphv", long_options, &option_index);
|
||||
auto c = getopt_long(argc, argv, "dcphvx:", long_options, &option_index);
|
||||
|
||||
// end of the options
|
||||
if (c == -1)
|
||||
@ -111,6 +130,10 @@ parse_args(int argc, char *argv[], bool& persistent)
|
||||
versionFlag = true;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
port = std::atoi(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -138,21 +161,6 @@ parse_args(int argc, char *argv[], bool& persistent)
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
run()
|
||||
{
|
||||
if (dbusClient)
|
||||
return dbusClient->event_loop();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
interrupt()
|
||||
{
|
||||
if (dbusClient)
|
||||
dbusClient->exit();
|
||||
}
|
||||
|
||||
static void
|
||||
signal_handler(int code)
|
||||
{
|
||||
@ -164,7 +172,14 @@ signal_handler(int code)
|
||||
signal(SIGINT, SIG_DFL);
|
||||
signal(SIGTERM, SIG_DFL);
|
||||
|
||||
interrupt();
|
||||
// Interrupt the process
|
||||
#if REST_API
|
||||
if (restClient)
|
||||
restClient->exit();
|
||||
#else
|
||||
if (dbusClient)
|
||||
dbusClient->exit();
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
@ -189,6 +204,25 @@ main(int argc, char *argv [])
|
||||
if (parse_args(argc, argv, persistent))
|
||||
return 0;
|
||||
|
||||
// TODO: Block signals for all threads but the main thread, decide how/if we should
|
||||
// handle other signals
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGHUP, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
|
||||
#if REST_API
|
||||
try {
|
||||
restClient.reset(new RestClient {port, ringFlags, persistent});
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "One does not simply initialize the rest client: " << ex.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (restClient)
|
||||
return restClient->event_loop();
|
||||
else
|
||||
return 1;
|
||||
#else
|
||||
// initialize client/library
|
||||
try {
|
||||
dbusClient.reset(new DBusClient {ringFlags, persistent});
|
||||
@ -197,11 +231,10 @@ main(int argc, char *argv [])
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO: Block signals for all threads but the main thread, decide how/if we should
|
||||
// handle other signals
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGHUP, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
if (dbusClient)
|
||||
return dbusClient->event_loop();
|
||||
else
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
return run();
|
||||
}
|
||||
|
26
bin/restcpp/Makefile.am
Normal file
26
bin/restcpp/Makefile.am
Normal file
@ -0,0 +1,26 @@
|
||||
include $(top_srcdir)/globals.mak
|
||||
|
||||
noinst_LTLIBRARIES = libclient_rest.la
|
||||
|
||||
libclient_rest_la_SOURCES = \
|
||||
restclient.cpp \
|
||||
restclient.h \
|
||||
restconfigurationmanager.cpp \
|
||||
restconfigurationmanager.h \
|
||||
restvideomanager.cpp \
|
||||
restvideomanager.h
|
||||
|
||||
libclient_rest_la_CXXFLAGS = \
|
||||
-std=c++14 \
|
||||
-g \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-reorder \
|
||||
-Wno-unused-variable \
|
||||
-Wno-unused-parameter \
|
||||
-pedantic \
|
||||
-I$(top_srcdir)/src
|
||||
|
||||
libclient_rest_la_LDFLAGS = \
|
||||
-lpthread \
|
||||
-lrestbed
|
174
bin/restcpp/restclient.cpp
Normal file
174
bin/restcpp/restclient.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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_)
|
||||
{
|
||||
DRing::pollEvents();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
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 callbakc using a lambda. In this case, this displays the incomming 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;
|
||||
|
||||
registerConfHandlers(configEvHandlers);
|
||||
|
||||
// Dummy callbacks are registered for the other managers
|
||||
registerCallHandlers(std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>>());
|
||||
registerPresHandlers(std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>>());
|
||||
#ifdef RING_VIDEO
|
||||
registerVideoHandlers(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 availables
|
||||
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);
|
||||
}
|
67
bin/restcpp/restclient.h
Normal file
67
bin/restcpp/restclient.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <restbed>
|
||||
|
||||
#include "dring/dring.h"
|
||||
#include "dring/callmanager_interface.h"
|
||||
#include "dring/configurationmanager_interface.h"
|
||||
#include "dring/presencemanager_interface.h"
|
||||
#ifdef RING_VIDEO
|
||||
#include "dring/videomanager_interface.h"
|
||||
#endif
|
||||
#include "logger.h"
|
||||
#include "restconfigurationmanager.h"
|
||||
#include "restvideomanager.h"
|
||||
|
||||
class RestClient {
|
||||
public:
|
||||
RestClient(int port, int flags, bool persistent);
|
||||
~RestClient();
|
||||
|
||||
int event_loop() noexcept;
|
||||
int exit() noexcept;
|
||||
|
||||
private:
|
||||
int initLib(int flags);
|
||||
void endLib() noexcept;
|
||||
void initResources();
|
||||
|
||||
bool pollNoMore_ = false;
|
||||
|
||||
std::unique_ptr<RestConfigurationManager> configurationManager_;
|
||||
std::unique_ptr<RestVideoManager> videoManager_;
|
||||
|
||||
// Restbed attributes
|
||||
restbed::Service service_;
|
||||
std::shared_ptr<restbed::Settings> settings_;
|
||||
std::thread restbed;
|
||||
};
|
1811
bin/restcpp/restconfigurationmanager.cpp
Normal file
1811
bin/restcpp/restconfigurationmanager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
148
bin/restcpp/restconfigurationmanager.h
Normal file
148
bin/restcpp/restconfigurationmanager.h
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <restbed>
|
||||
|
||||
#if __GNUC__ >= 5 || (__GNUC__ >=4 && __GNUC_MINOR__ >= 6)
|
||||
/* This warning option only exists for gcc 4.6.0 and greater. */
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
#endif
|
||||
|
||||
#include "dring/dring.h"
|
||||
#include "dring/callmanager_interface.h"
|
||||
#include "dring/configurationmanager_interface.h"
|
||||
#include "dring/presencemanager_interface.h"
|
||||
#ifdef RING_VIDEO
|
||||
#include "dring/videomanager_interface.h"
|
||||
#endif
|
||||
#include "logger.h"
|
||||
#include "im/message_engine.h"
|
||||
|
||||
#pragma GCC diagnostic warning "-Wignored-qualifiers"
|
||||
|
||||
#if __GNUC__ >= 5 || (__GNUC__ >=4 && __GNUC_MINOR__ >= 6)
|
||||
/* This warning option only exists for gcc 4.6.0 and greater. */
|
||||
#pragma GCC diagnostic warning "-Wunused-but-set-variable"
|
||||
#endif
|
||||
|
||||
class RestConfigurationManager
|
||||
{
|
||||
public:
|
||||
RestConfigurationManager();
|
||||
|
||||
std::vector<std::shared_ptr<restbed::Resource>> getResources();
|
||||
|
||||
private:
|
||||
// Attributes
|
||||
std::vector<std::shared_ptr<restbed::Resource>> resources_;
|
||||
|
||||
// Methods
|
||||
std::map<std::string, std::string> parsePost(const std::string& post);
|
||||
void populateResources();
|
||||
void defaultRoute(const std::shared_ptr<restbed::Session> session);
|
||||
|
||||
void getAccountDetails(const std::shared_ptr<restbed::Session> session);
|
||||
void getVolatileAccountDetails(const std::shared_ptr<restbed::Session> session);
|
||||
void setAccountDetails(const std::shared_ptr<restbed::Session> session);
|
||||
void setAccountActive(const std::shared_ptr<restbed::Session> session);
|
||||
void getAccountTemplate(const std::shared_ptr<restbed::Session> session);
|
||||
void addAccount(const std::shared_ptr<restbed::Session> session);
|
||||
void removeAccount(const std::shared_ptr<restbed::Session> session);
|
||||
void getAccountList(const std::shared_ptr<restbed::Session> session);
|
||||
void sendRegister(const std::shared_ptr<restbed::Session> session);
|
||||
void registerAllAccounts(const std::shared_ptr<restbed::Session> session);
|
||||
void sendTextMessage(const std::shared_ptr<restbed::Session> session);
|
||||
void getMessageStatus(const std::shared_ptr<restbed::Session> session);
|
||||
void getTlsDefaultSettings(const std::shared_ptr<restbed::Session> session);
|
||||
void getCodecList(const std::shared_ptr<restbed::Session> session);
|
||||
void getSupportedTlsMethod(const std::shared_ptr<restbed::Session> session);
|
||||
void getSupportedCiphers(const std::shared_ptr<restbed::Session> session);
|
||||
void getCodecDetails(const std::shared_ptr<restbed::Session> session);
|
||||
void setCodecDetails(const std::shared_ptr<restbed::Session> session);
|
||||
void getActiveCodecList(const std::shared_ptr<restbed::Session> session);
|
||||
void setActiveCodecList(const std::string& accountID, const std::vector<unsigned>& list); // /!\ not implemented
|
||||
void getAudioPluginList(const std::shared_ptr<restbed::Session> session);
|
||||
void setAudioPlugin(const std::shared_ptr<restbed::Session> session);
|
||||
void getAudioOutputDeviceList(const std::shared_ptr<restbed::Session> session);
|
||||
void setAudioOutputDevice(const std::shared_ptr<restbed::Session> session);
|
||||
void setAudioInputDevice(const std::shared_ptr<restbed::Session> session);
|
||||
void setAudioRingtoneDevice(const std::shared_ptr<restbed::Session> session);
|
||||
void getAudioInputDeviceList(const std::shared_ptr<restbed::Session> session);
|
||||
void getCurrentAudioDevicesIndex(const std::shared_ptr<restbed::Session> session);
|
||||
void getAudioInputDeviceIndex(const std::shared_ptr<restbed::Session> session);
|
||||
void getAudioOutputDeviceIndex(const std::shared_ptr<restbed::Session> session);
|
||||
void getCurrentAudioOutputPlugin(const std::shared_ptr<restbed::Session> session);
|
||||
void getNoiseSuppressState(const std::shared_ptr<restbed::Session> session);
|
||||
void setNoiseSuppressState(const std::shared_ptr<restbed::Session> session);
|
||||
void isAgcEnabled(const std::shared_ptr<restbed::Session> session);
|
||||
void setAgcState(const std::shared_ptr<restbed::Session> session);
|
||||
void muteDtmf(const std::shared_ptr<restbed::Session> session);
|
||||
void isDtmfMuted(const std::shared_ptr<restbed::Session> session);
|
||||
void isCaptureMuted(const std::shared_ptr<restbed::Session> session);
|
||||
void muteCapture(const std::shared_ptr<restbed::Session> session);
|
||||
void isPlaybackMuted(const std::shared_ptr<restbed::Session> session);
|
||||
void mutePlayback(const std::shared_ptr<restbed::Session> session);
|
||||
void isRingtoneMuted(const std::shared_ptr<restbed::Session> session);
|
||||
void muteRingtone(const std::shared_ptr<restbed::Session> session);
|
||||
void getAudioManager(const std::shared_ptr<restbed::Session> session);
|
||||
void setAudioManager(const std::shared_ptr<restbed::Session> session);
|
||||
void getSupportedAudioManagers(const std::shared_ptr<restbed::Session> session);
|
||||
void getRecordPath(const std::shared_ptr<restbed::Session> session);
|
||||
void setRecordPath(const std::shared_ptr<restbed::Session> session);
|
||||
void getIsAlwaysRecording(const std::shared_ptr<restbed::Session> session);
|
||||
void setIsAlwaysRecording(const std::shared_ptr<restbed::Session> session);
|
||||
void setHistoryLimit(const std::shared_ptr<restbed::Session> session);
|
||||
void getHistoryLimit(const std::shared_ptr<restbed::Session> session);
|
||||
void setAccountsOrder(const std::shared_ptr<restbed::Session> session);
|
||||
void getHookSettings(const std::shared_ptr<restbed::Session> session);
|
||||
void setHookSettings(const std::shared_ptr<restbed::Session> session);
|
||||
void getCredentials(const std::shared_ptr<restbed::Session> session);
|
||||
void setCredentials(const std::shared_ptr<restbed::Session> session);
|
||||
void getAddrFromInterfaceName(const std::shared_ptr<restbed::Session> session);
|
||||
void getAllIpInterface(const std::shared_ptr<restbed::Session> session);
|
||||
void getAllIpInterfaceByName(const std::shared_ptr<restbed::Session> session);
|
||||
void getShortcuts(const std::shared_ptr<restbed::Session> session);
|
||||
void setShortcuts(const std::shared_ptr<restbed::Session> session);
|
||||
void setVolume(const std::string& device, const double& value);
|
||||
void getVolume(const std::string& device);
|
||||
void validateCertificate(const std::string& accountId, const std::string& certificate);
|
||||
void validateCertificatePath(const std::string& accountId, const std::string& certificatePath, const std::string& privateKey, const std::string& privateKeyPass, const std::string& caList);
|
||||
void getCertificateDetails(const std::string& certificate);
|
||||
void getCertificateDetailsPath(const std::string& certificatePath, const std::string& privateKey, const std::string& privateKeyPass);
|
||||
void getPinnedCertificates();
|
||||
void pinCertificate(const std::vector<uint8_t>& certificate, const bool& local);
|
||||
void unpinCertificate(const std::string& certId);
|
||||
void pinCertificatePath(const std::string& path);
|
||||
void unpinCertificatePath(const std::string& path);
|
||||
void pinRemoteCertificate(const std::string& accountId, const std::string& certId);
|
||||
void setCertificateStatus(const std::string& account, const std::string& certId, const std::string& status);
|
||||
void getCertificatesByStatus(const std::string& account, const std::string& status);
|
||||
void getTrustRequests(const std::shared_ptr<restbed::Session> session);
|
||||
void acceptTrustRequest(const std::string& accountId, const std::string& from);
|
||||
void discardTrustRequest(const std::string& accountId, const std::string& from);
|
||||
void sendTrustRequest(const std::string& accountId, const std::string& to, const std::vector<uint8_t>& payload);
|
||||
void exportAccounts(const std::vector<std::string>& accountIDs, const std::string& filepath, const std::string& password);
|
||||
void importAccounts(const std::string& archivePath, const std::string& password);
|
||||
};
|
171
bin/restcpp/restvideomanager.cpp
Normal file
171
bin/restcpp/restvideomanager.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 "restvideomanager.h"
|
||||
#include "client/videomanager.h"
|
||||
|
||||
RestVideoManager::RestVideoManager() :
|
||||
resources_()
|
||||
{
|
||||
populateResources();
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<restbed::Resource>>
|
||||
RestVideoManager::getResources()
|
||||
{
|
||||
return resources_;
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
std::map<std::string, std::string>
|
||||
RestVideoManager::parsePost(const std::string& post)
|
||||
{
|
||||
std::map<std::string, std::string> data;
|
||||
|
||||
auto split = [](const std::string& s, char delim){
|
||||
std::vector<std::string> v;
|
||||
auto i = 0;
|
||||
auto pos = s.find(delim);
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
v.push_back(s.substr(i, pos-i));
|
||||
i = ++pos;
|
||||
pos = s.find(delim, pos);
|
||||
|
||||
if (pos == std::string::npos)
|
||||
v.push_back(s.substr(i, s.length()));
|
||||
}
|
||||
|
||||
return v;
|
||||
};
|
||||
|
||||
if(post.find_first_of('&') != std::string::npos)
|
||||
{
|
||||
std::vector<std::string> v = split(post, '&');
|
||||
|
||||
for(auto& it : v)
|
||||
{
|
||||
std::vector<std::string> tmp = split(it, '=');
|
||||
data[tmp.front()] = tmp.back();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string> tmp = split(post, '=');
|
||||
data[tmp.front()] = tmp.back();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
RestVideoManager::populateResources()
|
||||
{
|
||||
resources_.push_back(std::make_shared<restbed::Resource>());
|
||||
resources_.back()->set_path("/videoManager");
|
||||
resources_.back()->set_method_handler("GET",
|
||||
std::bind(&RestVideoManager::defaultRoute, this, std::placeholders::_1));
|
||||
|
||||
resources_.push_back(std::make_shared<restbed::Resource>());
|
||||
resources_.back()->set_path("/deviceList");
|
||||
resources_.back()->set_method_handler("GET",
|
||||
std::bind(&RestVideoManager::getDeviceList, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void
|
||||
RestVideoManager::defaultRoute(const std::shared_ptr<restbed::Session> session)
|
||||
{
|
||||
RING_INFO("[%s] GET /videoManager", session->get_origin().c_str());
|
||||
|
||||
std::string body = "Available routes are : \r\n";
|
||||
|
||||
const std::multimap<std::string, std::string> headers
|
||||
{
|
||||
{"Content-Type", "text/html"},
|
||||
{"Content-Length", std::to_string(body.length())}
|
||||
};
|
||||
|
||||
session->close(restbed::OK, body, headers);
|
||||
}
|
||||
|
||||
void RestVideoManager::getDeviceList(const std::shared_ptr<restbed::Session> session)
|
||||
{
|
||||
RING_INFO("[%s] GET /deviceList", session->get_origin().c_str());
|
||||
std::vector<std::string> list = DRing::getDeviceList();
|
||||
|
||||
std::string body = "";
|
||||
|
||||
for(auto& it : list)
|
||||
body += it + "\r\n";
|
||||
|
||||
const std::multimap<std::string, std::string> headers
|
||||
{
|
||||
{"Content-Type", "text/html"},
|
||||
{"Content-Length", std::to_string(body.length())}
|
||||
};
|
||||
|
||||
session->close(restbed::OK, body, headers);
|
||||
|
||||
}
|
||||
|
||||
void RestVideoManager::getCapabilities(const std::shared_ptr<restbed::Session> session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RestVideoManager::getSettings(const std::shared_ptr<restbed::Session> session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RestVideoManager::applySettings(const std::shared_ptr<restbed::Session> session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RestVideoManager::setDefaultDevice(const std::shared_ptr<restbed::Session> session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RestVideoManager::getDefaultDevice(const std::shared_ptr<restbed::Session> session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RestVideoManager::startCamera(const std::shared_ptr<restbed::Session> session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RestVideoManager::stopCamera(const std::shared_ptr<restbed::Session> session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RestVideoManager::switchInput(const std::shared_ptr<restbed::Session> session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RestVideoManager::hasCameraStarted(const std::shared_ptr<restbed::Session> session)
|
||||
{
|
||||
|
||||
}
|
72
bin/restcpp/restvideomanager.h
Normal file
72
bin/restcpp/restvideomanager.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <restbed>
|
||||
|
||||
#if __GNUC__ >= 5 || (__GNUC__ >=4 && __GNUC_MINOR__ >= 6)
|
||||
/* This warning option only exists for gcc 4.6.0 and greater. */
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
#endif
|
||||
|
||||
#include "dring/dring.h"
|
||||
#include "dring/callmanager_interface.h"
|
||||
#include "dring/configurationmanager_interface.h"
|
||||
#include "dring/presencemanager_interface.h"
|
||||
#ifdef RING_VIDEO
|
||||
#include "dring/videomanager_interface.h"
|
||||
#endif
|
||||
#include "logger.h"
|
||||
|
||||
#if __GNUC__ >= 5 || (__GNUC__ >=4 && __GNUC_MINOR__ >= 6)
|
||||
/* This warning option only exists for gcc 4.6.0 and greater. */
|
||||
#pragma GCC diagnostic warning "-Wunused-but-set-variable"
|
||||
#endif
|
||||
|
||||
class RestVideoManager
|
||||
{
|
||||
public:
|
||||
RestVideoManager();
|
||||
|
||||
std::vector<std::shared_ptr<restbed::Resource>> getResources();
|
||||
|
||||
private:
|
||||
// Attributes
|
||||
std::vector<std::shared_ptr<restbed::Resource>> resources_;
|
||||
|
||||
// Methods
|
||||
std::map<std::string, std::string> parsePost(const std::string& post);
|
||||
void populateResources();
|
||||
void defaultRoute(const std::shared_ptr<restbed::Session> session);
|
||||
|
||||
void getDeviceList(const std::shared_ptr<restbed::Session> session);
|
||||
void getCapabilities(const std::shared_ptr<restbed::Session> session);
|
||||
void getSettings(const std::shared_ptr<restbed::Session> session);
|
||||
void applySettings(const std::shared_ptr<restbed::Session> session);
|
||||
void setDefaultDevice(const std::shared_ptr<restbed::Session> session);
|
||||
void getDefaultDevice(const std::shared_ptr<restbed::Session> session);
|
||||
void startCamera(const std::shared_ptr<restbed::Session> session);
|
||||
void stopCamera(const std::shared_ptr<restbed::Session> session);
|
||||
void switchInput(const std::shared_ptr<restbed::Session> session);
|
||||
void hasCameraStarted(const std::shared_ptr<restbed::Session> session);
|
||||
};
|
24
configure.ac
24
configure.ac
@ -286,12 +286,12 @@ if test "${SYS}" = "linux"; then
|
||||
dnl Check for alsa development package - name: libasound2-dev
|
||||
ALSA_MIN_VERSION=1.0
|
||||
AC_ARG_WITH([alsa],
|
||||
[AS_HELP_STRING([--without-alsa], [disable support for alsa])],
|
||||
[],
|
||||
[with_alsa=yes])
|
||||
[AS_HELP_STRING([--without-alsa], [disable support for alsa])],
|
||||
[],
|
||||
[with_alsa=yes])
|
||||
AS_IF([test "x$with_alsa" = "xyes"], [
|
||||
PKG_CHECK_MODULES(ALSA, alsa >= ${ALSA_MIN_VERSION},, AC_MSG_ERROR([Missing alsa development files]))
|
||||
]);
|
||||
]);
|
||||
|
||||
AC_DEFINE_UNQUOTED([HAVE_ALSA], `if test "x$with_alsa" = "xyes"; then echo 1; else echo 0; fi`, [Define if you have alsa])
|
||||
fi
|
||||
@ -386,6 +386,20 @@ AS_IF([test "x$with_dbus" = "xyes"], [
|
||||
AM_CONDITIONAL(RING_DBUS, true)],
|
||||
AM_CONDITIONAL(RING_DBUS, false));
|
||||
|
||||
# Rest C++ with restbed
|
||||
AC_ARG_WITH([restcpp],
|
||||
AS_HELP_STRING([--with-restcpp], [enable rest support with C++]))
|
||||
|
||||
AS_IF([test "x$with_restcpp" = "xyes"], [
|
||||
PKG_CHECK_MODULES(RESTBED, librestbed,, AC_MSG_WARN([Missing restbed files]))
|
||||
|
||||
AS_AC_EXPAND(SBINDIR, $sbindir)
|
||||
AC_SUBST(SBINDIR)
|
||||
|
||||
AC_CONFIG_FILES([bin/restcpp/Makefile])
|
||||
|
||||
AM_CONDITIONAL(RING_RESTCPP, true)],
|
||||
AM_CONDITIONAL(RING_RESTCPP, false));
|
||||
|
||||
dnl Check for libav
|
||||
PKG_CHECK_MODULES(LIBAVCODEC, libavcodec >= 53.5.0,, AC_MSG_ERROR([Missing libavcodec development files]))
|
||||
@ -548,7 +562,7 @@ AS_IF([test "x$with_natpmp" != xno],
|
||||
AC_DEFINE_UNQUOTED([HAVE_LIBNATPMP], `if test "x$with_natpmp" != xno; then echo 1; else echo 0; fi`, [Define if you have libnatpmp])
|
||||
|
||||
AC_DEFINE_UNQUOTED([HAVE_SHM], `if test -z "${HAVE_LINUX_TRUE}" && test -z "${HAVE_ANDROID_FALSE}" ; then echo 1; else echo 0; fi`,
|
||||
[Define if you have shared memory support])
|
||||
[Define if you have shared memory support])
|
||||
|
||||
# DOXYGEN
|
||||
# required dependency(ies): doxygen
|
||||
|
10
contrib/src/restbed/CMakeLists.patch
Normal file
10
contrib/src/restbed/CMakeLists.patch
Normal file
@ -0,0 +1,10 @@
|
||||
--- CMakeLists.txt 2016-06-13 12:01:30.415787179 -0400
|
||||
+++ CMakeLists.txt 2016-06-13 12:01:33.329120391 -0400
|
||||
@@ -71,5 +71,5 @@
|
||||
install( FILES "${INCLUDE_DIR}/${PROJECT_NAME}" DESTINATION "include" )
|
||||
install( FILES ${BUILD_ARTIFACTS} DESTINATION "include/corvusoft/${PROJECT_NAME}" )
|
||||
install( TARGETS ${PROJECT_NAME}
|
||||
- LIBRARY DESTINATION "library"
|
||||
- ARCHIVE DESTINATION "library" COMPONENT library )
|
||||
+ LIBRARY DESTINATION "lib"
|
||||
+ ARCHIVE DESTINATION "lib" COMPONENT library )
|
29
contrib/src/restbed/conditional_sslv3.patch
Normal file
29
contrib/src/restbed/conditional_sslv3.patch
Normal file
@ -0,0 +1,29 @@
|
||||
Description: Conditionalize SSLv3 support for OpenSSL
|
||||
Author: Markus Wanner <markus@bluegap.ch>
|
||||
Forwarded: no
|
||||
|
||||
--- a/include/asio/ssl/impl/context.ipp
|
||||
+++ b/include/asio/ssl/impl/context.ipp
|
||||
@@ -88,6 +88,14 @@
|
||||
handle_ = ::SSL_CTX_new(::SSLv2_server_method());
|
||||
break;
|
||||
#endif // defined(OPENSSL_NO_SSL2)
|
||||
+#if defined(OPENSSL_NO_SSL3)
|
||||
+ case context::sslv3:
|
||||
+ case context::sslv3_client:
|
||||
+ case context::sslv3_server:
|
||||
+ asio::detail::throw_error(
|
||||
+ asio::error::invalid_argument, "context");
|
||||
+ break;
|
||||
+#else // defined(OPENSSL_NO_SSL3)
|
||||
case context::sslv3:
|
||||
handle_ = ::SSL_CTX_new(::SSLv3_method());
|
||||
break;
|
||||
@@ -97,6 +105,7 @@
|
||||
case context::sslv3_server:
|
||||
handle_ = ::SSL_CTX_new(::SSLv3_server_method());
|
||||
break;
|
||||
+#endif
|
||||
case context::tlsv1:
|
||||
handle_ = ::SSL_CTX_new(::TLSv1_method());
|
||||
break;
|
49
contrib/src/restbed/rules.mak
Normal file
49
contrib/src/restbed/rules.mak
Normal file
@ -0,0 +1,49 @@
|
||||
#
|
||||
# Copyright (C) 2016 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.
|
||||
#
|
||||
|
||||
RESTBED_VERSION := 4.0
|
||||
RESTBED_URL := https://github.com/Corvusoft/restbed/archive/$(RESTBED_VERSION).tar.gz
|
||||
|
||||
ifeq ($(call need_pkg,"restbed >= 4.0"),)
|
||||
PKGS_FOUND += restbed
|
||||
endif
|
||||
|
||||
$(TARBALLS)/restbed-$(RESTBED_VERSION).tar.gz:
|
||||
$(call download,$(RESTBED_URL))
|
||||
|
||||
RESTBED_CONF = -DBUILD_TESTS=NO \
|
||||
-DBUILD_EXAMPLES=NO \
|
||||
-DBUILD_SSL=NO \
|
||||
-DBUILD_SHARED=NO \
|
||||
-DCMAKE_C_COMPILER=gcc \
|
||||
-DCMAKE_CXX_COMPILER=g++ \
|
||||
-DCMAKE_INSTALL_PREFIX=$(PREFIX)
|
||||
|
||||
restbed: restbed-$(RESTBED_VERSION).tar.gz
|
||||
$(UNPACK)
|
||||
git clone https://github.com/Corvusoft/asio-dependency.git $(UNPACK_DIR)/dependency/asio/
|
||||
cd $(UNPACK_DIR)/dependency/asio/asio && patch -fp1 < ../../../../../src/restbed/conditional_sslv3.patch
|
||||
cd $(UNPACK_DIR)/ && ls && patch -p0 < ../../src/restbed/CMakeLists.patch
|
||||
$(MOVE)
|
||||
|
||||
.restbed: restbed
|
||||
cd $< && cmake $(RESTBED_CONF) .
|
||||
cd $< && $(MAKE) install
|
||||
touch $@
|
Reference in New Issue
Block a user