From 14ab4dcff7f8461dfed27b6352249b683c1f4bae Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 22 Oct 2011 00:21:43 +0000 Subject: Move *all* OSC and HTTP stuff to their respective modules. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@3578 a436a847-0d15-0410-975c-d299462d15a1 --- src/client/HTTPClientReceiver.cpp | 241 ------------------------------ src/client/HTTPClientReceiver.hpp | 85 ----------- src/client/HTTPEngineSender.cpp | 194 ------------------------ src/client/HTTPEngineSender.hpp | 126 ---------------- src/client/OSCClientReceiver.cpp | 303 -------------------------------------- src/client/OSCClientReceiver.hpp | 98 ------------ src/client/OSCEngineSender.cpp | 241 ------------------------------ src/client/OSCEngineSender.hpp | 117 --------------- src/client/ingen_client.cpp | 50 +------ src/client/wscript | 15 +- src/http/HTTPClientReceiver.cpp | 241 ++++++++++++++++++++++++++++++ src/http/HTTPClientReceiver.hpp | 85 +++++++++++ src/http/HTTPClientSender.hpp | 3 +- src/http/HTTPEngineSender.cpp | 194 ++++++++++++++++++++++++ src/http/HTTPEngineSender.hpp | 126 ++++++++++++++++ src/http/HTTPSender.cpp | 156 ++++++++++++++++++++ src/http/HTTPSender.hpp | 61 ++++++++ src/http/ingen_http.cpp | 54 ------- src/http/ingen_http_server.cpp | 54 +++++++ src/ingen/main.cpp | 17 ++- src/osc/OSCClientReceiver.cpp | 303 ++++++++++++++++++++++++++++++++++++++ src/osc/OSCClientReceiver.hpp | 90 +++++++++++ src/osc/OSCClientSender.hpp | 3 +- src/osc/OSCEngineReceiver.hpp | 56 +++---- src/osc/OSCEngineSender.cpp | 241 ++++++++++++++++++++++++++++++ src/osc/OSCEngineSender.hpp | 118 +++++++++++++++ src/osc/OSCSender.cpp | 111 ++++++++++++++ src/osc/OSCSender.hpp | 52 +++++++ src/osc/ingen_osc.cpp | 53 ------- src/osc/ingen_osc_server.cpp | 53 +++++++ src/shared/HTTPSender.cpp | 156 -------------------- src/shared/HTTPSender.hpp | 61 -------- src/shared/OSCSender.cpp | 111 -------------- src/shared/OSCSender.hpp | 52 ------- src/shared/World.cpp | 5 + src/shared/wscript | 9 +- wscript | 2 +- 37 files changed, 1936 insertions(+), 2001 deletions(-) delete mode 100644 src/client/HTTPClientReceiver.cpp delete mode 100644 src/client/HTTPClientReceiver.hpp delete mode 100644 src/client/HTTPEngineSender.cpp delete mode 100644 src/client/HTTPEngineSender.hpp delete mode 100644 src/client/OSCClientReceiver.cpp delete mode 100644 src/client/OSCClientReceiver.hpp delete mode 100644 src/client/OSCEngineSender.cpp delete mode 100644 src/client/OSCEngineSender.hpp create mode 100644 src/http/HTTPClientReceiver.cpp create mode 100644 src/http/HTTPClientReceiver.hpp create mode 100644 src/http/HTTPEngineSender.cpp create mode 100644 src/http/HTTPEngineSender.hpp create mode 100644 src/http/HTTPSender.cpp create mode 100644 src/http/HTTPSender.hpp delete mode 100644 src/http/ingen_http.cpp create mode 100644 src/http/ingen_http_server.cpp create mode 100644 src/osc/OSCClientReceiver.cpp create mode 100644 src/osc/OSCClientReceiver.hpp create mode 100644 src/osc/OSCEngineSender.cpp create mode 100644 src/osc/OSCEngineSender.hpp create mode 100644 src/osc/OSCSender.cpp create mode 100644 src/osc/OSCSender.hpp delete mode 100644 src/osc/ingen_osc.cpp create mode 100644 src/osc/ingen_osc_server.cpp delete mode 100644 src/shared/HTTPSender.cpp delete mode 100644 src/shared/HTTPSender.hpp delete mode 100644 src/shared/OSCSender.cpp delete mode 100644 src/shared/OSCSender.hpp diff --git a/src/client/HTTPClientReceiver.cpp b/src/client/HTTPClientReceiver.cpp deleted file mode 100644 index 0ec5aaa4..00000000 --- a/src/client/HTTPClientReceiver.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2008-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include - -#include - -#include "ingen/shared/World.hpp" -#include "raul/log.hpp" - -#include "HTTPClientReceiver.hpp" - -#define LOG(s) s << "[HTTPClientReceiver] " - -using namespace std; -using namespace Raul; - -namespace Ingen { - -using namespace Serialisation; - -namespace Client { - -static SoupSession* client_session = NULL; -static HTTPClientReceiver* client_receiver = NULL; - -HTTPClientReceiver::HTTPClientReceiver( - Shared::World* world, - const std::string& url, - SharedPtr target) - : _target(target) - , _world(world) - , _url(url) -{ - start(false); - client_receiver = this; -} - -HTTPClientReceiver::~HTTPClientReceiver() -{ - stop(); - if (client_receiver == this) - client_receiver = NULL; -} - -HTTPClientReceiver::Listener::Listener(HTTPClientReceiver* receiver, const std::string& uri) - : _uri(uri) - , _receiver(receiver) -{ - const string port_str = uri.substr(uri.find_last_of(":")+1); - int port = atoi(port_str.c_str()); - - LOG(info) << "Client HTTP listen: " << uri << " (port " << port << ")" << endl; - - struct sockaddr_in servaddr; - - // Create listen address - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons(port); - - // Create listen socket - if ((_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - LOG(error) << "Error creating listening socket: %s" << strerror(errno) << endl; - _sock = -1; - return; - } - - // Set remote address (FIXME: always localhost) - if (inet_aton("127.0.0.1", &servaddr.sin_addr) <= 0) { - LOG(error) << "Invalid remote IP address" << endl; - _sock = -1; - return; - } - - // Connect to server - if (connect(_sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { - LOG(error) << "Error calling connect: " << strerror(errno) << endl; - _sock = -1; - return; - } -} - -HTTPClientReceiver::Listener::~Listener() -{ - close(_sock); -} - -void -HTTPClientReceiver::send(SoupMessage* msg) -{ - if (!client_session) { - LOG(debug) << "Starting session" << endl; - client_session = soup_session_sync_new(); - } - - assert(SOUP_IS_MESSAGE(msg)); - soup_session_queue_message(client_session, msg, message_callback, client_receiver); -} - -void -HTTPClientReceiver::close_session() -{ - if (client_session) { - SoupSession* s = client_session; - client_session = NULL; - soup_session_abort(s); - } -} - -void -HTTPClientReceiver::update(const std::string& str) -{ - //LOG(info) << _world->parser()->parse_update(_world, _target.get(), str, _url); -} - -void -HTTPClientReceiver::Listener::_run() -{ - char in = '\0'; - char last = '\0'; - char llast = '\0'; - string recv; - - while (true) { - while (read(_sock, &in, 1) > 0 ) { - recv += in; - if (in == '\n' && last == '\n' && llast == '\n') { - if (!recv.empty()) { - _receiver->update(recv); - recv.clear(); - last = '\0'; - llast = '\0'; - } - break; - } - llast = last; - last = in; - } - } - - LOG(info) << "HTTP listener finished" << endl; -} - -void -HTTPClientReceiver::message_callback(SoupSession* session, SoupMessage* msg, void* ptr) -{ - if (ptr == NULL) - return; - - HTTPClientReceiver* me = (HTTPClientReceiver*)ptr; - const string path = soup_message_get_uri(msg)->path; - - if (msg->response_body->data == NULL) { - LOG(error) << "Empty client message" << endl; - return; - } - - if (path == "/") { - me->_target->response_ok(0); - - } else if (path == "/plugins") { - if (msg->response_body->data == NULL) { - LOG(error) << "Empty response" << endl; - } else { - Glib::Mutex::Lock lock(me->_mutex); - me->_target->response_ok(0); - me->_world->parser()->parse_string(me->_world, me->_target.get(), - Glib::ustring(msg->response_body->data), me->_url); - } - - } else if (path.substr(0, 6) == "/patch") { - if (msg->response_body->data == NULL) { - LOG(error) << "Empty response" << endl; - } else { - Glib::Mutex::Lock lock(me->_mutex); - me->_target->response_ok(0); - me->_world->parser()->parse_string( - me->_world, - me->_target.get(), - Glib::ustring(msg->response_body->data), - path); - } - - } else if (path == "/stream") { - if (msg->response_body->data == NULL) { - LOG(error) << "Empty response" << endl; - } else { - Glib::Mutex::Lock lock(me->_mutex); - string uri = string(soup_uri_to_string(soup_message_get_uri(msg), false)); - uri = uri.substr(0, uri.find_last_of(":")); - uri += string(":") + msg->response_body->data; - LOG(info) << "Stream URI: " << uri << endl; - me->_listener = boost::shared_ptr(new Listener(me, uri)); - me->_listener->start(); - } - - } else { - LOG(error) << "Unknown message: " << path << endl; - me->update(msg->response_body->data); - } -} - -void -HTTPClientReceiver::start(bool dump) -{ - if (!_world->parser()) - _world->load_module("serialisation"); - - SoupMessage* msg = soup_message_new("GET", (_url + "/stream").c_str()); - assert(SOUP_IS_MESSAGE(msg)); - soup_session_queue_message(client_session, msg, message_callback, this); -} - -void -HTTPClientReceiver::stop() -{ - //unregister_client(); - close_session(); -} - -} // namespace Client -} // namespace Ingen - diff --git a/src/client/HTTPClientReceiver.hpp b/src/client/HTTPClientReceiver.hpp deleted file mode 100644 index d7165c81..00000000 --- a/src/client/HTTPClientReceiver.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2008-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef INGEN_CLIENT_HTTPCLIENTRECEIVER_HPP -#define INGEN_CLIENT_HTTPCLIENTRECEIVER_HPP - -#include - -#include -#include - -#include "ingen/ClientInterface.hpp" -#include "ingen/serialisation/Parser.hpp" -#include "raul/Deletable.hpp" -#include "raul/SharedPtr.hpp" -#include "raul/Thread.hpp" -#include "sord/sordmm.hpp" - -typedef struct _SoupSession SoupSession; -typedef struct _SoupMessage SoupMessage; - -namespace Ingen { -namespace Client { - -class HTTPClientReceiver : public boost::noncopyable, public Raul::Deletable -{ -public: - HTTPClientReceiver(Shared::World* world, - const std::string& url, - SharedPtr target); - - ~HTTPClientReceiver(); - - static void send(SoupMessage* msg); - static void close_session(); - - std::string uri() const { return _url; } - - void start(bool dump); - void stop(); - -private: - static void message_callback(SoupSession* session, SoupMessage* msg, void* ptr); - - void update(const std::string& str); - - class Listener : public Raul::Thread { - public: - Listener(HTTPClientReceiver* receiver, const std::string& uri); - ~Listener(); - void _run(); - private: - std::string _uri; - int _sock; - HTTPClientReceiver* _receiver; - }; - - friend class Listener; - - SharedPtr _listener; - Glib::Mutex _mutex; - SharedPtr _target; - Shared::World* _world; - const std::string _url; - bool _quit_flag; -}; - -} // namespace Client -} // namespace Ingen - -#endif // INGEN_CLIENT_HTTPCLIENTRECEIVER_HPP diff --git a/src/client/HTTPEngineSender.cpp b/src/client/HTTPEngineSender.cpp deleted file mode 100644 index 43a3d44c..00000000 --- a/src/client/HTTPEngineSender.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2008-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include "raul/AtomRDF.hpp" -#include "raul/log.hpp" -#include "sord/sordmm.hpp" - -#include "ingen/shared/World.hpp" -#include "HTTPEngineSender.hpp" -#include "HTTPClientReceiver.hpp" - -#define LOG(s) s << "[HTTPEngineSender] " - -using namespace std; -using namespace Raul; - -namespace Ingen { - -using namespace Shared; - -namespace Client { - -HTTPEngineSender::HTTPEngineSender(World* world, - const URI& engine_url, - SharedPtr receiver) - : _receiver(receiver) - , _world(*world->rdf_world()) - , _engine_url(engine_url) - , _id(0) - , _enabled(true) -{ - _session = soup_session_sync_new(); -} - -HTTPEngineSender::~HTTPEngineSender() -{ - soup_session_abort(_session); -} - -void -HTTPEngineSender::attach(int32_t ping_id, bool block) -{ - LOG(debug) << "Attaching to " << _engine_url << endl; - SoupMessage* msg = soup_message_new ("GET", _engine_url.c_str()); - HTTPClientReceiver::send(msg); -} - -/* *** ServerInterface implementation below here *** */ - -/** Register with the engine via HTTP. - * - * Note that this does not actually use 'key', since the engine creates - * it's own key for HTTP clients (namely the incoming URL), for NAT - * traversal. It is a parameter to remain compatible with ServerInterface. - */ -void -HTTPEngineSender::register_client(ClientInterface* client) -{ - /*SoupMessage* msg = soup_message_new("GET", (_engine_url.str() + "/stream").c_str()); - HTTPClientReceiver::send(msg);*/ -} - -void -HTTPEngineSender::unregister_client(const URI& uri) -{ -} - -// Object commands - -void -HTTPEngineSender::put(const URI& uri, - const Resource::Properties& properties, - Resource::Graph ctx) -{ - const string path = (uri.substr(0, 6) == "path:/") ? uri.substr(6) : uri.str(); - const string full_uri = _engine_url.str() + "/" + path; - - Sord::Model model(_world); - for (Resource::Properties::const_iterator i = properties.begin(); i != properties.end(); ++i) - model.add_statement(Sord::URI(_world, path), - AtomRDF::atom_to_node(model, i->first), - AtomRDF::atom_to_node(model, i->second)); - - const string str = model.write_to_string(""); - SoupMessage* msg = soup_message_new(SOUP_METHOD_PUT, full_uri.c_str()); - assert(msg); - soup_message_set_request(msg, "application/x-turtle", SOUP_MEMORY_COPY, str.c_str(), str.length()); - soup_session_send_message(_session, msg); -} - -void -HTTPEngineSender::delta(const Raul::URI& path, - const Resource::Properties& remove, - const Resource::Properties& add) -{ - LOG(warn) << "TODO: HTTP delta" << endl; -} - -void -HTTPEngineSender::move(const Path& old_path, - const Path& new_path) -{ - SoupMessage* msg = soup_message_new(SOUP_METHOD_MOVE, - (_engine_url.str() + old_path.str()).c_str()); - soup_message_headers_append(msg->request_headers, "Destination", - (_engine_url.str() + new_path.str()).c_str()); - soup_session_send_message(_session, msg); -} - -void -HTTPEngineSender::del(const URI& uri) -{ - const string path = (uri.substr(0, 6) == "path:/") ? uri.substr(6) : uri.str(); - const string full_uri = _engine_url.str() + "/" + path; - SoupMessage* msg = soup_message_new(SOUP_METHOD_DELETE, full_uri.c_str()); - soup_session_send_message(_session, msg); -} - -void -HTTPEngineSender::connect(const Path& src_port_path, - const Path& dst_port_path) -{ - LOG(warn) << "TODO: HTTP connect" << endl; -} - -void -HTTPEngineSender::disconnect(const URI& src, - const URI& dst) -{ - LOG(warn) << "TODO: HTTP disconnect" << endl; -} - -void -HTTPEngineSender::disconnect_all(const Path& parent_patch_path, - const Path& path) -{ - LOG(warn) << "TODO: HTTP disconnect_all" << endl; -} - -void -HTTPEngineSender::set_property(const URI& subject, - const URI& predicate, - const Atom& value) -{ - Resource::Properties prop; - prop.insert(make_pair(predicate, value)); - put(subject, prop); -} - -// Requests // - -void -HTTPEngineSender::ping() -{ - LOG(debug) << "Ping " << _engine_url << endl; - get(_engine_url); -} - -void -HTTPEngineSender::get(const URI& uri) -{ - if (!Raul::Path::is_path(uri) && uri.scheme() != "http") { - LOG(warn) << "Ignoring GET of non-HTTP URI " << uri << endl; - return; - } - - const std::string request_uri = (Raul::Path::is_path(uri)) - ?_engine_url.str() + "/patch" + uri.substr(uri.find("/")) - : uri.str(); - cout << "Get " << request_uri << endl; - LOG(debug) << "Get " << request_uri << endl; - SoupMessage* msg = soup_message_new("GET", request_uri.c_str()); - HTTPClientReceiver::send(msg); -} - -} // namespace Client -} // namespace Ingen - diff --git a/src/client/HTTPEngineSender.hpp b/src/client/HTTPEngineSender.hpp deleted file mode 100644 index 14439e39..00000000 --- a/src/client/HTTPEngineSender.hpp +++ /dev/null @@ -1,126 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2008-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef INGEN_CLIENT_HTTPENGINESENDER_HPP -#define INGEN_CLIENT_HTTPENGINESENDER_HPP - -#include - -#include - -#include "raul/Deletable.hpp" -#include "raul/Path.hpp" -#include "sord/sordmm.hpp" - -#include "ingen/ServerInterface.hpp" - -typedef struct _SoupSession SoupSession; - -namespace Ingen { - -namespace Shared { class World; } - -namespace Client { - -class HTTPClientReceiver; - -/* HTTP (via libsoup) interface to the engine. - * - * Clients can use this opaquely as an ServerInterface to control the engine - * over HTTP (whether over a network or not). - * - * \ingroup IngenClient - */ -class HTTPEngineSender : public ServerInterface -{ -public: - HTTPEngineSender(Shared::World* world, - const Raul::URI& engine_url, - SharedPtr receiver); - - ~HTTPEngineSender(); - - Raul::URI uri() const { return _engine_url; } - - inline int32_t next_id() - { int32_t ret = (_id == -1) ? -1 : _id++; return ret; } - - void respond_to(ClientInterface* client, int32_t id) { _id = id; } - void disable_responses() { _id = -1; } - - void attach(int32_t ping_id, bool block); - - /* *** ServerInterface implementation below here *** */ - - void enable() { _enabled = true; } - void disable() { _enabled = false; } - - void bundle_begin() {} - void bundle_end() {} - - // Client registration - void register_client(ClientInterface* client); - void unregister_client(const Raul::URI& uri); - - // Object commands - - virtual void put(const Raul::URI& path, - const Resource::Properties& properties, - Resource::Graph ctx=Resource::DEFAULT); - - virtual void delta(const Raul::URI& path, - const Resource::Properties& remove, - const Resource::Properties& add); - - virtual void del(const Raul::URI& uri); - - virtual void move(const Raul::Path& old_path, - const Raul::Path& new_path); - - virtual void connect(const Raul::Path& src_port_path, - const Raul::Path& dst_port_path); - - virtual void disconnect(const Raul::URI& src, - const Raul::URI& dst); - - virtual void disconnect_all(const Raul::Path& parent_patch_path, - const Raul::Path& path); - - virtual void set_property(const Raul::URI& subject, - const Raul::URI& predicate, - const Raul::Atom& value); - - // Requests // - void ping(); - void get(const Raul::URI& uri); - -protected: - SharedPtr _receiver; - - SoupSession* _session; - Sord::World& _world; - const Raul::URI _engine_url; - int _client_port; - int32_t _id; - bool _enabled; -}; - -} // namespace Client -} // namespace Ingen - -#endif // INGEN_CLIENT_HTTPENGINESENDER_HPP - diff --git a/src/client/OSCClientReceiver.cpp b/src/client/OSCClientReceiver.cpp deleted file mode 100644 index 4fef1d1c..00000000 --- a/src/client/OSCClientReceiver.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include - -#include "raul/log.hpp" -#include "raul/AtomLiblo.hpp" -#include "raul/Path.hpp" - -#include "ingen-config.h" -#include "OSCClientReceiver.hpp" - -#define LOG(s) s << "[OSCClientReceiver] " - -using namespace std; -using namespace Raul; - -namespace Ingen { -namespace Client { - -OSCClientReceiver::OSCClientReceiver(int listen_port, - SharedPtr target) - : _target(target) - , _st(NULL) - , _listen_port(listen_port) -{ -#ifdef RAUL_LOG_DEBUG - start(true); -#else - start(false); // true = dump, false = shutup -#endif -} - -OSCClientReceiver::~OSCClientReceiver() -{ - stop(); -} - -void -OSCClientReceiver::start(bool dump_osc) -{ - if (_st != NULL) - return; - - // Attempt preferred port - if (_listen_port != 0) { - char port_str[8]; - snprintf(port_str, 8, "%d", _listen_port); - _st = lo_server_thread_new(port_str, lo_error_cb); - } - - // Find a free port - if (!_st) { - _st = lo_server_thread_new(NULL, lo_error_cb); - _listen_port = lo_server_thread_get_port(_st); - } - - if (_st == NULL) { - LOG(error) << "Could not start OSC listener. Aborting." << endl; - exit(EXIT_FAILURE); - } else { - LOG(info) << "Started OSC listener on port " << lo_server_thread_get_port(_st) << endl; - } - - // Print all incoming messages - if (dump_osc) - lo_server_thread_add_method(_st, NULL, NULL, generic_cb, NULL); - - setup_callbacks(); - - // Display any uncaught messages to the console - //lo_server_thread_add_method(_st, NULL, NULL, unknown_cb, NULL); - - lo_server_thread_start(_st); -} - -void -OSCClientReceiver::stop() -{ - if (_st != NULL) { - //unregister_client(); - lo_server_thread_free(_st); - _st = NULL; - } -} - -int -OSCClientReceiver::generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data) -{ - printf("[OSCClientReceiver] %s (%s)\t", path, types); - - for (int i=0; i < argc; ++i) { - lo_arg_pp(lo_type(types[i]), argv[i]); - printf("\t"); - } - printf("\n"); - - return 1; // not handled -} - -void -OSCClientReceiver::lo_error_cb(int num, const char* msg, const char* path) -{ - LOG(error) << "Got error from server: " << msg << endl; -} - -int -OSCClientReceiver::unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data) -{ - std::string msg = "Received unknown OSC message: "; - msg += path; - - LOG(error) << msg << endl; - - return 0; -} - -void -OSCClientReceiver::setup_callbacks() -{ - if (!_target) - return; - - lo_server_thread_add_method(_st, "/ok", "i", response_ok_cb, this); - lo_server_thread_add_method(_st, "/error", "is", response_error_cb, this); - lo_server_thread_add_method(_st, "/plugin", "sss", plugin_cb, this); - lo_server_thread_add_method(_st, "/put", NULL, put_cb, this); - lo_server_thread_add_method(_st, "/delta_begin", NULL, delta_begin_cb, this); - lo_server_thread_add_method(_st, "/delta_remove", NULL, delta_remove_cb, this); - lo_server_thread_add_method(_st, "/delta_add", NULL, delta_add_cb, this); - lo_server_thread_add_method(_st, "/delta_end", NULL, delta_end_cb, this); - lo_server_thread_add_method(_st, "/move", "ss", move_cb, this); - lo_server_thread_add_method(_st, "/delete", "s", del_cb, this); - lo_server_thread_add_method(_st, "/connect", "ss", connection_cb, this); - lo_server_thread_add_method(_st, "/disconnect", "ss", disconnection_cb, this); - lo_server_thread_add_method(_st, "/set_property", NULL, set_property_cb, this); - lo_server_thread_add_method(_st, "/activity", "sT", activity_cb, this); - lo_server_thread_add_method(_st, "/activity", "sf", activity_cb, this); -} - -/** Catches errors that aren't a direct result of a client request. - */ -int -OSCClientReceiver::_error_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - _target->error((char*)argv[0]); - return 0; -} - -int -OSCClientReceiver::_del_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - _target->del((const char*)&argv[0]->s); - return 0; -} - -int -OSCClientReceiver::_put_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* obj_path = &argv[0]->s; - const char* ctx = &argv[1]->s; - Resource::Properties prop; - for (int i = 2; i < argc-1; i += 2) - prop.insert(make_pair(&argv[i]->s, - AtomLiblo::lo_arg_to_atom(types[i+1], argv[i+1]))); - _target->put(obj_path, prop, Resource::uri_to_graph(ctx)); - return 0; -} - -int -OSCClientReceiver::_delta_begin_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* obj_path = &argv[0]->s; - assert(_delta_remove.empty()); - assert(_delta_add.empty()); - _delta_uri = obj_path; - return 0; -} - -int -OSCClientReceiver::_delta_remove_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - _delta_remove.insert(make_pair(&argv[0]->s, - AtomLiblo::lo_arg_to_atom(types[1], argv[1]))); - return 0; -} - -int -OSCClientReceiver::_delta_add_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - _delta_add.insert(make_pair(&argv[0]->s, - AtomLiblo::lo_arg_to_atom(types[1], argv[1]))); - return 0; -} - -int -OSCClientReceiver::_delta_end_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - _target->delta(_delta_uri, _delta_remove, _delta_add); - _delta_uri = Raul::URI(); - _delta_remove.clear(); - _delta_add.clear(); - return 0; -} - -int -OSCClientReceiver::_move_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* old_path = &argv[1]->s; - const char* new_path = &argv[2]->s; - - _target->move(old_path, new_path); - return 0; -} - -int -OSCClientReceiver::_connection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* const src_port_path = &argv[0]->s; - const char* const dst_port_path = &argv[1]->s; - - _target->connect(src_port_path, dst_port_path); - - return 0; -} - -int -OSCClientReceiver::_disconnection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* src_uri = &argv[0]->s; - const char* dst_uri = &argv[1]->s; - - _target->disconnect(src_uri, dst_uri); - - return 0; -} - -/** Notification of a new or updated property. - */ -int -OSCClientReceiver::_set_property_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - if (argc != 3 || types[0] != 's' || types[1] != 's') - return 1; - - const char* obj_uri = &argv[0]->s; - const char* key = &argv[1]->s; - - Atom value = AtomLiblo::lo_arg_to_atom(types[2], argv[2]); - - _target->set_property(obj_uri, key, value); - - return 0; -} - -int -OSCClientReceiver::_activity_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* const port_path = &argv[0]->s; - - Atom value = AtomLiblo::lo_arg_to_atom(types[1], argv[1]); - - _target->activity(port_path, value); - - return 0; -} - -int -OSCClientReceiver::_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - assert(!strcmp(types, "i")); - _target->response_ok(argv[0]->i); - - return 0; -} - -int -OSCClientReceiver::_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - assert(!strcmp(types, "is")); - _target->response_error(argv[0]->i, &argv[1]->s); - - return 0; -} - -} // namespace Client -} // namespace Ingen diff --git a/src/client/OSCClientReceiver.hpp b/src/client/OSCClientReceiver.hpp deleted file mode 100644 index 3b7f5db0..00000000 --- a/src/client/OSCClientReceiver.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef INGEN_CLIENT_OSCCLIENTRECEIVER_HPP -#define INGEN_CLIENT_OSCCLIENTRECEIVER_HPP - -#include - -#include -#include - -#include "ingen/ClientInterface.hpp" -#include "raul/Deletable.hpp" -#include "raul/SharedPtr.hpp" - -namespace Ingen { -namespace Client { - -/** Arguments to a liblo handler */ -#define LO_HANDLER_ARGS const char* path, const char* types, lo_arg** argv, int argc, lo_message msg - -/** Define a static handler to be passed to lo_add_method, which is a trivial - * wrapper around a non-static method that does the real work. */ -#define LO_HANDLER(name) \ -int _##name##_cb (LO_HANDLER_ARGS);\ -inline static int name##_cb(LO_HANDLER_ARGS, void* osc_listener)\ -{ return ((OSCClientReceiver*)osc_listener)->_##name##_cb(path, types, argv, argc, msg); } - -/** Client-side receiver for OSC messages from the engine. - * - * \ingroup IngenClient - */ -class OSCClientReceiver : public boost::noncopyable, public Raul::Deletable -{ -public: - OSCClientReceiver(int listen_port, SharedPtr target); - ~OSCClientReceiver(); - - std::string uri() const { return lo_server_thread_get_url(_st); } - - void start(bool dump_osc); - void stop(); - - int listen_port() { return _listen_port; } - std::string listen_url() { return lo_server_thread_get_url(_st); } - -private: - void setup_callbacks(); - - static void lo_error_cb(int num, const char* msg, const char* path); - - static int generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data); - static int unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* osc_receiver); - - SharedPtr _target; - lo_server_thread _st; - Raul::URI _delta_uri; - Resource::Properties _delta_remove; - Resource::Properties _delta_add; - int _listen_port; - - LO_HANDLER(error); - LO_HANDLER(response_ok); - LO_HANDLER(response_error); - LO_HANDLER(plugin); - LO_HANDLER(plugin_list_end); - LO_HANDLER(new_patch); - LO_HANDLER(del); - LO_HANDLER(move); - LO_HANDLER(connection); - LO_HANDLER(disconnection); - LO_HANDLER(put); - LO_HANDLER(delta_begin); - LO_HANDLER(delta_remove); - LO_HANDLER(delta_add); - LO_HANDLER(delta_end); - LO_HANDLER(set_property); - LO_HANDLER(activity); -}; - -} // namespace Client -} // namespace Ingen - -#endif // INGEN_CLIENT_OSCCLIENTRECEIVER_HPP diff --git a/src/client/OSCEngineSender.cpp b/src/client/OSCEngineSender.cpp deleted file mode 100644 index e2436af7..00000000 --- a/src/client/OSCEngineSender.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "raul/log.hpp" -#include "raul/AtomLiblo.hpp" -#include "raul/Path.hpp" - -#include "ingen/Patch.hpp" -#include "ingen/Port.hpp" -#include "ingen/Plugin.hpp" - -#include "OSCEngineSender.hpp" - -#define LOG(s) s << "[OSCEngineSender] " - -using namespace std; -using namespace Raul; - -namespace Ingen { -namespace Client { - -/** Note the sending port is implicitly set by liblo, lo_send by default sends - * from the most recently created server, so create the OSC listener before - * this to have it all happen on the same port. Yeah, this is a big magic :/ - */ -OSCEngineSender::OSCEngineSender(const URI& engine_url, - size_t max_packet_size, - SharedPtr receiver) - : Shared::OSCSender(max_packet_size) - , _receiver(receiver) - , _engine_url(engine_url) - , _id(0) -{ - _address = lo_address_new_from_url(engine_url.c_str()); -} - -OSCEngineSender::~OSCEngineSender() -{ - lo_address_free(_address); -} - -/** Attempt to connect to the engine (by pinging it). - * - * This doesn't register a client (or otherwise affect the client/engine state). - * To check for success wait for the ping response with id @a ping_id (using the - * relevant OSCClientReceiver). - * - * Passing a client_port of 0 will automatically choose a free port. If the - * @a block parameter is true, this function will not return until a connection - * has successfully been made. - */ -void -OSCEngineSender::attach(int32_t ping_id, bool block) -{ - if (!_address) - _address = lo_address_new_from_url(_engine_url.c_str()); - - if (_address == NULL) { - LOG(error) << "Unable to connect to " << _engine_url << endl; - exit(EXIT_FAILURE); - } - - LOG(info) << "Attempting to contact engine at " << _engine_url << " ..." << endl; - - _id = ping_id; - this->ping(); -} - -/* *** ServerInterface implementation below here *** */ - -/** Register with the engine via OSC. - * - * Note that this does not actually use 'client', since the engine creates - * it's own key for OSC clients (namely the incoming URL), for NAT - * traversal. It is a parameter to remain compatible with ServerInterface. - */ -void -OSCEngineSender::register_client(ClientInterface* client) -{ - send("/register_client", "i", next_id(), LO_ARGS_END); -} - -void -OSCEngineSender::unregister_client(const URI& uri) -{ - send("/unregister_client", "i", next_id(), LO_ARGS_END); -} - -// Object commands - -void -OSCEngineSender::put(const Raul::URI& path, - const Resource::Properties& properties, - Resource::Graph ctx) -{ - typedef Resource::Properties::const_iterator iterator; - lo_message m = lo_message_new(); - lo_message_add_int32(m, next_id()); - lo_message_add_string(m, path.c_str()); - lo_message_add_string(m, Resource::graph_to_uri(ctx).c_str()); - for (iterator i = properties.begin(); i != properties.end(); ++i) { - lo_message_add_string(m, i->first.c_str()); - Raul::AtomLiblo::lo_message_add_atom(m, i->second); - } - send_message("/put", m); -} - -void -OSCEngineSender::delta(const Raul::URI& path, - const Resource::Properties& remove, - const Resource::Properties& add) -{ - typedef Resource::Properties::const_iterator iterator; - - const bool bundle = !_bundle; - if (bundle) - bundle_begin(); - - const int32_t id = next_id(); - send("/delta_begin", "is", id, path.c_str(), LO_ARGS_END); - - for (iterator i = remove.begin(); i != remove.end(); ++i) { - lo_message m = lo_message_new(); - lo_message_add_string(m, i->first.c_str()); - Raul::AtomLiblo::lo_message_add_atom(m, i->second); - send_message("/delta_remove", m); - } - - for (iterator i = add.begin(); i != add.end(); ++i) { - lo_message m = lo_message_new(); - lo_message_add_string(m, i->first.c_str()); - Raul::AtomLiblo::lo_message_add_atom(m, i->second); - send_message("/delta_add", m); - } - - send("/delta_end", "i", id, LO_ARGS_END); - - if (bundle) - bundle_end(); -} - -void -OSCEngineSender::move(const Path& old_path, - const Path& new_path) -{ - send("/move", "iss", - next_id(), - old_path.c_str(), - new_path.c_str(), - LO_ARGS_END); -} - -void -OSCEngineSender::del(const URI& uri) -{ - send("/delete", "is", - next_id(), - uri.c_str(), - LO_ARGS_END); -} - -void -OSCEngineSender::connect(const Path& src_port_path, - const Path& dst_port_path) -{ - send("/connect", "iss", - next_id(), - src_port_path.c_str(), - dst_port_path.c_str(), - LO_ARGS_END); -} - -void -OSCEngineSender::disconnect(const URI& src, - const URI& dst) -{ - send("/disconnect", "iss", - next_id(), - src.c_str(), - dst.c_str(), - LO_ARGS_END); -} - -void -OSCEngineSender::disconnect_all(const Path& parent_patch_path, - const Path& path) -{ - send("/disconnect_all", "iss", - next_id(), - parent_patch_path.c_str(), - path.c_str(), - LO_ARGS_END); -} - -void -OSCEngineSender::set_property(const URI& subject, - const URI& predicate, - const Atom& value) -{ - lo_message m = lo_message_new(); - lo_message_add_int32(m, next_id()); - lo_message_add_string(m, subject.c_str()); - lo_message_add_string(m, predicate.c_str()); - Raul::AtomLiblo::lo_message_add_atom(m, value); - send_message("/set_property", m); -} - -// Requests // - -void -OSCEngineSender::ping() -{ - send("/ping", "i", next_id(), LO_ARGS_END); -} - -void -OSCEngineSender::get(const URI& uri) -{ - send("/get", "is", - next_id(), - uri.c_str(), - LO_ARGS_END); -} - -} // namespace Client -} // namespace Ingen - diff --git a/src/client/OSCEngineSender.hpp b/src/client/OSCEngineSender.hpp deleted file mode 100644 index 75569ec0..00000000 --- a/src/client/OSCEngineSender.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef INGEN_CLIENT_OSCENGINESENDER_HPP -#define INGEN_CLIENT_OSCENGINESENDER_HPP - -#include - -#include - -#include - -#include "raul/Deletable.hpp" - -#include "ingen/ServerInterface.hpp" -#include "../shared/OSCSender.hpp" - -namespace Ingen { - -namespace Client { - -/* OSC (via liblo) interface to the engine. - * - * Clients can use this opaquely as an ServerInterface* to control the engine - * over OSC (whether over a network or not, etc). - * - * \ingroup IngenClient - */ -class OSCEngineSender : public ServerInterface, public Shared::OSCSender { -public: - OSCEngineSender(const Raul::URI& engine_url, - size_t max_packet_size, - SharedPtr receiver); - - ~OSCEngineSender(); - - Raul::URI uri() const { return _engine_url; } - - inline int32_t next_id() - { int32_t ret = (_id == -1) ? -1 : _id++; return ret; } - - void respond_to(ClientInterface* client, int32_t id) { _id = id; } - void disable_responses() { _id = -1; } - - void attach(int32_t ping_id, bool block); - - /* *** ServerInterface implementation below here *** */ - - void enable() { _enabled = true; } - void disable() { _enabled = false; } - - void bundle_begin() { OSCSender::bundle_begin(); } - void bundle_end() { OSCSender::bundle_end(); } - - // Client registration - void register_client(ClientInterface* client); - void unregister_client(const Raul::URI& uri); - - // Object commands - - virtual void put(const Raul::URI& path, - const Resource::Properties& properties, - Resource::Graph ctx=Resource::DEFAULT); - - virtual void delta(const Raul::URI& path, - const Resource::Properties& remove, - const Resource::Properties& add); - - virtual void del(const Raul::URI& uri); - - virtual void move(const Raul::Path& old_path, - const Raul::Path& new_path); - - virtual void connect(const Raul::Path& src_port_path, - const Raul::Path& dst_port_path); - - virtual void disconnect(const Raul::URI& src, - const Raul::URI& dst); - - virtual void disconnect_all(const Raul::Path& parent_patch_path, - const Raul::Path& path); - - virtual void set_property(const Raul::URI& subject_path, - const Raul::URI& predicate, - const Raul::Atom& value); - - // Requests // - void ping(); - void get(const Raul::URI& uri); - -protected: - SharedPtr _receiver; - - const Raul::URI _engine_url; - int _client_port; - int32_t _id; -}; - -} // namespace Client -} // namespace Ingen - -#endif // INGEN_CLIENT_OSCENGINESENDER_HPP - diff --git a/src/client/ingen_client.cpp b/src/client/ingen_client.cpp index 03056f65..2e3e2c74 100644 --- a/src/client/ingen_client.cpp +++ b/src/client/ingen_client.cpp @@ -15,60 +15,16 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "ingen-config.h" -#include "raul/SharedPtr.hpp" #include "ingen/shared/Module.hpp" #include "ingen/shared/World.hpp" -#ifdef HAVE_LIBLO -#include "OSCClientReceiver.hpp" -#include "OSCEngineSender.hpp" -#endif -#ifdef HAVE_SOUP -#include "HTTPClientReceiver.hpp" -#include "HTTPEngineSender.hpp" -#endif - -using namespace Ingen; +#include "raul/SharedPtr.hpp" -#ifdef HAVE_LIBLO -SharedPtr -new_osc_interface(Ingen::Shared::World* world, - const std::string& url, - SharedPtr respond_to) -{ - SharedPtr receiver( - new Client::OSCClientReceiver(16181, respond_to)); - Client::OSCEngineSender* oes = new Client::OSCEngineSender( - url, world->conf()->option("packet-size").get_int32(), receiver); - oes->attach(rand(), true); - return SharedPtr(oes); -} -#endif +#include "ingen-config.h" -#ifdef HAVE_SOUP -SharedPtr -new_http_interface(Ingen::Shared::World* world, - const std::string& url, - SharedPtr respond_to) -{ - SharedPtr receiver( - new Client::HTTPClientReceiver(world, url, respond_to)); - Client::HTTPEngineSender* hes = new Client::HTTPEngineSender( - world, url, receiver); - hes->attach(rand(), true); - return SharedPtr(hes); -} -#endif +using namespace Ingen; struct IngenClientModule : public Ingen::Shared::Module { void load(Ingen::Shared::World* world) { -#ifdef HAVE_LIBLO - world->add_interface_factory("osc.udp", &new_osc_interface); - world->add_interface_factory("osc.tcp", &new_osc_interface); -#endif -#ifdef HAVE_SOUP - world->add_interface_factory("http", &new_http_interface); -#endif } }; diff --git a/src/client/wscript b/src/client/wscript index 9047859a..29ac636d 100644 --- a/src/client/wscript +++ b/src/client/wscript @@ -9,7 +9,7 @@ def build(bld): target = 'ingen_client', install_path = '${LIBDIR}', use = 'libingen_shared') - autowaf.use_lib(bld, obj, 'GLIBMM LV2CORE LILV SUIL RAUL SORD SOUP SIGCPP LIBLO SOUP') + autowaf.use_lib(bld, obj, 'GLIBMM LV2CORE LILV SUIL RAUL SORD SIGCPP') obj.source = ''' ClientStore.cpp @@ -22,16 +22,3 @@ def build(bld): ThreadedSigClientInterface.cpp ingen_client.cpp ''' - - if bld.is_defined('HAVE_SOUP'): - obj.source += ''' - HTTPClientReceiver.cpp - HTTPEngineSender.cpp - ''' - - if bld.is_defined('HAVE_LIBLO'): - obj.source += ''' - OSCClientReceiver.cpp - OSCEngineSender.cpp - ''' - diff --git a/src/http/HTTPClientReceiver.cpp b/src/http/HTTPClientReceiver.cpp new file mode 100644 index 00000000..0ec5aaa4 --- /dev/null +++ b/src/http/HTTPClientReceiver.cpp @@ -0,0 +1,241 @@ +/* This file is part of Ingen. + * Copyright 2008-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include + +#include "ingen/shared/World.hpp" +#include "raul/log.hpp" + +#include "HTTPClientReceiver.hpp" + +#define LOG(s) s << "[HTTPClientReceiver] " + +using namespace std; +using namespace Raul; + +namespace Ingen { + +using namespace Serialisation; + +namespace Client { + +static SoupSession* client_session = NULL; +static HTTPClientReceiver* client_receiver = NULL; + +HTTPClientReceiver::HTTPClientReceiver( + Shared::World* world, + const std::string& url, + SharedPtr target) + : _target(target) + , _world(world) + , _url(url) +{ + start(false); + client_receiver = this; +} + +HTTPClientReceiver::~HTTPClientReceiver() +{ + stop(); + if (client_receiver == this) + client_receiver = NULL; +} + +HTTPClientReceiver::Listener::Listener(HTTPClientReceiver* receiver, const std::string& uri) + : _uri(uri) + , _receiver(receiver) +{ + const string port_str = uri.substr(uri.find_last_of(":")+1); + int port = atoi(port_str.c_str()); + + LOG(info) << "Client HTTP listen: " << uri << " (port " << port << ")" << endl; + + struct sockaddr_in servaddr; + + // Create listen address + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(port); + + // Create listen socket + if ((_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + LOG(error) << "Error creating listening socket: %s" << strerror(errno) << endl; + _sock = -1; + return; + } + + // Set remote address (FIXME: always localhost) + if (inet_aton("127.0.0.1", &servaddr.sin_addr) <= 0) { + LOG(error) << "Invalid remote IP address" << endl; + _sock = -1; + return; + } + + // Connect to server + if (connect(_sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { + LOG(error) << "Error calling connect: " << strerror(errno) << endl; + _sock = -1; + return; + } +} + +HTTPClientReceiver::Listener::~Listener() +{ + close(_sock); +} + +void +HTTPClientReceiver::send(SoupMessage* msg) +{ + if (!client_session) { + LOG(debug) << "Starting session" << endl; + client_session = soup_session_sync_new(); + } + + assert(SOUP_IS_MESSAGE(msg)); + soup_session_queue_message(client_session, msg, message_callback, client_receiver); +} + +void +HTTPClientReceiver::close_session() +{ + if (client_session) { + SoupSession* s = client_session; + client_session = NULL; + soup_session_abort(s); + } +} + +void +HTTPClientReceiver::update(const std::string& str) +{ + //LOG(info) << _world->parser()->parse_update(_world, _target.get(), str, _url); +} + +void +HTTPClientReceiver::Listener::_run() +{ + char in = '\0'; + char last = '\0'; + char llast = '\0'; + string recv; + + while (true) { + while (read(_sock, &in, 1) > 0 ) { + recv += in; + if (in == '\n' && last == '\n' && llast == '\n') { + if (!recv.empty()) { + _receiver->update(recv); + recv.clear(); + last = '\0'; + llast = '\0'; + } + break; + } + llast = last; + last = in; + } + } + + LOG(info) << "HTTP listener finished" << endl; +} + +void +HTTPClientReceiver::message_callback(SoupSession* session, SoupMessage* msg, void* ptr) +{ + if (ptr == NULL) + return; + + HTTPClientReceiver* me = (HTTPClientReceiver*)ptr; + const string path = soup_message_get_uri(msg)->path; + + if (msg->response_body->data == NULL) { + LOG(error) << "Empty client message" << endl; + return; + } + + if (path == "/") { + me->_target->response_ok(0); + + } else if (path == "/plugins") { + if (msg->response_body->data == NULL) { + LOG(error) << "Empty response" << endl; + } else { + Glib::Mutex::Lock lock(me->_mutex); + me->_target->response_ok(0); + me->_world->parser()->parse_string(me->_world, me->_target.get(), + Glib::ustring(msg->response_body->data), me->_url); + } + + } else if (path.substr(0, 6) == "/patch") { + if (msg->response_body->data == NULL) { + LOG(error) << "Empty response" << endl; + } else { + Glib::Mutex::Lock lock(me->_mutex); + me->_target->response_ok(0); + me->_world->parser()->parse_string( + me->_world, + me->_target.get(), + Glib::ustring(msg->response_body->data), + path); + } + + } else if (path == "/stream") { + if (msg->response_body->data == NULL) { + LOG(error) << "Empty response" << endl; + } else { + Glib::Mutex::Lock lock(me->_mutex); + string uri = string(soup_uri_to_string(soup_message_get_uri(msg), false)); + uri = uri.substr(0, uri.find_last_of(":")); + uri += string(":") + msg->response_body->data; + LOG(info) << "Stream URI: " << uri << endl; + me->_listener = boost::shared_ptr(new Listener(me, uri)); + me->_listener->start(); + } + + } else { + LOG(error) << "Unknown message: " << path << endl; + me->update(msg->response_body->data); + } +} + +void +HTTPClientReceiver::start(bool dump) +{ + if (!_world->parser()) + _world->load_module("serialisation"); + + SoupMessage* msg = soup_message_new("GET", (_url + "/stream").c_str()); + assert(SOUP_IS_MESSAGE(msg)); + soup_session_queue_message(client_session, msg, message_callback, this); +} + +void +HTTPClientReceiver::stop() +{ + //unregister_client(); + close_session(); +} + +} // namespace Client +} // namespace Ingen + diff --git a/src/http/HTTPClientReceiver.hpp b/src/http/HTTPClientReceiver.hpp new file mode 100644 index 00000000..d7165c81 --- /dev/null +++ b/src/http/HTTPClientReceiver.hpp @@ -0,0 +1,85 @@ +/* This file is part of Ingen. + * Copyright 2008-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef INGEN_CLIENT_HTTPCLIENTRECEIVER_HPP +#define INGEN_CLIENT_HTTPCLIENTRECEIVER_HPP + +#include + +#include +#include + +#include "ingen/ClientInterface.hpp" +#include "ingen/serialisation/Parser.hpp" +#include "raul/Deletable.hpp" +#include "raul/SharedPtr.hpp" +#include "raul/Thread.hpp" +#include "sord/sordmm.hpp" + +typedef struct _SoupSession SoupSession; +typedef struct _SoupMessage SoupMessage; + +namespace Ingen { +namespace Client { + +class HTTPClientReceiver : public boost::noncopyable, public Raul::Deletable +{ +public: + HTTPClientReceiver(Shared::World* world, + const std::string& url, + SharedPtr target); + + ~HTTPClientReceiver(); + + static void send(SoupMessage* msg); + static void close_session(); + + std::string uri() const { return _url; } + + void start(bool dump); + void stop(); + +private: + static void message_callback(SoupSession* session, SoupMessage* msg, void* ptr); + + void update(const std::string& str); + + class Listener : public Raul::Thread { + public: + Listener(HTTPClientReceiver* receiver, const std::string& uri); + ~Listener(); + void _run(); + private: + std::string _uri; + int _sock; + HTTPClientReceiver* _receiver; + }; + + friend class Listener; + + SharedPtr _listener; + Glib::Mutex _mutex; + SharedPtr _target; + Shared::World* _world; + const std::string _url; + bool _quit_flag; +}; + +} // namespace Client +} // namespace Ingen + +#endif // INGEN_CLIENT_HTTPCLIENTRECEIVER_HPP diff --git a/src/http/HTTPClientSender.hpp b/src/http/HTTPClientSender.hpp index 116f0601..761a60a6 100644 --- a/src/http/HTTPClientSender.hpp +++ b/src/http/HTTPClientSender.hpp @@ -24,7 +24,8 @@ #include "raul/Thread.hpp" #include "ingen/ClientInterface.hpp" -#include "../shared/HTTPSender.hpp" + +#include "HTTPSender.hpp" namespace Ingen { diff --git a/src/http/HTTPEngineSender.cpp b/src/http/HTTPEngineSender.cpp new file mode 100644 index 00000000..43a3d44c --- /dev/null +++ b/src/http/HTTPEngineSender.cpp @@ -0,0 +1,194 @@ +/* This file is part of Ingen. + * Copyright 2008-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "raul/AtomRDF.hpp" +#include "raul/log.hpp" +#include "sord/sordmm.hpp" + +#include "ingen/shared/World.hpp" +#include "HTTPEngineSender.hpp" +#include "HTTPClientReceiver.hpp" + +#define LOG(s) s << "[HTTPEngineSender] " + +using namespace std; +using namespace Raul; + +namespace Ingen { + +using namespace Shared; + +namespace Client { + +HTTPEngineSender::HTTPEngineSender(World* world, + const URI& engine_url, + SharedPtr receiver) + : _receiver(receiver) + , _world(*world->rdf_world()) + , _engine_url(engine_url) + , _id(0) + , _enabled(true) +{ + _session = soup_session_sync_new(); +} + +HTTPEngineSender::~HTTPEngineSender() +{ + soup_session_abort(_session); +} + +void +HTTPEngineSender::attach(int32_t ping_id, bool block) +{ + LOG(debug) << "Attaching to " << _engine_url << endl; + SoupMessage* msg = soup_message_new ("GET", _engine_url.c_str()); + HTTPClientReceiver::send(msg); +} + +/* *** ServerInterface implementation below here *** */ + +/** Register with the engine via HTTP. + * + * Note that this does not actually use 'key', since the engine creates + * it's own key for HTTP clients (namely the incoming URL), for NAT + * traversal. It is a parameter to remain compatible with ServerInterface. + */ +void +HTTPEngineSender::register_client(ClientInterface* client) +{ + /*SoupMessage* msg = soup_message_new("GET", (_engine_url.str() + "/stream").c_str()); + HTTPClientReceiver::send(msg);*/ +} + +void +HTTPEngineSender::unregister_client(const URI& uri) +{ +} + +// Object commands + +void +HTTPEngineSender::put(const URI& uri, + const Resource::Properties& properties, + Resource::Graph ctx) +{ + const string path = (uri.substr(0, 6) == "path:/") ? uri.substr(6) : uri.str(); + const string full_uri = _engine_url.str() + "/" + path; + + Sord::Model model(_world); + for (Resource::Properties::const_iterator i = properties.begin(); i != properties.end(); ++i) + model.add_statement(Sord::URI(_world, path), + AtomRDF::atom_to_node(model, i->first), + AtomRDF::atom_to_node(model, i->second)); + + const string str = model.write_to_string(""); + SoupMessage* msg = soup_message_new(SOUP_METHOD_PUT, full_uri.c_str()); + assert(msg); + soup_message_set_request(msg, "application/x-turtle", SOUP_MEMORY_COPY, str.c_str(), str.length()); + soup_session_send_message(_session, msg); +} + +void +HTTPEngineSender::delta(const Raul::URI& path, + const Resource::Properties& remove, + const Resource::Properties& add) +{ + LOG(warn) << "TODO: HTTP delta" << endl; +} + +void +HTTPEngineSender::move(const Path& old_path, + const Path& new_path) +{ + SoupMessage* msg = soup_message_new(SOUP_METHOD_MOVE, + (_engine_url.str() + old_path.str()).c_str()); + soup_message_headers_append(msg->request_headers, "Destination", + (_engine_url.str() + new_path.str()).c_str()); + soup_session_send_message(_session, msg); +} + +void +HTTPEngineSender::del(const URI& uri) +{ + const string path = (uri.substr(0, 6) == "path:/") ? uri.substr(6) : uri.str(); + const string full_uri = _engine_url.str() + "/" + path; + SoupMessage* msg = soup_message_new(SOUP_METHOD_DELETE, full_uri.c_str()); + soup_session_send_message(_session, msg); +} + +void +HTTPEngineSender::connect(const Path& src_port_path, + const Path& dst_port_path) +{ + LOG(warn) << "TODO: HTTP connect" << endl; +} + +void +HTTPEngineSender::disconnect(const URI& src, + const URI& dst) +{ + LOG(warn) << "TODO: HTTP disconnect" << endl; +} + +void +HTTPEngineSender::disconnect_all(const Path& parent_patch_path, + const Path& path) +{ + LOG(warn) << "TODO: HTTP disconnect_all" << endl; +} + +void +HTTPEngineSender::set_property(const URI& subject, + const URI& predicate, + const Atom& value) +{ + Resource::Properties prop; + prop.insert(make_pair(predicate, value)); + put(subject, prop); +} + +// Requests // + +void +HTTPEngineSender::ping() +{ + LOG(debug) << "Ping " << _engine_url << endl; + get(_engine_url); +} + +void +HTTPEngineSender::get(const URI& uri) +{ + if (!Raul::Path::is_path(uri) && uri.scheme() != "http") { + LOG(warn) << "Ignoring GET of non-HTTP URI " << uri << endl; + return; + } + + const std::string request_uri = (Raul::Path::is_path(uri)) + ?_engine_url.str() + "/patch" + uri.substr(uri.find("/")) + : uri.str(); + cout << "Get " << request_uri << endl; + LOG(debug) << "Get " << request_uri << endl; + SoupMessage* msg = soup_message_new("GET", request_uri.c_str()); + HTTPClientReceiver::send(msg); +} + +} // namespace Client +} // namespace Ingen + diff --git a/src/http/HTTPEngineSender.hpp b/src/http/HTTPEngineSender.hpp new file mode 100644 index 00000000..14439e39 --- /dev/null +++ b/src/http/HTTPEngineSender.hpp @@ -0,0 +1,126 @@ +/* This file is part of Ingen. + * Copyright 2008-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef INGEN_CLIENT_HTTPENGINESENDER_HPP +#define INGEN_CLIENT_HTTPENGINESENDER_HPP + +#include + +#include + +#include "raul/Deletable.hpp" +#include "raul/Path.hpp" +#include "sord/sordmm.hpp" + +#include "ingen/ServerInterface.hpp" + +typedef struct _SoupSession SoupSession; + +namespace Ingen { + +namespace Shared { class World; } + +namespace Client { + +class HTTPClientReceiver; + +/* HTTP (via libsoup) interface to the engine. + * + * Clients can use this opaquely as an ServerInterface to control the engine + * over HTTP (whether over a network or not). + * + * \ingroup IngenClient + */ +class HTTPEngineSender : public ServerInterface +{ +public: + HTTPEngineSender(Shared::World* world, + const Raul::URI& engine_url, + SharedPtr receiver); + + ~HTTPEngineSender(); + + Raul::URI uri() const { return _engine_url; } + + inline int32_t next_id() + { int32_t ret = (_id == -1) ? -1 : _id++; return ret; } + + void respond_to(ClientInterface* client, int32_t id) { _id = id; } + void disable_responses() { _id = -1; } + + void attach(int32_t ping_id, bool block); + + /* *** ServerInterface implementation below here *** */ + + void enable() { _enabled = true; } + void disable() { _enabled = false; } + + void bundle_begin() {} + void bundle_end() {} + + // Client registration + void register_client(ClientInterface* client); + void unregister_client(const Raul::URI& uri); + + // Object commands + + virtual void put(const Raul::URI& path, + const Resource::Properties& properties, + Resource::Graph ctx=Resource::DEFAULT); + + virtual void delta(const Raul::URI& path, + const Resource::Properties& remove, + const Resource::Properties& add); + + virtual void del(const Raul::URI& uri); + + virtual void move(const Raul::Path& old_path, + const Raul::Path& new_path); + + virtual void connect(const Raul::Path& src_port_path, + const Raul::Path& dst_port_path); + + virtual void disconnect(const Raul::URI& src, + const Raul::URI& dst); + + virtual void disconnect_all(const Raul::Path& parent_patch_path, + const Raul::Path& path); + + virtual void set_property(const Raul::URI& subject, + const Raul::URI& predicate, + const Raul::Atom& value); + + // Requests // + void ping(); + void get(const Raul::URI& uri); + +protected: + SharedPtr _receiver; + + SoupSession* _session; + Sord::World& _world; + const Raul::URI _engine_url; + int _client_port; + int32_t _id; + bool _enabled; +}; + +} // namespace Client +} // namespace Ingen + +#endif // INGEN_CLIENT_HTTPENGINESENDER_HPP + diff --git a/src/http/HTTPSender.cpp b/src/http/HTTPSender.cpp new file mode 100644 index 00000000..1a4d35da --- /dev/null +++ b/src/http/HTTPSender.cpp @@ -0,0 +1,156 @@ +/* This file is part of Ingen. + * Copyright 2008-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "raul/log.hpp" +#include "HTTPSender.hpp" + +using namespace std; +using namespace Raul; + +namespace Ingen { +namespace Shared { + +HTTPSender::HTTPSender() + : _listen_port(-1) + , _listen_sock(-1) + , _client_sock(-1) + , _send_state(Immediate) +{ + Thread::set_name("HTTPSender"); + + struct sockaddr_in addr; + + // Create listen address + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + // Create listen socket + if ((_listen_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) { + error << "Error creating listening socket (" << strerror(errno) << ")" << endl; + exit(EXIT_FAILURE); + } + + // Bind our socket addresss to the listening socket + if (bind(_listen_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + error << "Error calling bind (%s)\n" << strerror(errno) << ")" << endl; + _listen_sock = -1; + } + + // Find port number + socklen_t length = sizeof(addr); + if (getsockname(_listen_sock, (struct sockaddr*)&addr, &length) == -1) { + error << "Error calling getsockname (" << strerror(errno) << ")" << endl; + _listen_sock = -1; + return; + } + + if (listen(_listen_sock, 1) < 0 ) { + error << "Error calling listen (" << strerror(errno) << ")" << endl; + _listen_sock = -1; + return; + } + + _listen_port = ntohs(addr.sin_port); + info << "Opening event stream on TCP port " << _listen_port << endl; + start(); +} + +HTTPSender::~HTTPSender() +{ + stop(); + if (_listen_sock != -1) + close(_listen_sock); + if (_client_sock != -1) + close(_client_sock); +} + +void +HTTPSender::_run() +{ + if (_listen_sock == -1) { + error << "Unable to open socket, exiting sender thread" << endl; + return; + } + + // Accept connection + if ((_client_sock = accept(_listen_sock, NULL, NULL) ) < 0) { + error << "Error calling accept: " << strerror(errno) << endl; + return; + } + + // Hold connection open and write when signalled + while (true) { + _mutex.lock(); + _signal.wait(_mutex); + + write(_client_sock, _transfer.c_str(), _transfer.length()); + write(_client_sock, "\n\n\n", 3); + + _signal.broadcast(); + _mutex.unlock(); + } + + close(_listen_sock); + _listen_sock = -1; +} + +void +HTTPSender::bundle_begin() +{ + _mutex.lock(); + _send_state = SendingBundle; + _transfer = ""; +} + +void +HTTPSender::bundle_end() +{ + assert(_send_state == SendingBundle); + _signal.broadcast(); + _signal.wait(_mutex); + _send_state = Immediate; + _mutex.unlock(); +} + +void +HTTPSender::send_chunk(const std::string& buf) +{ + if (_send_state == Immediate) { + _mutex.lock(); + _transfer = buf; + _signal.broadcast(); + _signal.wait(_mutex); + _mutex.unlock(); + } else { + _transfer.append(buf); + } +} + +} // namespace Shared +} // namespace Ingen diff --git a/src/http/HTTPSender.hpp b/src/http/HTTPSender.hpp new file mode 100644 index 00000000..a1a3ea2a --- /dev/null +++ b/src/http/HTTPSender.hpp @@ -0,0 +1,61 @@ +/* This file is part of Ingen. + * Copyright 2008-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef INGEN_SHARED_HTTPSENDER_HPP +#define INGEN_SHARED_HTTPSENDER_HPP + +#include + +#include + +#include "raul/Thread.hpp" + +namespace Ingen { +namespace Shared { + +class HTTPSender : public Raul::Thread { +public: + HTTPSender(); + virtual ~HTTPSender(); + + void bundle_begin(); + void bundle_end(); + + int listen_port() const { return _listen_port; } + +protected: + void _run(); + + void send_chunk(const std::string& buf); + + enum SendState { Immediate, SendingBundle }; + + Glib::Mutex _mutex; + Glib::Cond _signal; + + int _listen_port; + int _listen_sock; + int _client_sock; + SendState _send_state; + std::string _transfer; +}; + +} // namespace Shared +} // namespace Ingen + +#endif // INGEN_SHARED_HTTPSENDER_HPP + diff --git a/src/http/ingen_http.cpp b/src/http/ingen_http.cpp deleted file mode 100644 index 0a08f59b..00000000 --- a/src/http/ingen_http.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "ingen/shared/Module.hpp" -#include "ingen/shared/World.hpp" - -#include "../server/Engine.hpp" -#include "../server/ServerInterfaceImpl.hpp" - -#include "HTTPEngineReceiver.hpp" - -using namespace std; -using namespace Ingen; - -struct IngenHTTPModule : public Ingen::Shared::Module { - void load(Ingen::Shared::World* world) { - Server::Engine* engine = (Server::Engine*)world->local_engine().get(); - SharedPtr interface( - new Server::ServerInterfaceImpl(*engine)); - - receiver = SharedPtr( - new Server::HTTPEngineReceiver( - *engine, - interface, - world->conf()->option("engine-port").get_int32())); - engine->add_event_source(interface); - } - - SharedPtr receiver; -}; - -extern "C" { - -Ingen::Shared::Module* -ingen_module_load() -{ - return new IngenHTTPModule(); -} - -} // extern "C" diff --git a/src/http/ingen_http_server.cpp b/src/http/ingen_http_server.cpp new file mode 100644 index 00000000..0a08f59b --- /dev/null +++ b/src/http/ingen_http_server.cpp @@ -0,0 +1,54 @@ +/* This file is part of Ingen. + * Copyright 2007-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ingen/shared/Module.hpp" +#include "ingen/shared/World.hpp" + +#include "../server/Engine.hpp" +#include "../server/ServerInterfaceImpl.hpp" + +#include "HTTPEngineReceiver.hpp" + +using namespace std; +using namespace Ingen; + +struct IngenHTTPModule : public Ingen::Shared::Module { + void load(Ingen::Shared::World* world) { + Server::Engine* engine = (Server::Engine*)world->local_engine().get(); + SharedPtr interface( + new Server::ServerInterfaceImpl(*engine)); + + receiver = SharedPtr( + new Server::HTTPEngineReceiver( + *engine, + interface, + world->conf()->option("engine-port").get_int32())); + engine->add_event_source(interface); + } + + SharedPtr receiver; +}; + +extern "C" { + +Ingen::Shared::Module* +ingen_module_load() +{ + return new IngenHTTPModule(); +} + +} // extern "C" diff --git a/src/ingen/main.cpp b/src/ingen/main.cpp index cb76f778..62c2b757 100644 --- a/src/ingen/main.cpp +++ b/src/ingen/main.cpp @@ -134,12 +134,12 @@ main(int argc, char** argv) // Not loading a GUI, load network engine interfaces if (!conf.option("gui").get_bool()) { #ifdef HAVE_LIBLO - ingen_try(world->load_module("osc"), - "Unable to load OSC module"); + ingen_try(world->load_module("osc_server"), + "Unable to load OSC server module"); #endif #ifdef HAVE_SOUP - ingen_try(world->load_module("http"), - "Unable to load HTTP module"); + ingen_try(world->load_module("http_server"), + "Unable to load HTTP server module"); #endif } } @@ -148,6 +148,15 @@ main(int argc, char** argv) if (!engine_interface) { ingen_try(world->load_module("client"), "Unable to load client module"); + #ifdef HAVE_LIBLO + ingen_try(world->load_module("osc_client"), + "Unable to load OSC client module"); + #endif + #ifdef HAVE_SOUP + ingen_try(world->load_module("http_client"), + "Unable to load HTTP client module"); + #endif + const char* const uri = conf.option("connect").get_string(); ingen_try((engine_interface = world->interface(uri, SharedPtr())), (string("Unable to create interface to `") + uri + "'").c_str()); diff --git a/src/osc/OSCClientReceiver.cpp b/src/osc/OSCClientReceiver.cpp new file mode 100644 index 00000000..4fef1d1c --- /dev/null +++ b/src/osc/OSCClientReceiver.cpp @@ -0,0 +1,303 @@ +/* This file is part of Ingen. + * Copyright 2007-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "raul/log.hpp" +#include "raul/AtomLiblo.hpp" +#include "raul/Path.hpp" + +#include "ingen-config.h" +#include "OSCClientReceiver.hpp" + +#define LOG(s) s << "[OSCClientReceiver] " + +using namespace std; +using namespace Raul; + +namespace Ingen { +namespace Client { + +OSCClientReceiver::OSCClientReceiver(int listen_port, + SharedPtr target) + : _target(target) + , _st(NULL) + , _listen_port(listen_port) +{ +#ifdef RAUL_LOG_DEBUG + start(true); +#else + start(false); // true = dump, false = shutup +#endif +} + +OSCClientReceiver::~OSCClientReceiver() +{ + stop(); +} + +void +OSCClientReceiver::start(bool dump_osc) +{ + if (_st != NULL) + return; + + // Attempt preferred port + if (_listen_port != 0) { + char port_str[8]; + snprintf(port_str, 8, "%d", _listen_port); + _st = lo_server_thread_new(port_str, lo_error_cb); + } + + // Find a free port + if (!_st) { + _st = lo_server_thread_new(NULL, lo_error_cb); + _listen_port = lo_server_thread_get_port(_st); + } + + if (_st == NULL) { + LOG(error) << "Could not start OSC listener. Aborting." << endl; + exit(EXIT_FAILURE); + } else { + LOG(info) << "Started OSC listener on port " << lo_server_thread_get_port(_st) << endl; + } + + // Print all incoming messages + if (dump_osc) + lo_server_thread_add_method(_st, NULL, NULL, generic_cb, NULL); + + setup_callbacks(); + + // Display any uncaught messages to the console + //lo_server_thread_add_method(_st, NULL, NULL, unknown_cb, NULL); + + lo_server_thread_start(_st); +} + +void +OSCClientReceiver::stop() +{ + if (_st != NULL) { + //unregister_client(); + lo_server_thread_free(_st); + _st = NULL; + } +} + +int +OSCClientReceiver::generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data) +{ + printf("[OSCClientReceiver] %s (%s)\t", path, types); + + for (int i=0; i < argc; ++i) { + lo_arg_pp(lo_type(types[i]), argv[i]); + printf("\t"); + } + printf("\n"); + + return 1; // not handled +} + +void +OSCClientReceiver::lo_error_cb(int num, const char* msg, const char* path) +{ + LOG(error) << "Got error from server: " << msg << endl; +} + +int +OSCClientReceiver::unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data) +{ + std::string msg = "Received unknown OSC message: "; + msg += path; + + LOG(error) << msg << endl; + + return 0; +} + +void +OSCClientReceiver::setup_callbacks() +{ + if (!_target) + return; + + lo_server_thread_add_method(_st, "/ok", "i", response_ok_cb, this); + lo_server_thread_add_method(_st, "/error", "is", response_error_cb, this); + lo_server_thread_add_method(_st, "/plugin", "sss", plugin_cb, this); + lo_server_thread_add_method(_st, "/put", NULL, put_cb, this); + lo_server_thread_add_method(_st, "/delta_begin", NULL, delta_begin_cb, this); + lo_server_thread_add_method(_st, "/delta_remove", NULL, delta_remove_cb, this); + lo_server_thread_add_method(_st, "/delta_add", NULL, delta_add_cb, this); + lo_server_thread_add_method(_st, "/delta_end", NULL, delta_end_cb, this); + lo_server_thread_add_method(_st, "/move", "ss", move_cb, this); + lo_server_thread_add_method(_st, "/delete", "s", del_cb, this); + lo_server_thread_add_method(_st, "/connect", "ss", connection_cb, this); + lo_server_thread_add_method(_st, "/disconnect", "ss", disconnection_cb, this); + lo_server_thread_add_method(_st, "/set_property", NULL, set_property_cb, this); + lo_server_thread_add_method(_st, "/activity", "sT", activity_cb, this); + lo_server_thread_add_method(_st, "/activity", "sf", activity_cb, this); +} + +/** Catches errors that aren't a direct result of a client request. + */ +int +OSCClientReceiver::_error_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + _target->error((char*)argv[0]); + return 0; +} + +int +OSCClientReceiver::_del_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + _target->del((const char*)&argv[0]->s); + return 0; +} + +int +OSCClientReceiver::_put_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* obj_path = &argv[0]->s; + const char* ctx = &argv[1]->s; + Resource::Properties prop; + for (int i = 2; i < argc-1; i += 2) + prop.insert(make_pair(&argv[i]->s, + AtomLiblo::lo_arg_to_atom(types[i+1], argv[i+1]))); + _target->put(obj_path, prop, Resource::uri_to_graph(ctx)); + return 0; +} + +int +OSCClientReceiver::_delta_begin_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* obj_path = &argv[0]->s; + assert(_delta_remove.empty()); + assert(_delta_add.empty()); + _delta_uri = obj_path; + return 0; +} + +int +OSCClientReceiver::_delta_remove_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + _delta_remove.insert(make_pair(&argv[0]->s, + AtomLiblo::lo_arg_to_atom(types[1], argv[1]))); + return 0; +} + +int +OSCClientReceiver::_delta_add_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + _delta_add.insert(make_pair(&argv[0]->s, + AtomLiblo::lo_arg_to_atom(types[1], argv[1]))); + return 0; +} + +int +OSCClientReceiver::_delta_end_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + _target->delta(_delta_uri, _delta_remove, _delta_add); + _delta_uri = Raul::URI(); + _delta_remove.clear(); + _delta_add.clear(); + return 0; +} + +int +OSCClientReceiver::_move_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* old_path = &argv[1]->s; + const char* new_path = &argv[2]->s; + + _target->move(old_path, new_path); + return 0; +} + +int +OSCClientReceiver::_connection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* const src_port_path = &argv[0]->s; + const char* const dst_port_path = &argv[1]->s; + + _target->connect(src_port_path, dst_port_path); + + return 0; +} + +int +OSCClientReceiver::_disconnection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* src_uri = &argv[0]->s; + const char* dst_uri = &argv[1]->s; + + _target->disconnect(src_uri, dst_uri); + + return 0; +} + +/** Notification of a new or updated property. + */ +int +OSCClientReceiver::_set_property_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + if (argc != 3 || types[0] != 's' || types[1] != 's') + return 1; + + const char* obj_uri = &argv[0]->s; + const char* key = &argv[1]->s; + + Atom value = AtomLiblo::lo_arg_to_atom(types[2], argv[2]); + + _target->set_property(obj_uri, key, value); + + return 0; +} + +int +OSCClientReceiver::_activity_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* const port_path = &argv[0]->s; + + Atom value = AtomLiblo::lo_arg_to_atom(types[1], argv[1]); + + _target->activity(port_path, value); + + return 0; +} + +int +OSCClientReceiver::_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + assert(!strcmp(types, "i")); + _target->response_ok(argv[0]->i); + + return 0; +} + +int +OSCClientReceiver::_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + assert(!strcmp(types, "is")); + _target->response_error(argv[0]->i, &argv[1]->s); + + return 0; +} + +} // namespace Client +} // namespace Ingen diff --git a/src/osc/OSCClientReceiver.hpp b/src/osc/OSCClientReceiver.hpp new file mode 100644 index 00000000..46afc81a --- /dev/null +++ b/src/osc/OSCClientReceiver.hpp @@ -0,0 +1,90 @@ +/* This file is part of Ingen. + * Copyright 2007-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef INGEN_CLIENT_OSCCLIENTRECEIVER_HPP +#define INGEN_CLIENT_OSCCLIENTRECEIVER_HPP + +#include + +#include +#include + +#include "ingen/ClientInterface.hpp" +#include "raul/Deletable.hpp" +#include "raul/SharedPtr.hpp" + +#include "macros.h" + +namespace Ingen { +namespace Client { + +/** Client-side receiver for OSC messages from the engine. + * + * \ingroup IngenClient + */ +class OSCClientReceiver : public boost::noncopyable, public Raul::Deletable +{ +public: + OSCClientReceiver(int listen_port, SharedPtr target); + ~OSCClientReceiver(); + + std::string uri() const { return lo_server_thread_get_url(_st); } + + void start(bool dump_osc); + void stop(); + + int listen_port() { return _listen_port; } + std::string listen_url() { return lo_server_thread_get_url(_st); } + +private: + void setup_callbacks(); + + static void lo_error_cb(int num, const char* msg, const char* path); + + static int generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data); + static int unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* osc_receiver); + + SharedPtr _target; + lo_server_thread _st; + Raul::URI _delta_uri; + Resource::Properties _delta_remove; + Resource::Properties _delta_add; + int _listen_port; + + LO_HANDLER(OSCClientReceiver, error); + LO_HANDLER(OSCClientReceiver, response_ok); + LO_HANDLER(OSCClientReceiver, response_error); + LO_HANDLER(OSCClientReceiver, plugin); + LO_HANDLER(OSCClientReceiver, plugin_list_end); + LO_HANDLER(OSCClientReceiver, new_patch); + LO_HANDLER(OSCClientReceiver, del); + LO_HANDLER(OSCClientReceiver, move); + LO_HANDLER(OSCClientReceiver, connection); + LO_HANDLER(OSCClientReceiver, disconnection); + LO_HANDLER(OSCClientReceiver, put); + LO_HANDLER(OSCClientReceiver, delta_begin); + LO_HANDLER(OSCClientReceiver, delta_remove); + LO_HANDLER(OSCClientReceiver, delta_add); + LO_HANDLER(OSCClientReceiver, delta_end); + LO_HANDLER(OSCClientReceiver, set_property); + LO_HANDLER(OSCClientReceiver, activity); +}; + +} // namespace Client +} // namespace Ingen + +#endif // INGEN_CLIENT_OSCCLIENTRECEIVER_HPP diff --git a/src/osc/OSCClientSender.hpp b/src/osc/OSCClientSender.hpp index ffc3b202..c391e54a 100644 --- a/src/osc/OSCClientSender.hpp +++ b/src/osc/OSCClientSender.hpp @@ -25,7 +25,8 @@ #include "ingen/ClientInterface.hpp" #include "ingen/GraphObject.hpp" -#include "../shared/OSCSender.hpp" + +#include "OSCSender.hpp" namespace Ingen { diff --git a/src/osc/OSCEngineReceiver.hpp b/src/osc/OSCEngineReceiver.hpp index fe16ac1a..72388bc2 100644 --- a/src/osc/OSCEngineReceiver.hpp +++ b/src/osc/OSCEngineReceiver.hpp @@ -28,6 +28,7 @@ #include "ingen/Resource.hpp" #include "ingen-config.h" +#include "macros.h" namespace Ingen { @@ -37,17 +38,6 @@ namespace Server { class Engine; -/* Some boilerplate killing macros... */ -#define LO_HANDLER_ARGS const char* path, const char* types, lo_arg** argv, int argc, lo_message msg - -/* Defines a static handler to be passed to lo_add_method, which is a trivial - * wrapper around a non-static method that does the real work. Makes a whoole - * lot of ugly boiler plate go away */ -#define LO_HANDLER(name) \ -int _##name##_cb (LO_HANDLER_ARGS);\ -inline static int name##_cb(LO_HANDLER_ARGS, void* myself)\ -{ return ((OSCEngineReceiver*)myself)->_##name##_cb(path, types, argv, argc, msg); } - /* FIXME: Make this receive and preprocess in the same thread? */ /** Receive OSC messages and call interface functions. @@ -96,28 +86,28 @@ private: static int generic_cb(LO_HANDLER_ARGS, void* myself); static int unknown_cb(LO_HANDLER_ARGS, void* myself); - LO_HANDLER(quit); - LO_HANDLER(ping); - LO_HANDLER(ping_slow); - LO_HANDLER(register_client); - LO_HANDLER(unregister_client); - LO_HANDLER(get); - LO_HANDLER(put); - LO_HANDLER(delta_begin); - LO_HANDLER(delta_remove); - LO_HANDLER(delta_add); - LO_HANDLER(delta_end); - LO_HANDLER(move); - LO_HANDLER(del); - LO_HANDLER(connect); - LO_HANDLER(disconnect); - LO_HANDLER(disconnect_all); - LO_HANDLER(note_on); - LO_HANDLER(note_off); - LO_HANDLER(all_notes_off); - LO_HANDLER(learn); - LO_HANDLER(set_property); - LO_HANDLER(property_set); + LO_HANDLER(OSCEngineReceiver, quit); + LO_HANDLER(OSCEngineReceiver, ping); + LO_HANDLER(OSCEngineReceiver, ping_slow); + LO_HANDLER(OSCEngineReceiver, register_client); + LO_HANDLER(OSCEngineReceiver, unregister_client); + LO_HANDLER(OSCEngineReceiver, get); + LO_HANDLER(OSCEngineReceiver, put); + LO_HANDLER(OSCEngineReceiver, delta_begin); + LO_HANDLER(OSCEngineReceiver, delta_remove); + LO_HANDLER(OSCEngineReceiver, delta_add); + LO_HANDLER(OSCEngineReceiver, delta_end); + LO_HANDLER(OSCEngineReceiver, move); + LO_HANDLER(OSCEngineReceiver, del); + LO_HANDLER(OSCEngineReceiver, connect); + LO_HANDLER(OSCEngineReceiver, disconnect); + LO_HANDLER(OSCEngineReceiver, disconnect_all); + LO_HANDLER(OSCEngineReceiver, note_on); + LO_HANDLER(OSCEngineReceiver, note_off); + LO_HANDLER(OSCEngineReceiver, all_notes_off); + LO_HANDLER(OSCEngineReceiver, learn); + LO_HANDLER(OSCEngineReceiver, set_property); + LO_HANDLER(OSCEngineReceiver, property_set); Engine& _engine; SharedPtr _interface; diff --git a/src/osc/OSCEngineSender.cpp b/src/osc/OSCEngineSender.cpp new file mode 100644 index 00000000..e2436af7 --- /dev/null +++ b/src/osc/OSCEngineSender.cpp @@ -0,0 +1,241 @@ +/* This file is part of Ingen. + * Copyright 2007-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "raul/log.hpp" +#include "raul/AtomLiblo.hpp" +#include "raul/Path.hpp" + +#include "ingen/Patch.hpp" +#include "ingen/Port.hpp" +#include "ingen/Plugin.hpp" + +#include "OSCEngineSender.hpp" + +#define LOG(s) s << "[OSCEngineSender] " + +using namespace std; +using namespace Raul; + +namespace Ingen { +namespace Client { + +/** Note the sending port is implicitly set by liblo, lo_send by default sends + * from the most recently created server, so create the OSC listener before + * this to have it all happen on the same port. Yeah, this is a big magic :/ + */ +OSCEngineSender::OSCEngineSender(const URI& engine_url, + size_t max_packet_size, + SharedPtr receiver) + : Shared::OSCSender(max_packet_size) + , _receiver(receiver) + , _engine_url(engine_url) + , _id(0) +{ + _address = lo_address_new_from_url(engine_url.c_str()); +} + +OSCEngineSender::~OSCEngineSender() +{ + lo_address_free(_address); +} + +/** Attempt to connect to the engine (by pinging it). + * + * This doesn't register a client (or otherwise affect the client/engine state). + * To check for success wait for the ping response with id @a ping_id (using the + * relevant OSCClientReceiver). + * + * Passing a client_port of 0 will automatically choose a free port. If the + * @a block parameter is true, this function will not return until a connection + * has successfully been made. + */ +void +OSCEngineSender::attach(int32_t ping_id, bool block) +{ + if (!_address) + _address = lo_address_new_from_url(_engine_url.c_str()); + + if (_address == NULL) { + LOG(error) << "Unable to connect to " << _engine_url << endl; + exit(EXIT_FAILURE); + } + + LOG(info) << "Attempting to contact engine at " << _engine_url << " ..." << endl; + + _id = ping_id; + this->ping(); +} + +/* *** ServerInterface implementation below here *** */ + +/** Register with the engine via OSC. + * + * Note that this does not actually use 'client', since the engine creates + * it's own key for OSC clients (namely the incoming URL), for NAT + * traversal. It is a parameter to remain compatible with ServerInterface. + */ +void +OSCEngineSender::register_client(ClientInterface* client) +{ + send("/register_client", "i", next_id(), LO_ARGS_END); +} + +void +OSCEngineSender::unregister_client(const URI& uri) +{ + send("/unregister_client", "i", next_id(), LO_ARGS_END); +} + +// Object commands + +void +OSCEngineSender::put(const Raul::URI& path, + const Resource::Properties& properties, + Resource::Graph ctx) +{ + typedef Resource::Properties::const_iterator iterator; + lo_message m = lo_message_new(); + lo_message_add_int32(m, next_id()); + lo_message_add_string(m, path.c_str()); + lo_message_add_string(m, Resource::graph_to_uri(ctx).c_str()); + for (iterator i = properties.begin(); i != properties.end(); ++i) { + lo_message_add_string(m, i->first.c_str()); + Raul::AtomLiblo::lo_message_add_atom(m, i->second); + } + send_message("/put", m); +} + +void +OSCEngineSender::delta(const Raul::URI& path, + const Resource::Properties& remove, + const Resource::Properties& add) +{ + typedef Resource::Properties::const_iterator iterator; + + const bool bundle = !_bundle; + if (bundle) + bundle_begin(); + + const int32_t id = next_id(); + send("/delta_begin", "is", id, path.c_str(), LO_ARGS_END); + + for (iterator i = remove.begin(); i != remove.end(); ++i) { + lo_message m = lo_message_new(); + lo_message_add_string(m, i->first.c_str()); + Raul::AtomLiblo::lo_message_add_atom(m, i->second); + send_message("/delta_remove", m); + } + + for (iterator i = add.begin(); i != add.end(); ++i) { + lo_message m = lo_message_new(); + lo_message_add_string(m, i->first.c_str()); + Raul::AtomLiblo::lo_message_add_atom(m, i->second); + send_message("/delta_add", m); + } + + send("/delta_end", "i", id, LO_ARGS_END); + + if (bundle) + bundle_end(); +} + +void +OSCEngineSender::move(const Path& old_path, + const Path& new_path) +{ + send("/move", "iss", + next_id(), + old_path.c_str(), + new_path.c_str(), + LO_ARGS_END); +} + +void +OSCEngineSender::del(const URI& uri) +{ + send("/delete", "is", + next_id(), + uri.c_str(), + LO_ARGS_END); +} + +void +OSCEngineSender::connect(const Path& src_port_path, + const Path& dst_port_path) +{ + send("/connect", "iss", + next_id(), + src_port_path.c_str(), + dst_port_path.c_str(), + LO_ARGS_END); +} + +void +OSCEngineSender::disconnect(const URI& src, + const URI& dst) +{ + send("/disconnect", "iss", + next_id(), + src.c_str(), + dst.c_str(), + LO_ARGS_END); +} + +void +OSCEngineSender::disconnect_all(const Path& parent_patch_path, + const Path& path) +{ + send("/disconnect_all", "iss", + next_id(), + parent_patch_path.c_str(), + path.c_str(), + LO_ARGS_END); +} + +void +OSCEngineSender::set_property(const URI& subject, + const URI& predicate, + const Atom& value) +{ + lo_message m = lo_message_new(); + lo_message_add_int32(m, next_id()); + lo_message_add_string(m, subject.c_str()); + lo_message_add_string(m, predicate.c_str()); + Raul::AtomLiblo::lo_message_add_atom(m, value); + send_message("/set_property", m); +} + +// Requests // + +void +OSCEngineSender::ping() +{ + send("/ping", "i", next_id(), LO_ARGS_END); +} + +void +OSCEngineSender::get(const URI& uri) +{ + send("/get", "is", + next_id(), + uri.c_str(), + LO_ARGS_END); +} + +} // namespace Client +} // namespace Ingen + diff --git a/src/osc/OSCEngineSender.hpp b/src/osc/OSCEngineSender.hpp new file mode 100644 index 00000000..5aeeed7b --- /dev/null +++ b/src/osc/OSCEngineSender.hpp @@ -0,0 +1,118 @@ +/* This file is part of Ingen. + * Copyright 2007-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef INGEN_CLIENT_OSCENGINESENDER_HPP +#define INGEN_CLIENT_OSCENGINESENDER_HPP + +#include + +#include + +#include + +#include "raul/Deletable.hpp" + +#include "ingen/ServerInterface.hpp" + +#include "OSCSender.hpp" + +namespace Ingen { + +namespace Client { + +/* OSC (via liblo) interface to the engine. + * + * Clients can use this opaquely as an ServerInterface* to control the engine + * over OSC (whether over a network or not, etc). + * + * \ingroup IngenClient + */ +class OSCEngineSender : public ServerInterface, public Shared::OSCSender { +public: + OSCEngineSender(const Raul::URI& engine_url, + size_t max_packet_size, + SharedPtr receiver); + + ~OSCEngineSender(); + + Raul::URI uri() const { return _engine_url; } + + inline int32_t next_id() + { int32_t ret = (_id == -1) ? -1 : _id++; return ret; } + + void respond_to(ClientInterface* client, int32_t id) { _id = id; } + void disable_responses() { _id = -1; } + + void attach(int32_t ping_id, bool block); + + /* *** ServerInterface implementation below here *** */ + + void enable() { _enabled = true; } + void disable() { _enabled = false; } + + void bundle_begin() { OSCSender::bundle_begin(); } + void bundle_end() { OSCSender::bundle_end(); } + + // Client registration + void register_client(ClientInterface* client); + void unregister_client(const Raul::URI& uri); + + // Object commands + + virtual void put(const Raul::URI& path, + const Resource::Properties& properties, + Resource::Graph ctx=Resource::DEFAULT); + + virtual void delta(const Raul::URI& path, + const Resource::Properties& remove, + const Resource::Properties& add); + + virtual void del(const Raul::URI& uri); + + virtual void move(const Raul::Path& old_path, + const Raul::Path& new_path); + + virtual void connect(const Raul::Path& src_port_path, + const Raul::Path& dst_port_path); + + virtual void disconnect(const Raul::URI& src, + const Raul::URI& dst); + + virtual void disconnect_all(const Raul::Path& parent_patch_path, + const Raul::Path& path); + + virtual void set_property(const Raul::URI& subject_path, + const Raul::URI& predicate, + const Raul::Atom& value); + + // Requests // + void ping(); + void get(const Raul::URI& uri); + +protected: + SharedPtr _receiver; + + const Raul::URI _engine_url; + int _client_port; + int32_t _id; +}; + +} // namespace Client +} // namespace Ingen + +#endif // INGEN_CLIENT_OSCENGINESENDER_HPP + diff --git a/src/osc/OSCSender.cpp b/src/osc/OSCSender.cpp new file mode 100644 index 00000000..6c07551b --- /dev/null +++ b/src/osc/OSCSender.cpp @@ -0,0 +1,111 @@ +/* This file is part of Ingen. + * Copyright 2008-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "raul/log.hpp" + +#include "OSCSender.hpp" +#include "ingen-config.h" + +using namespace std; +using namespace Raul; + +namespace Ingen { +namespace Shared { + +OSCSender::OSCSender(size_t max_packet_size) + : _bundle(NULL) + , _address(NULL) + , _max_packet_size(max_packet_size) + , _enabled(true) +{ +} + +void +OSCSender::bundle_begin() +{ + assert(!_bundle); + lo_timetag t; + lo_timetag_now(&t); + _bundle = lo_bundle_new(t); +} + +void +OSCSender::bundle_end() +{ + assert(_bundle); + lo_send_bundle(_address, _bundle); + lo_bundle_free_messages(_bundle); + _bundle = NULL; +} + +int +OSCSender::send(const char *path, const char *types, ...) +{ + if (!_enabled) + return 0; + +#ifdef RAUL_LOG_DEBUG + info << "[OSCSender] " << path << " (" << types << ")" << endl; +#endif + + va_list args; + va_start(args, types); + + lo_message msg = lo_message_new(); + int ret = lo_message_add_varargs(msg, types, args); + + if (!ret) + send_message(path, msg); + else + lo_message_free(msg); + + va_end(args); + + return ret; +} + +void +OSCSender::send_message(const char* path, lo_message msg) +{ + if (!_enabled) { + lo_message_free(msg); + return; + } + + if (_bundle) { + if (lo_bundle_length(_bundle) + lo_message_length(msg, path) > _max_packet_size) { + warn << "Maximum bundle size reached, bundle split" << endl; + lo_send_bundle(_address, _bundle); + lo_bundle_free_messages(_bundle); + lo_timetag t; + lo_timetag_now(&t); + _bundle = lo_bundle_new(t); + } + lo_bundle_add_message(_bundle, path, msg); + + } else { + lo_send_message(_address, path, msg); + lo_message_free(msg); + } +} + +} // namespace Shared +} // namespace Ingen diff --git a/src/osc/OSCSender.hpp b/src/osc/OSCSender.hpp new file mode 100644 index 00000000..b2febb70 --- /dev/null +++ b/src/osc/OSCSender.hpp @@ -0,0 +1,52 @@ +/* This file is part of Ingen. + * Copyright 2007-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef INGEN_SHARED_OSCSENDER_HPP +#define INGEN_SHARED_OSCSENDER_HPP + +#include + +#include + +namespace Ingen { +namespace Shared { + +class OSCSender { +public: + OSCSender(size_t max_packet_size); + virtual ~OSCSender() {} + + lo_address address() const { return _address; } + + void bundle_begin(); + void bundle_end(); + +protected: + int send(const char *path, const char *types, ...); + void send_message(const char* path, lo_message m); + + lo_bundle _bundle; + lo_address _address; + size_t _max_packet_size; + bool _enabled; +}; + +} // namespace Shared +} // namespace Ingen + +#endif // INGEN_SHARED_OSCSENDER_HPP + diff --git a/src/osc/ingen_osc.cpp b/src/osc/ingen_osc.cpp deleted file mode 100644 index 4a8946c0..00000000 --- a/src/osc/ingen_osc.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "ingen/shared/Module.hpp" -#include "ingen/shared/World.hpp" - -#include "../server/Engine.hpp" -#include "../server/ServerInterfaceImpl.hpp" - -#include "OSCEngineReceiver.hpp" - -using namespace std; -using namespace Ingen; - -struct IngenOSCModule : public Ingen::Shared::Module { - void load(Ingen::Shared::World* world) { - Server::Engine* engine = (Server::Engine*)world->local_engine().get(); - SharedPtr interface( - new Server::ServerInterfaceImpl(*engine)); - receiver = SharedPtr( - new Server::OSCEngineReceiver( - *engine, - interface, - world->conf()->option("engine-port").get_int32())); - engine->add_event_source(interface); - } - - SharedPtr receiver; -}; - -extern "C" { - -Ingen::Shared::Module* -ingen_module_load() -{ - return new IngenOSCModule(); -} - -} // extern "C" diff --git a/src/osc/ingen_osc_server.cpp b/src/osc/ingen_osc_server.cpp new file mode 100644 index 00000000..fd4455f0 --- /dev/null +++ b/src/osc/ingen_osc_server.cpp @@ -0,0 +1,53 @@ +/* This file is part of Ingen. + * Copyright 2007-2011 David Robillard + * + * Ingen 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. + * + * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ingen/shared/Module.hpp" +#include "ingen/shared/World.hpp" + +#include "../server/Engine.hpp" +#include "../server/ServerInterfaceImpl.hpp" + +#include "OSCEngineReceiver.hpp" + +using namespace std; +using namespace Ingen; + +struct IngenOSCServerModule : public Ingen::Shared::Module { + void load(Ingen::Shared::World* world) { + Server::Engine* engine = (Server::Engine*)world->local_engine().get(); + SharedPtr interface( + new Server::ServerInterfaceImpl(*engine)); + receiver = SharedPtr( + new Server::OSCEngineReceiver( + *engine, + interface, + world->conf()->option("engine-port").get_int32())); + engine->add_event_source(interface); + } + + SharedPtr receiver; +}; + +extern "C" { + +Ingen::Shared::Module* +ingen_module_load() +{ + return new IngenOSCServerModule(); +} + +} // extern "C" diff --git a/src/shared/HTTPSender.cpp b/src/shared/HTTPSender.cpp deleted file mode 100644 index 1a4d35da..00000000 --- a/src/shared/HTTPSender.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2008-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "raul/log.hpp" -#include "HTTPSender.hpp" - -using namespace std; -using namespace Raul; - -namespace Ingen { -namespace Shared { - -HTTPSender::HTTPSender() - : _listen_port(-1) - , _listen_sock(-1) - , _client_sock(-1) - , _send_state(Immediate) -{ - Thread::set_name("HTTPSender"); - - struct sockaddr_in addr; - - // Create listen address - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - // Create listen socket - if ((_listen_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) { - error << "Error creating listening socket (" << strerror(errno) << ")" << endl; - exit(EXIT_FAILURE); - } - - // Bind our socket addresss to the listening socket - if (bind(_listen_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { - error << "Error calling bind (%s)\n" << strerror(errno) << ")" << endl; - _listen_sock = -1; - } - - // Find port number - socklen_t length = sizeof(addr); - if (getsockname(_listen_sock, (struct sockaddr*)&addr, &length) == -1) { - error << "Error calling getsockname (" << strerror(errno) << ")" << endl; - _listen_sock = -1; - return; - } - - if (listen(_listen_sock, 1) < 0 ) { - error << "Error calling listen (" << strerror(errno) << ")" << endl; - _listen_sock = -1; - return; - } - - _listen_port = ntohs(addr.sin_port); - info << "Opening event stream on TCP port " << _listen_port << endl; - start(); -} - -HTTPSender::~HTTPSender() -{ - stop(); - if (_listen_sock != -1) - close(_listen_sock); - if (_client_sock != -1) - close(_client_sock); -} - -void -HTTPSender::_run() -{ - if (_listen_sock == -1) { - error << "Unable to open socket, exiting sender thread" << endl; - return; - } - - // Accept connection - if ((_client_sock = accept(_listen_sock, NULL, NULL) ) < 0) { - error << "Error calling accept: " << strerror(errno) << endl; - return; - } - - // Hold connection open and write when signalled - while (true) { - _mutex.lock(); - _signal.wait(_mutex); - - write(_client_sock, _transfer.c_str(), _transfer.length()); - write(_client_sock, "\n\n\n", 3); - - _signal.broadcast(); - _mutex.unlock(); - } - - close(_listen_sock); - _listen_sock = -1; -} - -void -HTTPSender::bundle_begin() -{ - _mutex.lock(); - _send_state = SendingBundle; - _transfer = ""; -} - -void -HTTPSender::bundle_end() -{ - assert(_send_state == SendingBundle); - _signal.broadcast(); - _signal.wait(_mutex); - _send_state = Immediate; - _mutex.unlock(); -} - -void -HTTPSender::send_chunk(const std::string& buf) -{ - if (_send_state == Immediate) { - _mutex.lock(); - _transfer = buf; - _signal.broadcast(); - _signal.wait(_mutex); - _mutex.unlock(); - } else { - _transfer.append(buf); - } -} - -} // namespace Shared -} // namespace Ingen diff --git a/src/shared/HTTPSender.hpp b/src/shared/HTTPSender.hpp deleted file mode 100644 index a1a3ea2a..00000000 --- a/src/shared/HTTPSender.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2008-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef INGEN_SHARED_HTTPSENDER_HPP -#define INGEN_SHARED_HTTPSENDER_HPP - -#include - -#include - -#include "raul/Thread.hpp" - -namespace Ingen { -namespace Shared { - -class HTTPSender : public Raul::Thread { -public: - HTTPSender(); - virtual ~HTTPSender(); - - void bundle_begin(); - void bundle_end(); - - int listen_port() const { return _listen_port; } - -protected: - void _run(); - - void send_chunk(const std::string& buf); - - enum SendState { Immediate, SendingBundle }; - - Glib::Mutex _mutex; - Glib::Cond _signal; - - int _listen_port; - int _listen_sock; - int _client_sock; - SendState _send_state; - std::string _transfer; -}; - -} // namespace Shared -} // namespace Ingen - -#endif // INGEN_SHARED_HTTPSENDER_HPP - diff --git a/src/shared/OSCSender.cpp b/src/shared/OSCSender.cpp deleted file mode 100644 index 6c07551b..00000000 --- a/src/shared/OSCSender.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2008-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include - -#include "raul/log.hpp" - -#include "OSCSender.hpp" -#include "ingen-config.h" - -using namespace std; -using namespace Raul; - -namespace Ingen { -namespace Shared { - -OSCSender::OSCSender(size_t max_packet_size) - : _bundle(NULL) - , _address(NULL) - , _max_packet_size(max_packet_size) - , _enabled(true) -{ -} - -void -OSCSender::bundle_begin() -{ - assert(!_bundle); - lo_timetag t; - lo_timetag_now(&t); - _bundle = lo_bundle_new(t); -} - -void -OSCSender::bundle_end() -{ - assert(_bundle); - lo_send_bundle(_address, _bundle); - lo_bundle_free_messages(_bundle); - _bundle = NULL; -} - -int -OSCSender::send(const char *path, const char *types, ...) -{ - if (!_enabled) - return 0; - -#ifdef RAUL_LOG_DEBUG - info << "[OSCSender] " << path << " (" << types << ")" << endl; -#endif - - va_list args; - va_start(args, types); - - lo_message msg = lo_message_new(); - int ret = lo_message_add_varargs(msg, types, args); - - if (!ret) - send_message(path, msg); - else - lo_message_free(msg); - - va_end(args); - - return ret; -} - -void -OSCSender::send_message(const char* path, lo_message msg) -{ - if (!_enabled) { - lo_message_free(msg); - return; - } - - if (_bundle) { - if (lo_bundle_length(_bundle) + lo_message_length(msg, path) > _max_packet_size) { - warn << "Maximum bundle size reached, bundle split" << endl; - lo_send_bundle(_address, _bundle); - lo_bundle_free_messages(_bundle); - lo_timetag t; - lo_timetag_now(&t); - _bundle = lo_bundle_new(t); - } - lo_bundle_add_message(_bundle, path, msg); - - } else { - lo_send_message(_address, path, msg); - lo_message_free(msg); - } -} - -} // namespace Shared -} // namespace Ingen diff --git a/src/shared/OSCSender.hpp b/src/shared/OSCSender.hpp deleted file mode 100644 index b2febb70..00000000 --- a/src/shared/OSCSender.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard - * - * Ingen 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. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef INGEN_SHARED_OSCSENDER_HPP -#define INGEN_SHARED_OSCSENDER_HPP - -#include - -#include - -namespace Ingen { -namespace Shared { - -class OSCSender { -public: - OSCSender(size_t max_packet_size); - virtual ~OSCSender() {} - - lo_address address() const { return _address; } - - void bundle_begin(); - void bundle_end(); - -protected: - int send(const char *path, const char *types, ...); - void send_message(const char* path, lo_message m); - - lo_bundle _bundle; - lo_address _address; - size_t _max_packet_size; - bool _enabled; -}; - -} // namespace Shared -} // namespace Ingen - -#endif // INGEN_SHARED_OSCSENDER_HPP - diff --git a/src/shared/World.cpp b/src/shared/World.cpp index 9aa17d4f..aae321fe 100644 --- a/src/shared/World.cpp +++ b/src/shared/World.cpp @@ -219,6 +219,11 @@ SharedPtr World::lv2_uri_map() { return _impl->lv2_uri_map; } bool World::load_module(const char* name) { + Pimpl::Modules::iterator i = _impl->modules.find(name); + if (i != _impl->modules.end()) { + LOG(info) << "Module `" << name << "' already loaded" << endl; + return true; + } SharedPtr lib = ingen_load_module(name); Ingen::Shared::Module* (*module_load)() = NULL; if (lib && lib->get_symbol("ingen_module_load", (void*&)module_load)) { diff --git a/src/shared/wscript b/src/shared/wscript index 601f3286..410325a4 100644 --- a/src/shared/wscript +++ b/src/shared/wscript @@ -10,7 +10,7 @@ def build(bld): vnum = '0.0.0', install_path = '${LIBDIR}', linkflags = '-ldl') - autowaf.use_lib(bld, obj, 'GLIBMM LV2CORE LILV RAUL SORD LIBLO') + autowaf.use_lib(bld, obj, 'GLIBMM LV2CORE LILV RAUL SORD') obj.source = ''' Builder.cpp @@ -26,10 +26,3 @@ def build(bld): World.cpp runtime_paths.cpp ''' - - if bld.is_defined('HAVE_LIBLO'): - obj.source += ' OSCSender.cpp ' - - if bld.is_defined('HAVE_SOUP'): - autowaf.use_lib(bld, obj, 'SOUP') - obj.source += ' HTTPSender.cpp ' diff --git a/wscript b/wscript index 026c3db3..27b85e7e 100644 --- a/wscript +++ b/wscript @@ -154,7 +154,7 @@ def build(bld): defines = 'VERSION="' + bld.env['INGEN_VERSION'] + '"', use = 'libingen_shared', install_path = '${BINDIR}') - autowaf.use_lib(bld, obj, 'GTHREAD GLIBMM SORD RAUL LILV INGEN LIBLO SOUP' + + autowaf.use_lib(bld, obj, 'GTHREAD GLIBMM SORD RAUL LILV INGEN' + ' LV2CORE LV2_EVENT LV2_URI_MAP LV2_PERSIST') bld.install_files('${DATADIR}/applications', 'src/ingen/ingen.desktop') -- cgit v1.2.1