diff options
author | David Robillard <d@drobilla.net> | 2008-08-19 18:51:06 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2008-08-19 18:51:06 +0000 |
commit | e16206982d074e62956de00eeef611478f01c430 (patch) | |
tree | 388bc6e5ad9220cf9cdedf865a2d45856f418ae4 | |
parent | 14764da12f3808da0c40b643ac8224716f060729 (diff) | |
download | ingen-e16206982d074e62956de00eeef611478f01c430.tar.gz ingen-e16206982d074e62956de00eeef611478f01c430.tar.bz2 ingen-e16206982d074e62956de00eeef611478f01c430.zip |
Preliminary connecting via HTTP in Gtk client.
Better handling of overflowed client event receive buffer.
Store fixes, complain only once about orphans, don't request an orphan parent over and over.
git-svn-id: http://svn.drobilla.net/lad/ingen@1447 a436a847-0d15-0410-975c-d299462d15a1
39 files changed, 819 insertions, 132 deletions
diff --git a/src/common/interface/ClientInterface.hpp b/src/common/interface/ClientInterface.hpp index e7ddfeaf..2d604ced 100644 --- a/src/common/interface/ClientInterface.hpp +++ b/src/common/interface/ClientInterface.hpp @@ -42,6 +42,8 @@ public: virtual void response_ok(int32_t id) = 0; virtual void response_error(int32_t id, const std::string& msg) = 0; + + virtual bool enabled() const = 0; virtual void enable() = 0; diff --git a/src/common/interface/EngineInterface.hpp b/src/common/interface/EngineInterface.hpp index b82bf8c2..a9b2a0c1 100644 --- a/src/common/interface/EngineInterface.hpp +++ b/src/common/interface/EngineInterface.hpp @@ -38,6 +38,8 @@ class EngineInterface : public CommonInterface { public: virtual ~EngineInterface() {} + + virtual std::string uri() const = 0; // Responses virtual void set_next_response_id(int32_t id) = 0; diff --git a/src/libs/client/ClientStore.cpp b/src/libs/client/ClientStore.cpp index 0597aa21..18582046 100644 --- a/src/libs/client/ClientStore.cpp +++ b/src/libs/client/ClientStore.cpp @@ -72,17 +72,15 @@ ClientStore::add_plugin_orphan(SharedPtr<NodeModel> node) { if (!_handle_orphans) return; - cerr << "WARNING: Node " << node->path() << " received, but plugin " - << node->plugin_uri() << " unknown." << endl; Raul::Table<string, list<SharedPtr<NodeModel> > >::iterator spawn = _plugin_orphans.find(node->plugin_uri()); - _engine->request_plugin(node->plugin_uri()); - if (spawn != _plugin_orphans.end()) { spawn->second.push_back(node); } else { + cerr << "WARNING: Orphans of plugin " << node->plugin_uri() << " received" << endl; + _engine->request_plugin(node->plugin_uri()); list<SharedPtr<NodeModel> > l; l.push_back(node); _plugin_orphans[node->plugin_uri()] = l; @@ -108,7 +106,7 @@ ClientStore::resolve_plugin_orphans(SharedPtr<PluginModel> plugin) for (list<SharedPtr<NodeModel> >::iterator i = spawn.begin(); i != spawn.end(); ++i) { (*i)->_plugin = plugin; - add_object(*i); + //add_object(*i); } } } @@ -248,7 +246,6 @@ ClientStore::add_object(SharedPtr<ObjectModel> object) // one (with precedence to the new values). iterator existing = find(object->path()); if (existing != end()) { - cout << "WARNING: Object " << object->path() << " already exists in store" << endl; PtrCast<ObjectModel>(existing->second)->set(object); } else { @@ -444,6 +441,7 @@ ClientStore::new_node(const string& path, const string& plugin_uri) if (!plug) { SharedPtr<NodeModel> n(new NodeModel(plugin_uri, path)); add_plugin_orphan(n); + add_object(n); } else { SharedPtr<NodeModel> n(new NodeModel(plug, path)); add_object(n); diff --git a/src/libs/client/HTTPClientReceiver.cpp b/src/libs/client/HTTPClientReceiver.cpp new file mode 100644 index 00000000..ece55ab2 --- /dev/null +++ b/src/libs/client/HTTPClientReceiver.cpp @@ -0,0 +1,97 @@ +/* This file is part of Ingen. + * Copyright (C) 2008 Dave Robillard <http://drobilla.net> + * + * 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 <list> +#include <cassert> +#include <cstring> +#include <iostream> +#include <sstream> +#include <raul/AtomLiblo.hpp> +#include "module/Module.hpp" +#include "HTTPClientReceiver.hpp" + +using namespace std; +using namespace Raul; + +namespace Ingen { +namespace Client { + + +HTTPClientReceiver::HTTPClientReceiver( + Shared::World* world, + const std::string& url, + SharedPtr<Shared::ClientInterface> target) + : _target(target) + , _world(world) + , _url(url) + , _session(NULL) +{ + start(false); +} + + +HTTPClientReceiver::~HTTPClientReceiver() +{ + stop(); +} + + +void +HTTPClientReceiver::message_callback(SoupSession* session, SoupMessage* msg, void* ptr) +{ + HTTPClientReceiver* me = (HTTPClientReceiver*)ptr; + cout << "RECEIVED ASYNC MESSAGE: " << msg->response_body->data << endl; + me->_target->response_ok(0); + me->_target->enable(); + me->_parser->parse_string(me->_world, me->_target.get(), Glib::ustring(msg->response_body->data), + Glib::ustring("/"), Glib::ustring("")); +} + + +void +HTTPClientReceiver::start(bool dump) +{ + Glib::Mutex::Lock lock(_world->rdf_world->mutex()); + if (!_parser) { + if (!_world->serialisation_module) + _world->serialisation_module = Ingen::Shared::load_module("ingen_serialisation"); + + if (_world->serialisation_module) { + Parser* (*new_parser)() = NULL; + if (_world->serialisation_module->get_symbol("new_parser", (void*&)new_parser)) + _parser = SharedPtr<Parser>(new_parser()); + } + } + _session = soup_session_async_new(); + SoupMessage* msg = soup_message_new("GET", _url.c_str()); + soup_session_queue_message (_session, msg, message_callback, this); +} + + +void +HTTPClientReceiver::stop() +{ + if (_session != NULL) { + //unregister_client(); + soup_session_abort(_session); + _session = NULL; + } +} + + +} // namespace Client +} // namespace Ingen diff --git a/src/libs/client/HTTPClientReceiver.hpp b/src/libs/client/HTTPClientReceiver.hpp new file mode 100644 index 00000000..bab55578 --- /dev/null +++ b/src/libs/client/HTTPClientReceiver.hpp @@ -0,0 +1,62 @@ +/* This file is part of Ingen. + * Copyright (C) 2008 Dave Robillard <http://drobilla.net> + * + * 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 HTTPCLIENTRECEIVER_H +#define HTTPCLIENTRECEIVER_H + +#include <cstdlib> +#include <boost/utility.hpp> +#include <libsoup/soup.h> +#include "interface/ClientInterface.hpp" +#include "serialisation/Parser.hpp" +#include "redlandmm/World.hpp" +#include "raul/Deletable.hpp" + +namespace Ingen { +namespace Client { + + +class HTTPClientReceiver : public boost::noncopyable, public Raul::Deletable +{ +public: + HTTPClientReceiver(Shared::World* world, + const std::string& url, + SharedPtr<Shared::ClientInterface> target); + + ~HTTPClientReceiver(); + + std::string uri() const { return _url; } + + void start(bool dump); + void stop(); + +private: + static void message_callback(SoupSession* session, SoupMessage* msg, void* ptr); + + SharedPtr<Shared::ClientInterface> _target; + + Shared::World* _world; + const std::string _url; + SoupSession* _session; + SharedPtr<Parser> _parser; +}; + + +} // namespace Client +} // namespace Ingen + +#endif // HTTPCLIENTRECEIVER_H diff --git a/src/libs/client/HTTPEngineSender.cpp b/src/libs/client/HTTPEngineSender.cpp new file mode 100644 index 00000000..882a4bc4 --- /dev/null +++ b/src/libs/client/HTTPEngineSender.cpp @@ -0,0 +1,300 @@ +/* This file is part of Ingen. + * Copyright (C) 2008 Dave Robillard <http://drobilla.net> + * + * 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 <iostream> +#include <libsoup/soup.h> +#include "HTTPEngineSender.hpp" + +using namespace std; + +namespace Ingen { +namespace Client { + + +HTTPEngineSender::HTTPEngineSender(const string& engine_url) + : _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) +{ + /*SoupMessage *msg; + msg = soup_message_new ("GET", _engine_url.c_str()); + int status = soup_session_send_message (_session, msg); + cout << "STATUS: " << status << endl; + cout << "RESPONSE: " << msg->response_body->data << endl;*/ +} + + +/* *** EngineInterface 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 EngineInterface. + */ +void +HTTPEngineSender::register_client(ClientInterface* client) +{ + +} + + +void +HTTPEngineSender::unregister_client(const string& uri) +{ + +} + + +// Engine commands +void +HTTPEngineSender::load_plugins() +{ + +} + + +void +HTTPEngineSender::activate() +{ + +} + + +void +HTTPEngineSender::deactivate() +{ + +} + + +void +HTTPEngineSender::quit() +{ + +} + + + +// Object commands + +void +HTTPEngineSender::new_patch(const string& path, + uint32_t poly) +{ +} + + +void +HTTPEngineSender::new_port(const string& path, + uint32_t index, + const string& data_type, + bool is_output) +{ +} + + +void +HTTPEngineSender::new_node(const string& path, + const string& plugin_uri) +{ +} + + +/** Create a node using library name and plugin label (DEPRECATED). + * + * DO NOT USE THIS. + */ +void +HTTPEngineSender::new_node_deprecated(const string& path, + const string& plugin_type, + const string& library_name, + const string& plugin_label) +{ +} + + +void +HTTPEngineSender::rename(const string& old_path, + const string& new_name) +{ +} + + +void +HTTPEngineSender::destroy(const string& path) +{ +} + + +void +HTTPEngineSender::clear_patch(const string& patch_path) +{ +} + + +void +HTTPEngineSender::connect(const string& src_port_path, + const string& dst_port_path) +{ +} + + +void +HTTPEngineSender::disconnect(const string& src_port_path, + const string& dst_port_path) +{ +} + + +void +HTTPEngineSender::disconnect_all(const string& parent_patch_path, + const string& node_path) +{ +} + + +void +HTTPEngineSender::set_port_value(const string& port_path, + const Raul::Atom& value) +{ +} + + +void +HTTPEngineSender::set_voice_value(const string& port_path, + uint32_t voice, + const Raul::Atom& value) +{ +} + + +void +HTTPEngineSender::set_port_value_immediate(const string& port_path, + const Raul::Atom& value) +{ +} + + +void +HTTPEngineSender::set_voice_value_immediate(const string& port_path, + uint32_t voice, + const Raul::Atom& value) +{ +} + + +void +HTTPEngineSender::set_program(const string& node_path, + uint32_t bank, + uint32_t program) +{ +} + + +void +HTTPEngineSender::midi_learn(const string& node_path) +{ +} + + +void +HTTPEngineSender::set_variable(const string& obj_path, + const string& predicate, + const Raul::Atom& value) +{ +} + + +void +HTTPEngineSender::set_property(const string& obj_path, + const string& predicate, + const Raul::Atom& value) +{ +} + + + +// Requests // + +void +HTTPEngineSender::ping() +{ +} + + +void +HTTPEngineSender::request_plugin(const string& uri) +{ +} + + +void +HTTPEngineSender::request_object(const string& path) +{ +} + + +void +HTTPEngineSender::request_port_value(const string& port_path) +{ +} + + +void +HTTPEngineSender::request_variable(const string& object_path, const string& key) +{ +} + + +void +HTTPEngineSender::request_property(const string& object_path, const string& key) +{ +} + + +void +HTTPEngineSender::request_plugins() +{ +} + + +void +HTTPEngineSender::request_all_objects() +{ +} + + + +} // namespace Client +} // namespace Ingen + + diff --git a/src/libs/client/HTTPEngineSender.hpp b/src/libs/client/HTTPEngineSender.hpp new file mode 100644 index 00000000..f753eea3 --- /dev/null +++ b/src/libs/client/HTTPEngineSender.hpp @@ -0,0 +1,162 @@ +/* This file is part of Ingen. + * Copyright (C) 2008 Dave Robillard <http://drobilla.net> + * + * 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 HTTPENGINESENDER_H +#define HTTPENGINESENDER_H + +#include <inttypes.h> +#include <string> +#include <libsoup/soup.h> +#include "interface/EngineInterface.hpp" +using std::string; +using Ingen::Shared::EngineInterface; +using Ingen::Shared::ClientInterface; + +namespace Ingen { +namespace Client { + + +/* HTTP (via libsoup) interface to the engine. + * + * Clients can use this opaquely as an EngineInterface to control the engine + * over HTTP (whether over a network or not). + * + * \ingroup IngenClient + */ +class HTTPEngineSender : public EngineInterface { +public: + HTTPEngineSender(const string& engine_url); + ~HTTPEngineSender(); + + string uri() const { return _engine_url; } + + inline int32_t next_id() + { int32_t ret = (_id == -1) ? -1 : _id++; return ret; } + + void set_next_response_id(int32_t id) { _id = id; } + void disable_responses() { _id = -1; } + + void attach(int32_t ping_id, bool block); + + + /* *** EngineInterface implementation below here *** */ + + void enable() { _enabled = true; } + void disable() { _enabled = false; } + + void bundle_begin() { transfer_begin(); } + void bundle_end() { transfer_end(); } + + void transfer_begin(); + void transfer_end(); + + // Client registration + void register_client(ClientInterface* client); + void unregister_client(const string& uri); + + // Engine commands + void load_plugins(); + void activate(); + void deactivate(); + void quit(); + + // Object commands + + void new_patch(const string& path, + uint32_t poly); + + void new_port(const string& path, + uint32_t index, + const string& data_type, + bool is_output); + + void new_node(const string& path, + const string& plugin_uri); + + void new_node_deprecated(const string& path, + const string& plugin_type, + const string& library_name, + const string& plugin_label); + + void rename(const string& old_path, + const string& new_name); + + void destroy(const string& path); + + void clear_patch(const string& patch_path); + + void connect(const string& src_port_path, + const string& dst_port_path); + + void disconnect(const string& src_port_path, + const string& dst_port_path); + + void disconnect_all(const string& parent_patch_path, + const string& node_path); + + void set_port_value(const string& port_path, + const Raul::Atom& value); + + void set_voice_value(const string& port_path, + uint32_t voice, + const Raul::Atom& value); + + void set_port_value_immediate(const string& port_path, + const Raul::Atom& value); + + void set_voice_value_immediate(const string& port_path, + uint32_t voice, + const Raul::Atom& value); + + void set_program(const string& node_path, + uint32_t bank, + uint32_t program); + + void midi_learn(const string& node_path); + + void set_variable(const string& obj_path, + const string& predicate, + const Raul::Atom& value); + + void set_property(const string& obj_path, + const string& predicate, + const Raul::Atom& value); + + // Requests // + void ping(); + void request_plugin(const string& uri); + void request_object(const string& path); + void request_port_value(const string& port_path); + void request_variable(const string& path, const string& key); + void request_property(const string& path, const string& key); + void request_plugins(); + void request_all_objects(); + +protected: + SoupSession* _session; + const string _engine_url; + int _client_port; + int32_t _id; + bool _enabled; +}; + + +} // namespace Client +} // namespace Ingen + +#endif // HTTPENGINESENDER_H + diff --git a/src/libs/client/Makefile.am b/src/libs/client/Makefile.am index 88e2b393..76835de6 100644 --- a/src/libs/client/Makefile.am +++ b/src/libs/client/Makefile.am @@ -15,7 +15,8 @@ libingen_client_la_CXXFLAGS = \ @LXML2_CFLAGS@ \ @RAUL_CFLAGS@ \ @REDLANDMM_CFLAGS@ \ - @SLV2_CFLAGS@ + @SLV2_CFLAGS@ \ + @SOUP_CFLAGS@ libingen_client_la_LIBADD = \ ../shared/libingen_shared.la \ @@ -25,14 +26,21 @@ libingen_client_la_LIBADD = \ @LXML2_LIBS@ \ @RAUL_LIBS@ \ @REDLANDMM_LIBS@ \ - @SLV2_LIBS@ + @SLV2_LIBS@ \ + @SOUP_LIBS@ libingen_client_la_SOURCES = \ $(top_srcdir)/ingen/src/common/interface/ClientInterface.hpp \ $(top_srcdir)/ingen/src/common/interface/EngineInterface.hpp \ + ClientStore.cpp \ + ClientStore.hpp \ ConnectionModel.hpp \ DeprecatedLoader.cpp \ DeprecatedLoader.hpp \ + HTTPClientReceiver.cpp \ + HTTPClientReceiver.hpp \ + HTTPEngineSender.cpp \ + HTTPEngineSender.hpp \ NodeModel.cpp \ NodeModel.hpp \ OSCClientReceiver.cpp \ @@ -45,13 +53,11 @@ libingen_client_la_SOURCES = \ PatchModel.hpp \ PluginModel.cpp \ PluginModel.hpp \ - PluginUI.hpp \ PluginUI.cpp \ + PluginUI.hpp \ PortModel.cpp \ PortModel.hpp \ SigClientInterface.hpp \ - ClientStore.cpp \ - ClientStore.hpp \ ThreadedSigClientInterface.cpp \ ThreadedSigClientInterface.hpp \ client.cpp \ diff --git a/src/libs/client/NodeModel.cpp b/src/libs/client/NodeModel.cpp index 02a0a678..ac0c8e68 100644 --- a/src/libs/client/NodeModel.cpp +++ b/src/libs/client/NodeModel.cpp @@ -69,7 +69,7 @@ void NodeModel::remove_port(SharedPtr<PortModel> port) { // FIXME: slow - for (PortModelList::iterator i = _ports.begin(); i != _ports.end(); ++i) { + for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { if ((*i) == port) { _ports.erase(i); break; @@ -83,7 +83,7 @@ void NodeModel::remove_port(const Path& port_path) { // FIXME: slow - for (PortModelList::iterator i = _ports.begin(); i != _ports.end(); ++i) { + for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { if ((*i)->path() == port_path) { _ports.erase(i); break; @@ -141,7 +141,7 @@ NodeModel::add_port(SharedPtr<PortModel> pm) assert(pm->path().is_child_of(_path)); assert(pm->parent().get() == this); - PortModelList::iterator existing = find(_ports.begin(), _ports.end(), pm); + Ports::iterator existing = find(_ports.begin(), _ports.end(), pm); // Store should have handled this by merging the two assert(existing == _ports.end()); @@ -155,7 +155,7 @@ SharedPtr<PortModel> NodeModel::get_port(const string& port_name) const { assert(port_name.find("/") == string::npos); - for (PortModelList::const_iterator i = _ports.begin(); i != _ports.end(); ++i) + for (Ports::const_iterator i = _ports.begin(); i != _ports.end(); ++i) if ((*i)->path().name() == port_name) return (*i); return SharedPtr<PortModel>(); @@ -211,8 +211,10 @@ void NodeModel::set(SharedPtr<ObjectModel> model) { SharedPtr<NodeModel> node = PtrCast<NodeModel>(model); - if (node) + if (node) { + _plugin_uri = node->_plugin_uri; _plugin = node->_plugin; + } ObjectModel::set(model); } diff --git a/src/libs/client/NodeModel.hpp b/src/libs/client/NodeModel.hpp index a4bcf4d8..03afc17c 100644 --- a/src/libs/client/NodeModel.hpp +++ b/src/libs/client/NodeModel.hpp @@ -50,6 +50,8 @@ class NodeModel : public ObjectModel, virtual public Ingen::Shared::Node public: NodeModel(const NodeModel& copy); virtual ~NodeModel(); + + typedef vector<SharedPtr<PortModel> > Ports; SharedPtr<PortModel> get_port(const string& port_name) const; @@ -58,7 +60,7 @@ public: const string& plugin_uri() const { return _plugin_uri; } const Shared::Plugin* plugin() const { return _plugin.get(); } uint32_t num_ports() const { return _ports.size(); } - const PortModelList& ports() const { return _ports; } + const Ports& ports() const { return _ports; } void port_value_range(SharedPtr<PortModel> port, float& min, float& max); @@ -84,7 +86,7 @@ protected: virtual void clear(); - PortModelList _ports; ///< List of ports (not a Table to preserve order) + Ports _ports; ///< Vector of ports (not a Table to preserve order) string _plugin_uri; ///< Plugin URI (if PluginModel is unknown) SharedPtr<PluginModel> _plugin; ///< The plugin this node is an instance of uint32_t _num_values; ///< Size of _min_values and _max_values @@ -93,9 +95,6 @@ protected: }; -typedef Table<string, SharedPtr<NodeModel> > NodeModelMap; - - } // namespace Client } // namespace Ingen diff --git a/src/libs/client/OSCClientReceiver.hpp b/src/libs/client/OSCClientReceiver.hpp index f1d71dbb..ea5871b3 100644 --- a/src/libs/client/OSCClientReceiver.hpp +++ b/src/libs/client/OSCClientReceiver.hpp @@ -25,18 +25,13 @@ #include "raul/Deletable.hpp" namespace Ingen { - -/** Client library */ namespace Client { -//class NodeModel; - -/* Some boilerplate killing macros... */ +/** Arguments to a liblo handler */ #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 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)\ @@ -62,6 +57,8 @@ public: OSCClientReceiver(int listen_port, SharedPtr<Shared::ClientInterface> target); ~OSCClientReceiver(); + std::string uri() const { return lo_server_thread_get_url(_st); } + void start(bool dump_osc); void stop(); @@ -105,7 +102,6 @@ private: } // namespace Client - } // namespace Ingen #endif // OSCCLIENTRECEIVER_H diff --git a/src/libs/client/OSCEngineSender.hpp b/src/libs/client/OSCEngineSender.hpp index dbb7e8f5..4c92afdb 100644 --- a/src/libs/client/OSCEngineSender.hpp +++ b/src/libs/client/OSCEngineSender.hpp @@ -44,7 +44,7 @@ public: ~OSCEngineSender(); - string engine_url() { return _engine_url; } + std::string uri() const { return _engine_url; } inline int32_t next_id() { int32_t ret = (_id == -1) ? -1 : _id++; return ret; } @@ -148,9 +148,9 @@ public: void request_all_objects(); protected: - string _engine_url; - int _client_port; - int32_t _id; + const string _engine_url; + int _client_port; + int32_t _id; }; diff --git a/src/libs/client/ObjectModel.cpp b/src/libs/client/ObjectModel.cpp index e9a491a6..ede5f822 100644 --- a/src/libs/client/ObjectModel.cpp +++ b/src/libs/client/ObjectModel.cpp @@ -119,21 +119,26 @@ ObjectModel::polyphonic() const * @a model as correct. The paths of the two models MUST be equal. */ void -ObjectModel::set(SharedPtr<ObjectModel> model) +ObjectModel::set(SharedPtr<ObjectModel> o) { - assert(_path == model->path()); - - for (Variables::const_iterator other = model->variables().begin(); - other != model->variables().end(); ++other) { - - Variables::const_iterator mine = _variables.find(other->first); - - if (mine != _variables.end()) { - cerr << "WARNING: " << _path << "Client/Server data mismatch: " << other->first << endl; - } - - _variables[other->first] = other->second; - signal_variable.emit(other->first, other->second); + assert(_path == o->path()); + if (o->_parent) + _parent = o->_parent; + + for (Variables::const_iterator v = o->variables().begin(); v != o->variables().end(); ++v) { + Variables::const_iterator mine = _variables.find(v->first); + if (mine != _variables.end()) + cerr << "WARNING: " << _path << "Client/Server variable mismatch: " << v->first << endl; + _variables[v->first] = v->second; + signal_variable.emit(v->first, v->second); + } + + for (Properties::const_iterator v = o->properties().begin(); v != o->properties().end(); ++v) { + Properties::const_iterator mine = _properties.find(v->first); + if (mine != _properties.end()) + cerr << "WARNING: " << _path << "Client/Server property mismatch: " << v->first << endl; + _properties[v->first] = v->second; + signal_variable.emit(v->first, v->second); } } diff --git a/src/libs/client/PortModel.cpp b/src/libs/client/PortModel.cpp index fa3cb345..c18378db 100644 --- a/src/libs/client/PortModel.cpp +++ b/src/libs/client/PortModel.cpp @@ -51,7 +51,11 @@ PortModel::set(SharedPtr<ObjectModel> model) { SharedPtr<PortModel> port = PtrCast<PortModel>(model); if (port) { + _index = port->_index; + _type = port->_type; + _direction = port->_direction; _current_val = port->_current_val; + _connections = port->_connections; signal_value_changed.emit(_current_val); } diff --git a/src/libs/client/PortModel.hpp b/src/libs/client/PortModel.hpp index a86c9188..a7f52679 100644 --- a/src/libs/client/PortModel.hpp +++ b/src/libs/client/PortModel.hpp @@ -105,8 +105,6 @@ private: size_t _connections; }; -typedef vector<SharedPtr<PortModel> > PortModelList; - } // namespace Client } // namespace Ingen diff --git a/src/libs/client/SigClientInterface.hpp b/src/libs/client/SigClientInterface.hpp index 32a0a43b..7ab32c12 100644 --- a/src/libs/client/SigClientInterface.hpp +++ b/src/libs/client/SigClientInterface.hpp @@ -41,6 +41,8 @@ class SigClientInterface : public Ingen::Shared::ClientInterface, public sigc::t { public: SigClientInterface() : _enabled(true) {} + + bool enabled() const { return _enabled; } std::string uri() const { return "(internal)"; } diff --git a/src/libs/client/ThreadedSigClientInterface.cpp b/src/libs/client/ThreadedSigClientInterface.cpp index 3b7af80c..ef95133b 100644 --- a/src/libs/client/ThreadedSigClientInterface.cpp +++ b/src/libs/client/ThreadedSigClientInterface.cpp @@ -17,7 +17,8 @@ #include "ThreadedSigClientInterface.hpp" #include <iostream> -using std::cerr; using std::endl; + +using namespace std; namespace Ingen { namespace Client { @@ -28,23 +29,19 @@ namespace Client { void ThreadedSigClientInterface::push_sig(Closure ev) { + _attached = true; if (!_enabled) return; bool success = false; - bool first = true; - - // (Very) slow busy-wait if the queue is full - // FIXME: Make this wait on a signal from process_sigs iff this happens while (!success) { - //printf("push %zu\n", _sigs.fill()); success = _sigs.push(ev); if (!success) { - if (first) { - cerr << "[ThreadedSigClientInterface] WARNING: (Client) event queue full. Waiting to try again..." << endl; - first = false; - } - usleep(200000); // 100 milliseconds (2* rate process_sigs is called) + cerr << "WARNING: Client event queue full. Waiting..." << endl; + _mutex.lock(); + _cond.wait(_mutex); + _mutex.unlock(); + cerr << "Queue drained, continuing" << endl; } } } @@ -58,18 +55,21 @@ ThreadedSigClientInterface::push_sig(Closure ev) bool ThreadedSigClientInterface::emit_signals() { - // Process a maximum of queue-size events, to prevent locking the GTK + // Process a limited number of events, to prevent locking the GTK // thread indefinitely while processing continually arriving events - const size_t limit = _sigs.capacity(); + size_t num_processed = 0; - while (!_sigs.empty() && num_processed++ < limit) { - //printf("emit %zu\n", _sigs.fill()); + while (!_sigs.empty() && num_processed++ < (_sigs.capacity() * 3 / 4)) { Closure& ev = _sigs.front(); - _sigs.pop(); ev(); ev.disconnect(); + _sigs.pop(); } + _mutex.lock(); + _cond.broadcast(); + _mutex.unlock(); + return true; } diff --git a/src/libs/client/ThreadedSigClientInterface.hpp b/src/libs/client/ThreadedSigClientInterface.hpp index b3a1b72c..3014c139 100644 --- a/src/libs/client/ThreadedSigClientInterface.hpp +++ b/src/libs/client/ThreadedSigClientInterface.hpp @@ -21,10 +21,12 @@ #include <inttypes.h> #include <string> #include <sigc++/sigc++.h> +#include <glibmm/thread.h> #include "interface/ClientInterface.hpp" #include "SigClientInterface.hpp" -#include <raul/SRSWQueue.hpp> #include <raul/Atom.hpp> +#include <raul/SRSWQueue.hpp> + using std::string; /** Returns nothing and takes no parameters (because they have all been bound) */ @@ -65,12 +67,15 @@ public: , port_activity_slot(signal_port_activity.make_slot()) , program_add_slot(signal_program_add.make_slot()) , program_remove_slot(signal_program_remove.make_slot()) - {} + { + } virtual std::string uri() const { return "(internal)"; } virtual void subscribe(Shared::EngineInterface* engine) { throw; } + bool enabled() const { return _attached; } + void bundle_begin() { push_sig(bundle_begin_slot); } @@ -143,7 +148,11 @@ public: private: void push_sig(Closure ev); + Glib::Mutex _mutex; + Glib::Cond _cond; + Raul::SRSWQueue<Closure> _sigs; + bool _attached; sigc::slot<void> bundle_begin_slot; sigc::slot<void> bundle_end_slot; diff --git a/src/libs/client/client.cpp b/src/libs/client/client.cpp index 8b86e958..32380378 100644 --- a/src/libs/client/client.cpp +++ b/src/libs/client/client.cpp @@ -15,21 +15,37 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <iostream> #include "client.hpp" #include "OSCEngineSender.hpp" +#include "HTTPEngineSender.hpp" + +using namespace std; namespace Ingen { namespace Client { SharedPtr<Ingen::Shared::EngineInterface> -new_osc_interface(const std::string& url) +new_remote_interface(const std::string& url) { - OSCEngineSender* oes = new OSCEngineSender(url); - oes->attach(rand(), true); - return SharedPtr<Shared::EngineInterface>(oes); + const string scheme = url.substr(0, url.find(":")); + cout << "SCHEME: " << scheme << endl; + if (scheme == "osc.udp" || scheme == "osc.tcp") { + OSCEngineSender* oes = new OSCEngineSender(url); + oes->attach(rand(), true); + return SharedPtr<Shared::EngineInterface>(oes); + } else if (scheme == "http") { + HTTPEngineSender* hes = new HTTPEngineSender(url); + hes->attach(rand(), true); + return SharedPtr<Shared::EngineInterface>(hes); + } else { + cerr << "WARNING: Unknown URI scheme '" << scheme << "'" << endl; + return SharedPtr<Shared::EngineInterface>(); + } } + } // namespace Client } // namespace Ingen diff --git a/src/libs/client/client.hpp b/src/libs/client/client.hpp index 931e4c45..82166da5 100644 --- a/src/libs/client/client.hpp +++ b/src/libs/client/client.hpp @@ -30,7 +30,7 @@ namespace Client { extern "C" { - SharedPtr<Shared::EngineInterface> new_osc_interface(const std::string& url); + SharedPtr<Shared::EngineInterface> new_remote_interface(const std::string& url); SharedPtr<Shared::EngineInterface> new_queued_interface(SharedPtr<Ingen::Engine> engine); } diff --git a/src/libs/engine/OSCClientSender.hpp b/src/libs/engine/OSCClientSender.hpp index d62dd1d3..c8c8418f 100644 --- a/src/libs/engine/OSCClientSender.hpp +++ b/src/libs/engine/OSCClientSender.hpp @@ -48,6 +48,8 @@ public: virtual ~OSCClientSender() { lo_address_free(_address); } + bool enabled() const { return _enabled; } + void enable() { _enabled = true; } void disable() { _enabled = false; } diff --git a/src/libs/engine/OSCEngineReceiver.cpp b/src/libs/engine/OSCEngineReceiver.cpp index a63c826b..f71bdb83 100644 --- a/src/libs/engine/OSCEngineReceiver.cpp +++ b/src/libs/engine/OSCEngineReceiver.cpp @@ -70,7 +70,7 @@ OSCEngineReceiver::OSCEngineReceiver(Engine& engine, size_t queue_size, uint16_t } // For debugging, print all incoming OSC messages - lo_server_add_method(_server, NULL, NULL, generic_cb, NULL); + //lo_server_add_method(_server, NULL, NULL, generic_cb, NULL); // Set response address for this message. // It's important this is first and returns nonzero. diff --git a/src/libs/engine/QueuedEngineInterface.hpp b/src/libs/engine/QueuedEngineInterface.hpp index 17f8c75a..3aba9c7e 100644 --- a/src/libs/engine/QueuedEngineInterface.hpp +++ b/src/libs/engine/QueuedEngineInterface.hpp @@ -62,12 +62,13 @@ public: QueuedEngineInterface(Engine& engine, size_t queued_size, size_t stamped_size); virtual ~QueuedEngineInterface() {} + std::string uri() const { return "ingen:internal"; } + void set_next_response_id(int32_t id); // Client registration virtual void register_client(ClientInterface* client); virtual void unregister_client(const string& uri); - // Engine commands virtual void load_plugins(); diff --git a/src/libs/gui/ConnectWindow.cpp b/src/libs/gui/ConnectWindow.cpp index 03f8408a..eb095af5 100644 --- a/src/libs/gui/ConnectWindow.cpp +++ b/src/libs/gui/ConnectWindow.cpp @@ -29,6 +29,7 @@ #include "engine/Engine.hpp" #include "engine/QueuedEngineInterface.hpp" #include "client/OSCClientReceiver.hpp" +#include "client/HTTPClientReceiver.hpp" #include "client/OSCEngineSender.hpp" #include "client/ThreadedSigClientInterface.hpp" #include "client/ClientStore.hpp" @@ -143,7 +144,9 @@ ConnectWindow::set_connecting_widget_states() void ConnectWindow::connect(bool existing) { - assert(!_attached); + if (_attached) + _attached = false; + assert(!App::instance().client()); _connect_stage = 0; @@ -153,15 +156,22 @@ ConnectWindow::connect(bool existing) if (_mode == CONNECT_REMOTE) { if (!existing) { - const string url = (_widgets_loaded ? _url_entry->get_text() : "osc.udp://localhost:16180"); + const string url = (_widgets_loaded ? (string)_url_entry->get_text() : world->engine->uri()); world->engine = SharedPtr<EngineInterface>(new OSCEngineSender(url)); } - - // FIXME: static args + SharedPtr<ThreadedSigClientInterface> tsci(new ThreadedSigClientInterface(1024)); - SharedPtr<OSCClientReceiver> client(new OSCClientReceiver(16181, tsci)); - App::instance().attach(tsci, client); + SharedPtr<Raul::Deletable> client; + + const string& uri = world->engine->uri(); + const string& scheme = uri.substr(0, uri.find(":")); + if (scheme == "osc.udp" || scheme == "osc.tcp") + client = SharedPtr<OSCClientReceiver>(new OSCClientReceiver(16181, tsci)); // FIXME: port + else if (scheme == "http") + client = SharedPtr<HTTPClientReceiver>(new HTTPClientReceiver(world, uri, tsci)); + App::instance().attach(tsci, client); + Glib::signal_timeout().connect( sigc::mem_fun(App::instance(), &App::gtk_main_iteration), 40, G_PRIORITY_DEFAULT); @@ -377,7 +387,7 @@ ConnectWindow::gtk_callback() assert(App::instance().client()); App::instance().client()->signal_response_ok.connect( - sigc::mem_fun(this, &ConnectWindow::response_ok_received)); + sigc::mem_fun(this, &ConnectWindow::on_response)); _ping_id = abs(rand()) / 2 * 2; // avoid -1 App::instance().engine()->set_next_response_id(_ping_id); @@ -391,7 +401,7 @@ ConnectWindow::gtk_callback() ++_connect_stage; } else if (_connect_stage == 1) { - if (_attached) { + if (_attached || App::instance().client()->enabled()) { App::instance().engine()->activate(); ++_connect_stage; } else { diff --git a/src/libs/gui/ConnectWindow.hpp b/src/libs/gui/ConnectWindow.hpp index 8410783d..fb75d4b2 100644 --- a/src/libs/gui/ConnectWindow.hpp +++ b/src/libs/gui/ConnectWindow.hpp @@ -53,7 +53,7 @@ public: void set_connected_to(SharedPtr<Shared::EngineInterface> engine); void start(Ingen::Shared::World* world); - void response_ok_received(int32_t id) { if (id == _ping_id) _attached = true; } + void on_response(int32_t id) { _attached = true; } private: enum Mode { CONNECT_REMOTE, LAUNCH_REMOTE, INTERNAL }; diff --git a/src/libs/gui/ControlPanel.cpp b/src/libs/gui/ControlPanel.cpp index 84f1163a..032f5758 100644 --- a/src/libs/gui/ControlPanel.cpp +++ b/src/libs/gui/ControlPanel.cpp @@ -69,7 +69,7 @@ ControlPanel::init(SharedPtr<NodeModel> node, uint32_t poly) _voice_control_box->hide(); } - for (PortModelList::const_iterator i = node->ports().begin(); i != node->ports().end(); ++i) { + for (NodeModel::Ports::const_iterator i = node->ports().begin(); i != node->ports().end(); ++i) { add_port(*i); } diff --git a/src/libs/gui/Makefile.am b/src/libs/gui/Makefile.am index fa956fca..48063d35 100644 --- a/src/libs/gui/Makefile.am +++ b/src/libs/gui/Makefile.am @@ -23,7 +23,8 @@ libingen_gui_la_CXXFLAGS = \ @LIBLO_CFLAGS@ \ @REDLANDMM_CFLAGS@ \ @RAUL_CFLAGS@ \ - @SLV2_CFLAGS@ + @SLV2_CFLAGS@ \ + @SOUP_CFLAGS@ libingen_gui_la_LDFLAGS = -no-undefined -module -avoid-version @@ -40,7 +41,8 @@ libingen_gui_la_LIBADD = \ @LIBLO_LIBS@ \ @REDLANDMM_LIBS@ \ @RAUL_LIBS@ \ - @SLV2_LIBS@ + @SLV2_LIBS@ \ + @SOUP_LIBS@ libingen_gui_la_SOURCES = \ gui.hpp \ diff --git a/src/libs/gui/NodeControlWindow.cpp b/src/libs/gui/NodeControlWindow.cpp index 95a07b2b..293d28f5 100644 --- a/src/libs/gui/NodeControlWindow.cpp +++ b/src/libs/gui/NodeControlWindow.cpp @@ -114,7 +114,7 @@ NodeControlWindow::resize() void NodeControlWindow::on_show() { - for (PortModelList::const_iterator i = _node->ports().begin(); + for (NodeModel::Ports::const_iterator i = _node->ports().begin(); i != _node->ports().end(); ++i) if ((*i)->type().is_control() && (*i)->is_input()) App::instance().engine()->request_port_value((*i)->path()); diff --git a/src/libs/gui/NodeMenu.cpp b/src/libs/gui/NodeMenu.cpp index 05139540..529eb52c 100644 --- a/src/libs/gui/NodeMenu.cpp +++ b/src/libs/gui/NodeMenu.cpp @@ -141,7 +141,7 @@ bool NodeMenu::has_control_inputs() { const NodeModel* const nm = (NodeModel*)_object.get(); - for (PortModelList::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) + for (NodeModel::Ports::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) if ((*i)->is_input() && (*i)->type().is_control()) return true; diff --git a/src/libs/gui/NodeModule.cpp b/src/libs/gui/NodeModule.cpp index 21415be9..b3898b94 100644 --- a/src/libs/gui/NodeModule.cpp +++ b/src/libs/gui/NodeModule.cpp @@ -90,7 +90,7 @@ NodeModule::create(boost::shared_ptr<PatchCanvas> canvas, SharedPtr<NodeModel> n for (GraphObject::Variables::const_iterator m = node->variables().begin(); m != node->variables().end(); ++m) ret->set_variable(m->first, m->second); - for (PortModelList::const_iterator p = node->ports().begin(); p != node->ports().end(); ++p) { + for (NodeModel::Ports::const_iterator p = node->ports().begin(); p != node->ports().end(); ++p) { ret->add_port(*p, false); } @@ -151,7 +151,7 @@ NodeModule::embed_gui(bool embed) if (_gui_widget) { _gui_widget->show_all(); - for (PortModelList::const_iterator p = _node->ports().begin(); + for (NodeModel::Ports::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p) if ((*p)->type().is_control() && (*p)->is_output()) App::instance().engine()->set_property((*p)->path(), "ingen:broadcast", true); @@ -162,7 +162,7 @@ NodeModule::embed_gui(bool embed) FlowCanvas::Module::embed(NULL); _plugin_ui.reset(); - for (PortModelList::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p) + for (NodeModel::Ports::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p) if ((*p)->type().is_control() && (*p)->is_output()) App::instance().engine()->set_property((*p)->path(), "ingen:broadcast", false); } @@ -262,7 +262,7 @@ void NodeModule::initialise_gui_values() { uint32_t index=0; - for (PortModelList::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p) { + for (NodeModel::Ports::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p) { if ((*p)->type().is_control()) value_changed(index, (*p)->value()); ++index; diff --git a/src/libs/gui/NodePropertiesWindow.cpp b/src/libs/gui/NodePropertiesWindow.cpp index 9848d872..ae2c23b5 100644 --- a/src/libs/gui/NodePropertiesWindow.cpp +++ b/src/libs/gui/NodePropertiesWindow.cpp @@ -53,8 +53,6 @@ NodePropertiesWindow::set_node(SharedPtr<NodeModel> node_model) _node_polyphonic_toggle->set_active(node_model->polyphonic()); const PluginModel* pm = dynamic_cast<const PluginModel*>(node_model->plugin()); - assert(pm); - if (pm) { _plugin_type_label->set_text(pm->type_uri()); _plugin_uri_label->set_text(pm->uri()); diff --git a/src/libs/gui/PatchCanvas.cpp b/src/libs/gui/PatchCanvas.cpp index f527041b..5d064124 100644 --- a/src/libs/gui/PatchCanvas.cpp +++ b/src/libs/gui/PatchCanvas.cpp @@ -269,7 +269,7 @@ PatchCanvas::build() } // Create pseudo modules for ports (ports on this canvas, not on our module) - for (PortModelList::const_iterator i = _patch->ports().begin(); + for (NodeModel::Ports::const_iterator i = _patch->ports().begin(); i != _patch->ports().end(); ++i) { add_port(*i); } @@ -590,8 +590,7 @@ PatchCanvas::paste() clipboard.new_patch("/", _patch->poly()); ClashAvoider avoider(*App::instance().store().get(), _patch->path(), clipboard, &clipboard); - parser->parse_string(App::instance().world(), &avoider, str, "/", - boost::optional<Glib::ustring>(), (Glib::ustring)_patch->path()); + parser->parse_string(App::instance().world(), &avoider, str, "/", _patch->path()); for (Store::iterator i = clipboard.begin(); i != clipboard.end(); ++i) { cout << "************ OBJECT: " << i->first << endl; diff --git a/src/libs/gui/PatchTreeWindow.cpp b/src/libs/gui/PatchTreeWindow.cpp index ee831cb3..87393cec 100644 --- a/src/libs/gui/PatchTreeWindow.cpp +++ b/src/libs/gui/PatchTreeWindow.cpp @@ -89,7 +89,7 @@ PatchTreeWindow::add_patch(SharedPtr<PatchModel> pm) Gtk::TreeModel::Row row = *iter; if (pm->path() == "/") { SharedPtr<OSCEngineSender> osc_sender = PtrCast<OSCEngineSender>(App::instance().engine()); - string root_name = osc_sender ? osc_sender->engine_url() : "Internal"; + string root_name = osc_sender ? osc_sender->uri() : "Internal"; // Hack off trailing '/' if it's there (ugly) //if (root_name.substr(root_name.length()-1,1) == "/") // root_name = root_name.substr(0, root_name.length()-1); diff --git a/src/libs/gui/PatchWindow.cpp b/src/libs/gui/PatchWindow.cpp index 125adeea..01f74436 100644 --- a/src/libs/gui/PatchWindow.cpp +++ b/src/libs/gui/PatchWindow.cpp @@ -210,7 +210,7 @@ PatchWindow::set_patch(SharedPtr<PatchModel> patch, SharedPtr<PatchView> view) _menu_view_control_window->property_sensitive() = false; - for (PortModelList::const_iterator p = patch->ports().begin(); + for (NodeModel::Ports::const_iterator p = patch->ports().begin(); p != patch->ports().end(); ++p) { if ((*p)->type().is_control() && (*p)->is_input()) { _menu_view_control_window->property_sensitive() = true; @@ -257,7 +257,7 @@ PatchWindow::patch_port_removed(SharedPtr<PortModel> port) bool found_control = false; - for (PortModelList::const_iterator i = _patch->ports().begin(); i != _patch->ports().end(); ++i) { + for (NodeModel::Ports::const_iterator i = _patch->ports().begin(); i != _patch->ports().end(); ++i) { if ((*i)->type().is_control() && (*i)->is_input()) { found_control = true; break; diff --git a/src/libs/serialisation/Parser.cpp b/src/libs/serialisation/Parser.cpp index cc8b4e4b..79c69648 100644 --- a/src/libs/serialisation/Parser.cpp +++ b/src/libs/serialisation/Parser.cpp @@ -63,7 +63,7 @@ Parser::parse_document( Ingen::Shared::CommonInterface* target, const Glib::ustring& document_uri, Glib::ustring object_uri, - boost::optional<Glib::ustring> engine_base, + Glib::ustring engine_base, boost::optional<Raul::Symbol> symbol, boost::optional<GraphObject::Variables> data) { @@ -74,7 +74,7 @@ Parser::parse_document( else cout << "Parsing " << object_uri << " from " << document_uri << endl; - return parse(world, target, model, document_uri, object_uri, engine_base, symbol, data);; + return parse(world, target, model, document_uri, engine_base, object_uri, symbol, data);; } @@ -84,8 +84,8 @@ Parser::parse_string( Ingen::Shared::CommonInterface* target, const Glib::ustring& str, const Glib::ustring& base_uri, + Glib::ustring engine_base, boost::optional<Glib::ustring> object_uri, - boost::optional<Glib::ustring> engine_base, boost::optional<Raul::Symbol> symbol, boost::optional<GraphObject::Variables> data) { @@ -96,10 +96,11 @@ Parser::parse_string( else cout << "Parsing all objects found in string (base " << base_uri << ")" << endl; - bool ret = parse(world, target, model, base_uri, object_uri, engine_base, symbol, data); + bool ret = parse(world, target, model, base_uri, engine_base, object_uri, symbol, data); if (ret) { const Glib::ustring subject = Glib::ustring("<") + base_uri + Glib::ustring(">"); - parse_connections(world, target, model, base_uri, subject, (engine_base ? (string)engine_base.get() : "/")); + parse_connections(world, target, model, base_uri, subject, + Path((engine_base == "") ? "/" : engine_base)); } return ret; @@ -112,13 +113,16 @@ Parser::parse( Ingen::Shared::CommonInterface* target, Redland::Model& model, Glib::ustring base_uri, + Glib::ustring engine_base, boost::optional<Glib::ustring> object_uri, - boost::optional<Glib::ustring> engine_base, boost::optional<Raul::Symbol> symbol, boost::optional<GraphObject::Variables> data) { const Redland::Node::Type res = Redland::Node::RESOURCE; Glib::ustring query_str; + if (object_uri && object_uri.get()[0] == '/') + object_uri = object_uri.get().substr(1); + if (object_uri) query_str = Glib::ustring("SELECT DISTINCT ?class WHERE { <") + object_uri.get() + "> a ?class . }"; else @@ -132,8 +136,13 @@ Parser::parse( const Redland::Node in_port_class(*world->rdf_world, res, NS_INGEN "InputPort"); const Redland::Node out_port_class(*world->rdf_world, res, NS_INGEN "OutputPort"); - const Redland::Node subject_uri(*world->rdf_world, res, - (object_uri ? object_uri.get() : "http://example.org")); + string subject_str = ((object_uri && object_uri.get() != "") ? object_uri.get() : base_uri); + if (subject_str[0] == '/') + subject_str = subject_str.substr(1); + if (subject_str == "") + subject_str = base_uri; + + const Redland::Node subject_uri(*world->rdf_world, res, subject_str); bool ret = false; @@ -141,7 +150,9 @@ Parser::parse( const Redland::Node subject = (object_uri ? subject_uri : (*i)["subject"]); const Redland::Node rdf_class = (*i)["class"]; if (!object_uri) { - std::string path_str = "/" + uri_relative_to_base(base_uri, subject.to_c_string()); + std::string path_str = uri_relative_to_base(base_uri, subject.to_c_string()); + if (path_str[0] != '/') + path_str = string("/").append(path_str); if (Path(path_str).parent() != "/") continue; } @@ -150,12 +161,13 @@ Parser::parse( rdf_class == in_port_class || rdf_class == out_port_class) { Raul::Path path("/"); if (base_uri != subject.to_c_string()) { - string path_str = string("/") + (string)uri_relative_to_base( - base_uri, subject.to_c_string()); + string path_str = (string)uri_relative_to_base(base_uri, subject.to_c_string()); + if (path_str[0] != '/') + path_str = string("/").append(path_str); if (Path::is_valid(path_str)) { path = path_str; } else { - cerr << "[Parser] ERROR: Invalid path " << path << endl; + cerr << "[Parser] ERROR: Invalid path '" << path << "'" << endl; continue; } } @@ -164,8 +176,8 @@ Parser::parse( continue; if (rdf_class == patch_class) { - ret = parse_patch(world, target, model, base_uri, subject.to_c_string(), - engine_base.get(), data); + ret = parse_patch(world, target, model, base_uri, engine_base, + subject.to_c_string(), data); if (ret) target->set_variable(path, "ingen:document", Atom(base_uri.c_str())); } else if (rdf_class == node_class) { @@ -193,8 +205,8 @@ Parser::parse_patch( Ingen::Shared::CommonInterface* target, Redland::Model& model, const Glib::ustring& base_uri, - const Glib::ustring& object_uri, Glib::ustring engine_base, + const Glib::ustring& object_uri, boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()) { std::set<Path> created; @@ -222,6 +234,7 @@ Parser::parse_patch( if (results.size() == 0) { cerr << "[Parser] ERROR: No polyphony found!" << endl; + cerr << "Query was:" << endl << query.string() << endl; return false; } @@ -237,10 +250,12 @@ Parser::parse_patch( patch_path = "/"; else if (engine_base[engine_base.length()-1] == '/') patch_path = Path(engine_base + symbol); - else + else if (Path::is_valid(engine_base)) patch_path = (Path)engine_base; + else + cerr << "WARNING: Illegal engine base path '" << engine_base << "', loading patch to root" << endl; - if (patch_path != "/") + //if (patch_path != "/") target->new_patch(patch_path, patch_poly); /* Plugin nodes */ diff --git a/src/libs/serialisation/Parser.hpp b/src/libs/serialisation/Parser.hpp index 2e088f51..7b8a35eb 100644 --- a/src/libs/serialisation/Parser.hpp +++ b/src/libs/serialisation/Parser.hpp @@ -44,8 +44,8 @@ public: Ingen::Shared::World* world, Shared::CommonInterface* target, const Glib::ustring& document_uri, + Glib::ustring engine_base, Glib::ustring object_uri, - boost::optional<Glib::ustring> engine_base=boost::optional<Glib::ustring>(), boost::optional<Raul::Symbol> symbol=boost::optional<Raul::Symbol>(), boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()); @@ -54,8 +54,8 @@ public: Shared::CommonInterface* target, const Glib::ustring& str, const Glib::ustring& base_uri, + Glib::ustring engine_base, boost::optional<Glib::ustring> object_uri=boost::optional<Glib::ustring>(), - boost::optional<Glib::ustring> engine_base=boost::optional<Glib::ustring>(), boost::optional<Raul::Symbol> symbol=boost::optional<Raul::Symbol>(), boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()); @@ -68,8 +68,8 @@ private: Shared::CommonInterface* target, Redland::Model& model, Glib::ustring base_uri, + Glib::ustring engine_base, boost::optional<Glib::ustring> object_uri=boost::optional<Glib::ustring>(), - boost::optional<Glib::ustring> engine_base=boost::optional<Glib::ustring>(), boost::optional<Raul::Symbol> symbol=boost::optional<Raul::Symbol>(), boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()); @@ -78,8 +78,8 @@ private: Ingen::Shared::CommonInterface* target, Redland::Model& model, const Glib::ustring& base_uri, - const Glib::ustring& object_uri, Glib::ustring engine_base, + const Glib::ustring& object_uri, boost::optional<GraphObject::Variables> data); bool parse_node( diff --git a/src/libs/shared/OSCSender.cpp b/src/libs/shared/OSCSender.cpp index 340786db..3936cf96 100644 --- a/src/libs/shared/OSCSender.cpp +++ b/src/libs/shared/OSCSender.cpp @@ -94,8 +94,8 @@ void OSCSender::send_message(const char* path, lo_message msg) { // FIXME: size? liblo doesn't export this. - // Don't want to exceed max UDP packet size (1500 bytes?) - static const size_t MAX_BUNDLE_SIZE = 1500 - 32*5; + // Don't want to exceed max UDP packet size (good default value?) + static const size_t MAX_BUNDLE_SIZE = 1024; if (!_enabled) return; diff --git a/src/libs/shared/OSCSender.hpp b/src/libs/shared/OSCSender.hpp index 16b6dd22..da91caed 100644 --- a/src/libs/shared/OSCSender.hpp +++ b/src/libs/shared/OSCSender.hpp @@ -27,7 +27,7 @@ namespace Shared { class OSCSender { public: OSCSender(); - ~OSCSender(); + virtual ~OSCSender() {} lo_address address() const { return _address; } diff --git a/src/progs/ingen/main.cpp b/src/progs/ingen/main.cpp index d0efb113..c8adf207 100644 --- a/src/progs/ingen/main.cpp +++ b/src/progs/ingen/main.cpp @@ -133,14 +133,14 @@ main(int argc, char** argv) cerr << "Unable to load client module." << endl; } - /* If we don't have a local engine interface (for GUI), use OSC */ + /* If we don't have a local engine interface (for GUI), use network */ if (client_module && ! engine_interface) { - SharedPtr<Shared::EngineInterface> (*new_osc_interface)(const std::string&) = NULL; + SharedPtr<Shared::EngineInterface> (*new_remote_interface)(const std::string&) = NULL; - if (client_module->get_symbol("new_osc_interface", (void*&)new_osc_interface)) { - engine_interface = new_osc_interface(args.connect_arg); + if (client_module->get_symbol("new_remote_interface", (void*&)new_remote_interface)) { + engine_interface = new_remote_interface(args.connect_arg); } else { - cerr << "Unable to find symbol 'new_osc_interface' in " + cerr << "Unable to find symbol 'new_remote_interface' in " "ingen_client module, aborting." << endl; return -1; } @@ -157,7 +157,7 @@ main(int argc, char** argv) /* Load a patch */ if (args.load_given && engine_interface) { - boost::optional<Glib::ustring> engine_base; + Glib::ustring engine_base = "/"; if (args.path_given) engine_base = string(args.path_arg) + "/"; @@ -185,7 +185,7 @@ main(int argc, char** argv) engine_interface->load_plugins(); - parser->parse_document(world, engine_interface.get(), uri, uri, engine_base); + parser->parse_document(world, engine_interface.get(), uri, engine_base, uri); } else { cerr << "Unable to load serialisation module, aborting." << endl; |