Port to websocketpp Web server, Ubuntu LV2 headers.

This commit is contained in:
Robin Davies
2021-09-05 03:58:10 -04:00
parent ad8fcb34c7
commit a667e4d8fb
19 changed files with 2101 additions and 1353 deletions
-5
View File
@@ -7,8 +7,3 @@ cd build
cmake .. cmake ..
cd .. cd ..
# Install react dependencies
cd react
npm install
cd ..
Executable
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/bash
# Install react dependencies
cd react
npm install
cd ..
+14 -32
View File
@@ -6449,11 +6449,11 @@
} }
}, },
"ext": { "ext": {
"version": "1.4.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", "resolved": "https://registry.npmjs.org/ext/-/ext-1.5.0.tgz",
"integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", "integrity": "sha512-+ONcYoWj/SoQwUofMr94aGu05Ou4FepKi7N7b+O8T4jVfyIsZQV1/xeS8jpaBzF0csAk0KLXoHCxU7cKYZjo1Q==",
"requires": { "requires": {
"type": "^2.0.0" "type": "^2.5.0"
}, },
"dependencies": { "dependencies": {
"type": { "type": {
@@ -13007,9 +13007,9 @@
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
}, },
"resolve-url-loader": { "resolve-url-loader": {
"version": "3.1.3", "version": "3.1.4",
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.3.tgz", "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.4.tgz",
"integrity": "sha512-WbDSNFiKPPLem1ln+EVTE+bFUBdTTytfQZWbmghroaFNFaAVmGq0Saqw6F/306CwgPXsGwXVxbODE+3xAo/YbA==", "integrity": "sha512-D3sQ04o0eeQEySLrcz4DsX3saHfsr8/N6tfhblxgZKXxMT2Louargg12oGNfoTRLV09GXhVUe5/qgA5vdgNigg==",
"requires": { "requires": {
"adjust-sourcemap-loader": "3.0.0", "adjust-sourcemap-loader": "3.0.0",
"camelcase": "5.3.1", "camelcase": "5.3.1",
@@ -13017,7 +13017,7 @@
"convert-source-map": "1.7.0", "convert-source-map": "1.7.0",
"es6-iterator": "2.0.3", "es6-iterator": "2.0.3",
"loader-utils": "1.2.3", "loader-utils": "1.2.3",
"postcss": "7.0.21", "postcss": "7.0.36",
"rework": "1.0.1", "rework": "1.0.1",
"rework-visit": "1.0.0", "rework-visit": "1.0.0",
"source-map": "0.6.1" "source-map": "0.6.1"
@@ -13059,28 +13059,10 @@
"json5": "^1.0.1" "json5": "^1.0.1"
} }
}, },
"postcss": {
"version": "7.0.21",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz",
"integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==",
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
}
},
"source-map": { "source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"requires": {
"has-flag": "^3.0.0"
}
} }
} }
}, },
@@ -14369,9 +14351,9 @@
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA=="
}, },
"tar": { "tar": {
"version": "6.1.0", "version": "6.1.11",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
"integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==",
"requires": { "requires": {
"chownr": "^2.0.0", "chownr": "^2.0.0",
"fs-minipass": "^2.0.0", "fs-minipass": "^2.0.0",
@@ -14961,9 +14943,9 @@
} }
}, },
"url-parse": { "url-parse": {
"version": "1.5.1", "version": "1.5.3",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz",
"integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==",
"requires": { "requires": {
"querystringify": "^2.1.1", "querystringify": "^2.1.1",
"requires-port": "^1.0.0" "requires-port": "^1.0.0"
+447 -1093
View File
File diff suppressed because it is too large Load Diff
+79 -87
View File
@@ -1,7 +1,10 @@
#pragma once #pragma once
#include <string.h>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/beast/http.hpp>
#include <boost/asio/ip/network_v4.hpp> #include <boost/asio/ip/network_v4.hpp>
#include <cstring>
#include <mutex> #include <mutex>
@@ -11,17 +14,63 @@
#include <filesystem> #include <filesystem>
// forward declaration. // forward declaration.
class websocket_session; class websocket_session;
namespace pipedal { namespace pipedal {
using HttpRequest =boost::beast::http::request<boost::beast::http::string_body>;
class HttpRequest {
public:
virtual const std::string&body() const = 0;
virtual const std::string &method() const = 0;
virtual const std::string&get(const std::string&key) const = 0;
virtual bool keepAlive() const = 0;
};
class HttpResponse {
public:
virtual void set(const std::string&key, const std::string&value) = 0;
virtual void setContentLength(size_t size) = 0;
virtual void setBody(const std::string&body) = 0;
virtual void keepAlive(bool value) = 0;
};
struct HttpVerb {
constexpr static const char * options = "OPTIONS";
constexpr static const char * get = "GET";
constexpr static const char * post = "POST";
constexpr static const char * head = "HEAD";
};
class HttpField {
public:
constexpr static const char * LastModified = "Last-Modified";
constexpr static const char* content_length = "Content-Length";
constexpr static const char* content_type = "Content-Type";
constexpr static const char* cache_control = "Cache-Control";
constexpr static const char* content_disposition = "Content-Disposition";
constexpr static const char* access_control_allow_origin = "Access-Control-Allow-Origin";
constexpr static const char* access_control_allow_methods= "Access-Control-Allow-Methods";
constexpr static const char* access_control_allow_headers = "Acess-Control-Allow-Headers";
constexpr static const char* origin = "Origin";
constexpr static const char* date = "Date";
};
//xxx move this to HtmlHelpers.
std::string last_modified(const std::filesystem::path& path); std::string last_modified(const std::filesystem::path& path);
class BeastServerImpl;
class SocketHandler { class SocketHandler {
friend class BeastServerImpl;
public: public:
class IWriteCallback { class IWriteCallback {
@@ -33,16 +82,15 @@ public:
}; };
private: private:
friend class ::websocket_session;
IWriteCallback *writeCallback_; IWriteCallback *writeCallback_;
public:
void setWriteCallback(IWriteCallback *writeCallback) { void setWriteCallback(IWriteCallback *writeCallback) {
writeCallback_ = writeCallback; writeCallback_ = writeCallback;
} }
protected: public:
virtual void onReceive(const std::string_view&text) = 0; virtual void onReceive(const std::string_view&text) = 0;
public: public:
std::string getFromAddress() const { return writeCallback_->getFromAddress(); } std::string getFromAddress() const { return writeCallback_->getFromAddress(); }
@@ -76,6 +124,7 @@ class RequestHandler {
private: private:
uri target_url_; uri target_url_;
public: public:
RequestHandler(const char*target_url) RequestHandler(const char*target_url)
: target_url_(target_url) : target_url_(target_url)
{ {
@@ -92,7 +141,7 @@ public:
return requestUri; return requestUri;
} }
virtual bool wants(boost::beast::http::verb verb,const uri &request_uri) const { virtual bool wants(const std::string& method,const uri &request_uri) const {
if (request_uri.segment_count() < target_url_.segment_count()) if (request_uri.segment_count() < target_url_.segment_count())
{ {
return false; return false;
@@ -107,105 +156,48 @@ public:
return true; return true;
} }
virtual void head_response( virtual void head_response(
const uri&request_uri, const uri&request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req, const HttpRequest &req,
boost::beast::http::response<boost::beast::http::empty_body> &res, HttpResponse &res,
boost::beast::error_code &ec) = 0; std::error_code &ec) = 0;
virtual void get_response( virtual void get_response(
const uri&request_uri, const uri&request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req, const HttpRequest &req,
boost::beast::http::response<boost::beast::http::string_body> &res, HttpResponse &res,
boost::beast::error_code &ec) = 0; std::error_code &ec) = 0;
virtual void post_response( virtual void post_response(
const uri&request_uri, const uri&request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req, const HttpRequest &req,
boost::beast::http::response<boost::beast::http::string_body> &res, HttpResponse &res,
boost::beast::error_code &ec) std::error_code &ec)
{ {
get_response(request_uri,req,res,ec); get_response(request_uri,req,res,ec);
} }
}; };
class BeastServer { class BeastServer {
private:
boost::asio::ip::address address;
unsigned short port;
std::string doc_root;
int threads;
std::mutex log_mutex;
std::vector<std::shared_ptr<RequestHandler> > request_handlers;
std::vector<std::shared_ptr<ISocketFactory> > socket_factories;
std::mutex io_mutex;
boost::asio::io_context *pIoContext = nullptr;
void*pListener = nullptr;
std::thread*pBgThread = nullptr;
bool logHttpRequests = false;
bool hasAccessPointGateway = false;
boost::asio::ip::network_v4 accessPointGateway;
std::string accessPointServerAddress;
bool stopping = false;
public: public:
virtual ~BeastServer() { }
BeastServer( virtual void SetLogHttpRequests(bool enableLogging) = 0;
const boost::asio::ip::address& address,
int port,
const char*rootPath,
int threads = 10);
void Run(); virtual void AddRequestHandler(std::shared_ptr<RequestHandler> requestHandler) = 0;
void RunInBackground(); virtual void AddSocketFactory(std::shared_ptr<ISocketFactory> &socketHandler) = 0;
bool Stopping() const { return this->stopping; }
void Stop();
void Join();
void SetLogHttpRequests(bool logRequests) { this->logHttpRequests = logRequests; } virtual void ShutDown(int timeoutMs) = 0;
bool LogHttpRequests() const { return this->logHttpRequests; } virtual void Join() = 0;
boost::asio::io_context& IoContext() {
return *pIoContext;
}
void AddRequestHandler(std::shared_ptr<RequestHandler> requestHandler) virtual void RunInBackground() = 0;
{
request_handlers.push_back(requestHandler);
}
void AddSocketFactory(const std::shared_ptr<ISocketFactory> &socketHandler)
{
socket_factories.push_back(socketHandler);
}
std::vector<std::shared_ptr<RequestHandler> > &RequestHandlers() { return request_handlers; }
const std::string&GetDocRoot() { return doc_root; }
virtual ~BeastServer();
std::shared_ptr<ISocketFactory> GetSocketFactory(const uri &request_uri);
void SetAccessPointGateway(const boost::asio::ip::network_v4 &gateway, const std::string&accessPointServerAddress)
{
this->accessPointGateway = gateway;
this->hasAccessPointGateway = true;
this->accessPointServerAddress = accessPointServerAddress;
}
bool HasAccessPointGateway() const { return hasAccessPointGateway; }
boost::asio::ip::network_v4 &GetAccessPointGateway() { return this->accessPointGateway; }
const std::string & GetAccessPointServerAddress() const { return this->accessPointServerAddress; }
public:
virtual void onError(boost::system::error_code ec, char const* what);
virtual void onWarning(boost::system::error_code ec, char const* what);
virtual void onInfo(char const* what);
virtual void onListenerClosed();
}; };
std::shared_ptr<BeastServer> createBeastServer(const boost::asio::ip::address &address, int port, const char *rootPath, int threads);
} // namespace pipedal; } // namespace pipedal;
@@ -22,20 +22,21 @@
#include "BeastServer.hpp" #include "BeastServer.hpp"
using namespace piddle; using namespace pipedal;
TEST_CASE( "BeastServer shutodwn", "[beastServerShutdown]" ) { TEST_CASE( "BeastServer shutdown", "[beastServerShutdown]" ) {
auto const address = boost::asio::ip::make_address("0.0.0.0"); auto const address = boost::asio::ip::make_address("0.0.0.0");
auto const port = 8081; auto const port = 8081;
std::string doc_root = "/bad"; std::string doc_root = ".";
auto const threads = 3; auto const threads = 3;
auto server = std::make_shared<BeastServer>( auto server = createBeastServer(
address,port,doc_root.c_str(),threads); address,port,doc_root.c_str(),threads);
server->RunInBackground(); server->RunInBackground();
sleep(3); sleep(30000);
server->Stop(); server->ShutDown(1000);
sleep(1);
server->Join(); server->Join();
} }
File diff suppressed because it is too large Load Diff
+217
View File
@@ -0,0 +1,217 @@
#pragma once
// avoid breaking changes from 1.64 to.71
// Note that raspbian only prvides 1.64; ubuntu studio only provides 1.71
#define BOOST_BEAST_ALLOW_DEPRECATED
#include <boost/asio/ip/tcp.hpp>
#include <boost/beast/http.hpp>
#include <boost/asio/ip/network_v4.hpp>
#include <mutex>
#include <thread>
#include "Uri.hpp"
#include <string_view>
#include <filesystem>
// forward declaration.
class websocket_session;
namespace pipedal {
using HttpRequest =boost::beast::http::request<boost::beast::http::string_body>;
std::string last_modified(const std::filesystem::path& path);
class SocketHandler {
public:
class IWriteCallback {
public:
virtual void close() = 0;
virtual void writeCallback(const std::string& text) = 0;
virtual std::string getFromAddress() const = 0;
};
private:
friend class ::websocket_session;
IWriteCallback *writeCallback_;
void setWriteCallback(IWriteCallback *writeCallback) {
writeCallback_ = writeCallback;
}
protected:
virtual void onReceive(const std::string_view&text) = 0;
public:
std::string getFromAddress() const { return writeCallback_->getFromAddress(); }
void receive(const std::string_view&text) {
onReceive(text);
}
void send(const std::string &text) {
if (writeCallback_ != nullptr)
{
writeCallback_->writeCallback(text);
}
}
virtual void Close()
{
writeCallback_->close();
}
virtual ~SocketHandler() = default;
virtual void onAttach() { }
};
class ISocketFactory {
public:
virtual bool wants(const uri &request) = 0;
virtual std::shared_ptr<SocketHandler> CreateHandler(const uri& request) = 0;
};
class RequestHandler {
private:
uri target_url_;
public:
RequestHandler(const char*target_url)
: target_url_(target_url)
{
}
~RequestHandler() = default;
virtual bool wantsRedirect(const uri& requestUri)
{
return false;
}
uri GetRedirect(const uri& requestUri)
{
return requestUri;
}
virtual bool wants(boost::beast::http::verb verb,const uri &request_uri) const {
if (request_uri.segment_count() < target_url_.segment_count())
{
return false;
}
for (int i = 0; i < target_url_.segment_count(); ++i)
{
if (request_uri.segment(i) != target_url_.segment(i))
{
return false;
}
}
return true;
}
virtual void head_response(
const uri&request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req,
boost::beast::http::response<boost::beast::http::empty_body> &res,
boost::beast::error_code &ec) = 0;
virtual void get_response(
const uri&request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req,
boost::beast::http::response<boost::beast::http::string_body> &res,
boost::beast::error_code &ec) = 0;
virtual void post_response(
const uri&request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req,
boost::beast::http::response<boost::beast::http::string_body> &res,
boost::beast::error_code &ec)
{
get_response(request_uri,req,res,ec);
}
};
class BeastServer {
private:
boost::asio::ip::address address;
unsigned short port;
std::string doc_root;
int threads;
std::mutex log_mutex;
std::vector<std::shared_ptr<RequestHandler> > request_handlers;
std::vector<std::shared_ptr<ISocketFactory> > socket_factories;
std::mutex io_mutex;
boost::asio::io_context *pIoContext = nullptr;
void*pListener = nullptr;
std::thread*pBgThread = nullptr;
bool logHttpRequests = false;
bool hasAccessPointGateway = false;
boost::asio::ip::network_v4 accessPointGateway;
std::string accessPointServerAddress;
bool stopping = false;
public:
BeastServer(
const boost::asio::ip::address& address,
int port,
const char*rootPath,
int threads = 10);
void Run();
void RunInBackground();
bool Stopping() const { return this->stopping; }
void Stop();
void Join();
void SetLogHttpRequests(bool logRequests) { this->logHttpRequests = logRequests; }
bool LogHttpRequests() const { return this->logHttpRequests; }
boost::asio::io_context& IoContext() {
return *pIoContext;
}
void AddRequestHandler(std::shared_ptr<RequestHandler> requestHandler)
{
request_handlers.push_back(requestHandler);
}
void AddSocketFactory(const std::shared_ptr<ISocketFactory> &socketHandler)
{
socket_factories.push_back(socketHandler);
}
std::vector<std::shared_ptr<RequestHandler> > &RequestHandlers() { return request_handlers; }
const std::string&GetDocRoot() { return doc_root; }
virtual ~BeastServer();
std::shared_ptr<ISocketFactory> GetSocketFactory(const uri &request_uri);
void SetAccessPointGateway(const boost::asio::ip::network_v4 &gateway, const std::string&accessPointServerAddress)
{
this->accessPointGateway = gateway;
this->hasAccessPointGateway = true;
this->accessPointServerAddress = accessPointServerAddress;
}
bool HasAccessPointGateway() const { return hasAccessPointGateway; }
boost::asio::ip::network_v4 &GetAccessPointGateway() { return this->accessPointGateway; }
const std::string & GetAccessPointServerAddress() const { return this->accessPointServerAddress; }
public:
virtual void onError(boost::system::error_code ec, char const* what);
virtual void onWarning(boost::system::error_code ec, char const* what);
virtual void onInfo(char const* what);
virtual void onListenerClosed();
};
} // namespace pipedal;
+11 -1
View File
@@ -149,6 +149,7 @@ add_executable(pipedaltest ${PIPEDAL_SOURCES} testMain.cpp
SystemConfigFile.hpp SystemConfigFile.cpp SystemConfigFile.hpp SystemConfigFile.cpp
SystemConfigFileTest.cpp SystemConfigFileTest.cpp
BeastServerTest.cpp
) )
configure_file(config.hpp.in config.hpp) configure_file(config.hpp.in config.hpp)
@@ -211,12 +212,21 @@ set (REACT_NOTICES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../build/src/notices.txt)
set (DEBIAN_COPYRIGHT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../debian/copyright) set (DEBIAN_COPYRIGHT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../debian/copyright)
# generate Copyright section of settings page. # generate Copyright section of settings page.
# warning: there may be multiple versions. Pick the latest.
if(EXISTS "/usr/share/doc/libboost1.71-dev")
set (BOOST_COPYRIGHT_DIR "libboost1.71-dev")
elseif(EXISTS "/usr/share/doc/libboost1.67-dev")
set (BOOST_COPYRIGHT_DIR "libboost1.67-dev")
else()
message(ERROR "Boost libary version has changed. Please update me.")
endif()
add_custom_command(OUTPUT ${REACT_NOTICES_FILE} add_custom_command(OUTPUT ${REACT_NOTICES_FILE}
COMMAND "$<TARGET_FILE:processcopyrights>" COMMAND "$<TARGET_FILE:processcopyrights>"
--output ${REACT_NOTICES_FILE} --output ${REACT_NOTICES_FILE}
--projectCopyright ${DEBIAN_COPYRIGHT_FILE} --projectCopyright ${DEBIAN_COPYRIGHT_FILE}
liblilv-0-0 libboost1.67-dev libnl-3-dev libnl-3-dev lv2-dev liblilv-0-0 ${BOOST_COPYRIGHT_DIR} libnl-3-dev libnl-3-dev lv2-dev
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${DEBIAN_COPYRIGHT_FILE} "$<TARGET_FILE:processcopyrights>" DEPENDS ${DEBIAN_COPYRIGHT_FILE} "$<TARGET_FILE:processcopyrights>"
COMMENT "Updating copyright notices." COMMENT "Updating copyright notices."
+1 -3
View File
@@ -19,12 +19,10 @@
#pragma once #pragma once
#include "lv2/lv2core.lv2/lv2.h" #include "lv2.h"
#include "lv2/atom.lv2/atom.h" #include "lv2/atom.lv2/atom.h"
#include "lv2/atom.lv2/util.h" #include "lv2/atom.lv2/util.h"
#include "lv2/lv2core.lv2/lv2.h"
#include "lv2/log.lv2/log.h"
#include "lv2/log.lv2/logger.h" #include "lv2/log.lv2/logger.h"
#include "lv2/midi.lv2/midi.h" #include "lv2/midi.lv2/midi.h"
#include "lv2/urid.lv2/urid.h" #include "lv2/urid.lv2/urid.h"
+1 -1
View File
@@ -24,7 +24,7 @@
#include <lilv/lilv.h> #include <lilv/lilv.h>
#include "lv2/atom.lv2/atom.h" #include "lv2/atom.lv2/atom.h"
#include "lv2/atom.lv2/util.h" #include "lv2/atom.lv2/util.h"
#include "lv2/lv2core.lv2/lv2.h" #include "lv2.h"
#include "lv2/log.lv2/log.h" #include "lv2/log.lv2/log.h"
#include "lv2/log.lv2/logger.h" #include "lv2/log.lv2/logger.h"
#include "lv2/midi.lv2/midi.h" #include "lv2/midi.lv2/midi.h"
+1 -1
View File
@@ -41,7 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <stdint.h> #include <stdint.h>
#include <cassert> #include <cassert>
#include <lv2/lv2core.lv2/lv2.h> #include <lv2.h>
#include <lv2/atom.lv2/atom.h> #include <lv2/atom.lv2/atom.h>
#include <lv2/midi.lv2/midi.h> #include <lv2/midi.lv2/midi.h>
#include <lv2/urid.lv2/urid.h> #include <lv2/urid.lv2/urid.h>
+1 -1
View File
@@ -31,7 +31,7 @@
#include "OptionsFeature.hpp" #include "OptionsFeature.hpp"
#include "JackConfiguration.hpp" #include "JackConfiguration.hpp"
#include "lv2/urid.lv2/urid.h" #include "lv2/urid.lv2/urid.h"
#include "lv2/lv2core.lv2/lv2.h" #include "lv2.h"
#include "lv2/atom.lv2/atom.h" #include "lv2/atom.lv2/atom.h"
#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h" #include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
#include "lv2/lv2plug.in/ns/ext/presets/presets.h" #include "lv2/lv2plug.in/ns/ext/presets/presets.h"
+1 -1
View File
@@ -31,7 +31,7 @@
#include <filesystem> #include <filesystem>
#include <cmath> #include <cmath>
#include "lv2/lv2core.lv2/lv2.h" #include "lv2.h"
#include "Units.hpp" #include "Units.hpp"
-1
View File
@@ -21,7 +21,6 @@
#include "lv2.h" #include "lv2.h"
#include "lv2/lv2core.lv2/lv2.h"
#include "lv2/log.lv2/log.h" #include "lv2/log.lv2/log.h"
#include "lv2/log.lv2/logger.h" #include "lv2/log.lv2/logger.h"
#include "lv2/midi.lv2/midi.h" #include "lv2/midi.lv2/midi.h"
+7 -6
View File
@@ -125,13 +125,11 @@ private:
std::string response; std::string response;
public: public:
template <typename T> // either execution_context (boost 1.74) or io_context (boost 1.63) Reader(asio::io_service &ios)
Reader(T &ios)
: socket(ios) : socket(ios)
{ {
} }
template <typename T> // either execution_context (boost 1.74) or io_context (boost 1.63) static std::shared_ptr<Reader> Create(asio::io_service &ios)
static std::shared_ptr<Reader> Create(T &ios)
{ {
return std::make_shared<Reader>(ios); return std::make_shared<Reader>(ios);
} }
@@ -290,6 +288,7 @@ class Server
{ {
private: private:
tcp::acceptor acceptor_; tcp::acceptor acceptor_;
boost::asio::io_service &io_service;
void HandleAccept(std::shared_ptr<Reader> connection, const boost::system::error_code &err) void HandleAccept(std::shared_ptr<Reader> connection, const boost::system::error_code &err)
{ {
@@ -303,7 +302,7 @@ private:
void StartAccept() void StartAccept()
{ {
// socket // socket
std::shared_ptr<Reader> reader = Reader::Create(acceptor_.get_executor().context()); std::shared_ptr<Reader> reader = Reader::Create(io_service);
// asynchronous accept operation and wait for a new connection. // asynchronous accept operation and wait for a new connection.
acceptor_.async_accept(reader->Socket(), acceptor_.async_accept(reader->Socket(),
@@ -314,7 +313,9 @@ private:
public: public:
//constructor for accepting connection from client //constructor for accepting connection from client
Server(boost::asio::io_service &io_service, const tcp::endpoint &endpoint) Server(boost::asio::io_service &io_service, const tcp::endpoint &endpoint)
: acceptor_(io_service, endpoint) : acceptor_(io_service, endpoint),
io_service(io_service)
{ {
StartAccept(); StartAccept();
} }
+3 -1
View File
@@ -29,8 +29,11 @@
using namespace pipedal; using namespace pipedal;
using namespace std; using namespace std;
#pragma GCC diagnostic ignored "-Wunused-result"
// find on path, but ONLY /usr/bin and /usr/sbin // find on path, but ONLY /usr/bin and /usr/sbin
static std::filesystem::path findOnSystemPath(const std::string &command) static std::filesystem::path findOnSystemPath(const std::string &command)
{ {
if (command.length() != 0 && command[0] == '/') if (command.length() != 0 && command[0] == '/')
@@ -76,7 +79,6 @@ void pipedal::SilentSysExec(const char *szCommand)
pclose(output); pclose(output);
} }
} }
int pipedal::SysExec(const char *szCommand) int pipedal::SysExec(const char *szCommand)
{ {
char *args = strdup(szCommand); char *args = strdup(szCommand);
+2 -2
View File
@@ -21,11 +21,11 @@
#pragma once #pragma once
#include <lilv/lilv.h> #include <lilv/lilv.h>
#include "lv2/lv2core.lv2/lv2.h" #include "lv2.h"
#include "lv2/atom.lv2/atom.h" #include "lv2/atom.lv2/atom.h"
#include "lv2/atom.lv2/util.h" #include "lv2/atom.lv2/util.h"
#include "lv2/lv2core.lv2/lv2.h" #include "lv2.h"
#include "lv2/log.lv2/log.h" #include "lv2/log.lv2/log.h"
#include "lv2/log.lv2/logger.h" #include "lv2/log.lv2/logger.h"
#include "lv2/midi.lv2/midi.h" #include "lv2/midi.lv2/midi.h"
+56 -112
View File
@@ -40,7 +40,6 @@
#include <systemd/sd-daemon.h> #include <systemd/sd-daemon.h>
using namespace pipedal; using namespace pipedal;
using namespace boost::beast;
#define PRESET_EXTENSION ".piPreset" #define PRESET_EXTENSION ".piPreset"
#define BANK_EXTENSION ".piBank" #define BANK_EXTENSION ".piBank"
@@ -83,7 +82,7 @@ public:
{ {
} }
virtual bool wants(boost::beast::http::verb verb, const uri &request_uri) const virtual bool wants(const std::string& method, const uri &request_uri) const
{ {
if (request_uri.segment_count() != 2 || request_uri.segment(0) != "var") if (request_uri.segment_count() != 2 || request_uri.segment(0) != "var")
{ {
@@ -156,9 +155,9 @@ public:
virtual void head_response( virtual void head_response(
const uri &request_uri, const uri &request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req, const HttpRequest &req,
boost::beast::http::response<boost::beast::http::empty_body> &res, HttpResponse &res,
boost::beast::error_code &ec) std::error_code &ec)
{ {
try try
{ {
@@ -168,10 +167,10 @@ public:
std::string content; std::string content;
GetPreset(request_uri, &name, &content); GetPreset(request_uri, &name, &content);
res.set(http::field::content_type, "application/octet-stream"); res.set(HttpField::content_type, "application/octet-stream");
res.set(http::field::cache_control, "no-cache"); res.set(HttpField::cache_control, "no-cache");
res.set(http::field::content_length, content.length()); res.setContentLength(content.length());
res.set(http::field::content_disposition, GetContentDispositionHeader(name, PRESET_EXTENSION)); res.set(HttpField::content_disposition, GetContentDispositionHeader(name, PRESET_EXTENSION));
return; return;
} }
if (request_uri.segment(1) == "downloadBank") if (request_uri.segment(1) == "downloadBank")
@@ -180,10 +179,10 @@ public:
std::string content; std::string content;
GetBank(request_uri, &name, &content); GetBank(request_uri, &name, &content);
res.set(http::field::content_type, "application/octet-stream"); res.set(HttpField::content_type, "application/octet-stream");
res.set(http::field::cache_control, "no-cache"); res.set(HttpField::cache_control, "no-cache");
res.set(http::field::content_length, content.length()); res.set(HttpField::content_disposition, GetContentDispositionHeader(name, BANK_EXTENSION));
res.set(http::field::content_disposition, GetContentDispositionHeader(name, BANK_EXTENSION)); res.setContentLength(content.length());
return; return;
} }
throw PiPedalException("Not found."); throw PiPedalException("Not found.");
@@ -203,9 +202,9 @@ public:
virtual void get_response( virtual void get_response(
const uri &request_uri, const uri &request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req, const HttpRequest &req,
boost::beast::http::response<boost::beast::http::string_body> &res, HttpResponse &res,
boost::beast::error_code &ec) std::error_code &ec)
{ {
try try
{ {
@@ -215,11 +214,11 @@ public:
std::string content; std::string content;
GetPreset(request_uri, &name, &content); GetPreset(request_uri, &name, &content);
res.set(http::field::content_type, "application/octet-stream"); res.set(HttpField::content_type, "application/octet-stream");
res.set(http::field::cache_control, "no-cache"); res.set(HttpField::cache_control, "no-cache");
res.set(http::field::content_length, content.length()); res.setContentLength(content.length());
res.set(http::field::content_disposition, GetContentDispositionHeader(name, PRESET_EXTENSION)); res.set(HttpField::content_disposition, GetContentDispositionHeader(name, PRESET_EXTENSION));
res.body() = content; res.setBody(content);
} }
else if (request_uri.segment(1) == "downloadBank") else if (request_uri.segment(1) == "downloadBank")
{ {
@@ -227,11 +226,11 @@ public:
std::string content; std::string content;
GetBank(request_uri, &name, &content); GetBank(request_uri, &name, &content);
res.set(http::field::content_type, "application/octet-stream"); res.set(HttpField::content_type, "application/octet-stream");
res.set(http::field::cache_control, "no-cache"); res.set(HttpField::cache_control, "no-cache");
res.set(http::field::content_length, content.length()); res.setContentLength(content.length());
res.set(http::field::content_disposition, GetContentDispositionHeader(name, BANK_EXTENSION)); res.set(HttpField::content_disposition, GetContentDispositionHeader(name, BANK_EXTENSION));
res.body() = content; res.setBody(content);
} }
else else
{ {
@@ -252,15 +251,15 @@ public:
} }
virtual void post_response( virtual void post_response(
const uri &request_uri, const uri &request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req, const HttpRequest &req,
boost::beast::http::response<boost::beast::http::string_body> &res, HttpResponse &res,
boost::beast::error_code &ec) std::error_code &ec)
{ {
try try
{ {
if (request_uri.segment(1) == "uploadPreset") if (request_uri.segment(1) == "uploadPreset")
{ {
std::string presetBody = req.body(); const std::string& presetBody = req.body();
std::stringstream s(presetBody); std::stringstream s(presetBody);
json_reader reader(s); json_reader reader(s);
@@ -276,19 +275,19 @@ public:
uint64_t instanceId = model->uploadPreset(bankFile, uploadAfter); uint64_t instanceId = model->uploadPreset(bankFile, uploadAfter);
res.set(http::field::content_type, "application/json"); res.set(HttpField::content_type, "application/json");
res.set(http::field::cache_control, "no-cache"); res.set(HttpField::cache_control, "no-cache");
std::stringstream sResult; std::stringstream sResult;
sResult << instanceId; sResult << instanceId;
std::string result = sResult.str(); std::string result = sResult.str();
res.set(http::field::content_length, result.length()); res.setContentLength(result.length());
res.body() = result; res.setBody(result);
} }
else if (request_uri.segment(1) == "uploadBank") else if (request_uri.segment(1) == "uploadBank")
{ {
std::string presetBody = req.body(); const std::string& presetBody = req.body();
std::stringstream s(presetBody); std::istringstream s(presetBody);
json_reader reader(s); json_reader reader(s);
uint64_t uploadAfter = -1; uint64_t uploadAfter = -1;
@@ -303,14 +302,14 @@ public:
uint64_t instanceId = model->uploadBank(bankFile, uploadAfter); uint64_t instanceId = model->uploadBank(bankFile, uploadAfter);
res.set(http::field::content_type, "application/json"); res.set(HttpField::content_type, "application/json");
res.set(http::field::cache_control, "no-cache"); res.set(HttpField::cache_control, "no-cache");
std::stringstream sResult; std::stringstream sResult;
sResult << instanceId; sResult << instanceId;
std::string result = sResult.str(); std::string result = sResult.str();
res.set(http::field::content_length, result.length()); res.setContentLength(result.length());
res.body() = result; res.setBody(result);
} }
else else
{ {
@@ -354,81 +353,31 @@ public:
} }
virtual ~InterceptConfig() {} virtual ~InterceptConfig() {}
virtual void head_response( virtual void head_response(
const uri &request_uri, const uri&request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req, const HttpRequest &req,
boost::beast::http::response<boost::beast::http::empty_body> &res, HttpResponse &res,
boost::beast::error_code &ec) std::error_code &ec)
{ {
res.set(http::field::content_type, "application/json"); res.set(HttpField::content_type, "application/json");
res.set(http::field::cache_control, "no-cache"); res.set(HttpField::cache_control, "no-cache");
res.content_length(response.length()); res.setContentLength(response.length());
return; return;
} }
virtual void get_response( virtual void get_response(
const uri &request_uri, const uri &request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req, const HttpRequest &req,
boost::beast::http::response<boost::beast::http::string_body> &res, HttpResponse &res,
boost::beast::error_code &ec) std::error_code &ec)
{ {
res.set(http::field::content_type, "application/json"); res.set(HttpField::content_type, "application/json");
res.set(http::field::cache_control, "no-cache"); res.set(HttpField::cache_control, "no-cache");
res.content_length(response.length()); res.setContentLength(response.length());
res.body() = response; res.setBody(response);
} }
}; };
class ReactRedirector : public RequestHandler
{
PiPedalConfiguration config;
public:
ReactRedirector(const PiPedalConfiguration &config)
: RequestHandler("/"),
config(config)
{
}
virtual ~ReactRedirector() {}
virtual bool wantsRedirect(const uri &requestUri)
{
if (requestUri.segment_count() == 0 || (requestUri.segment_count() == 1 && requestUri.segment(0) == "index.htm"))
{
return true;
}
return false;
}
uri GetRedirect(const uri &requestUri)
{
return requestUri;
}
virtual bool wants(boost::beast::http::verb verb, const uri &request_uri) const
{
return false;
}
virtual void head_response(
const uri &request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req,
boost::beast::http::response<boost::beast::http::empty_body> &res,
boost::beast::error_code &ec)
{
ec = errc::make_error_code(errc::no_such_file_or_directory);
return;
}
virtual void get_response(
const uri &request_uri,
const boost::beast::http::request<boost::beast::http::string_body> &req,
boost::beast::http::response<boost::beast::http::string_body> &res,
boost::beast::error_code &ec)
{
ec = errc::make_error_code(errc::no_such_file_or_directory);
}
};
static bool isJackServiceRunning() static bool isJackServiceRunning()
{ {
@@ -553,18 +502,13 @@ int main(int argc, char *argv[])
auto const threads = std::max<int>(1, configuration.GetThreads()); auto const threads = std::max<int>(1, configuration.GetThreads());
server = std::make_shared<BeastServer>( server = createBeastServer(
address, port, web_root.c_str(), threads); address, port, web_root.c_str(), threads);
Lv2Log::info("Document root: %s Threads: %d", doc_root.c_str(), (int)threads); Lv2Log::info("Document root: %s Threads: %d", doc_root.c_str(), (int)threads);
server->SetLogHttpRequests(configuration.LogHttpRequests()); server->SetLogHttpRequests(configuration.LogHttpRequests());
boost::asio::ip::network_v4 gateway;
if (configuration.GetAccessPointGateway(&gateway))
{
server->SetAccessPointGateway(gateway, configuration.GetAccessPointServerAddress());
}
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
@@ -655,7 +599,7 @@ int main(int argc, char *argv[])
Lv2Log::info("Shutting down gracefully."); Lv2Log::info("Shutting down gracefully.");
model.Close(); model.Close();
Lv2Log::info("Stopping web server."); Lv2Log::info("Stopping web server.");
server->Stop(); server->ShutDown(5000);
server->Join(); server->Join();
Lv2Log::info("Shutdown complete."); Lv2Log::info("Shutdown complete.");
} }