summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2015-05-30 18:15:59 +0000
committerDavid Robillard <d@drobilla.net>2015-05-30 18:15:59 +0000
commitd2760bc7ec7845b4e11966d035a91e863efc21e8 (patch)
tree7e4121e2d8335ea0a0714d2e2e1bf738ff163e75
parentecdcc5f2c3d98a551ff8e5ae6b546704bf6aa881 (diff)
downloadingen-d2760bc7ec7845b4e11966d035a91e863efc21e8.tar.gz
ingen-d2760bc7ec7845b4e11966d035a91e863efc21e8.tar.bz2
ingen-d2760bc7ec7845b4e11966d035a91e863efc21e8.zip
Preliminary server-side save support.
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5690 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--src/AtomReader.cpp26
-rw-r--r--src/Configuration.cpp1
-rw-r--r--src/ingen/ingen.cpp16
-rw-r--r--src/server/events/Copy.cpp78
-rw-r--r--src/server/events/Copy.hpp4
5 files changed, 109 insertions, 16 deletions
diff --git a/src/AtomReader.cpp b/src/AtomReader.cpp
index 28f511d6..c9f2f3ac 100644
--- a/src/AtomReader.cpp
+++ b/src/AtomReader.cpp
@@ -275,6 +275,32 @@ AtomReader::write(const LV2_Atom* msg)
get_props(remove, remove_props);
_iface.delta(*subject_uri, remove_props, add_props);
+ } else if (obj->body.otype == _uris.patch_Copy) {
+ if (!subject) {
+ _log.warn("Copy message has no subject\n");
+ return false;
+ }
+
+ const LV2_Atom* dest = NULL;
+ lv2_atom_object_get(obj, (LV2_URID)_uris.patch_destination, &dest, 0);
+ if (!dest) {
+ _log.warn("Copy message has no destination\n");
+ return false;
+ }
+
+ boost::optional<Raul::Path> subject_path(atom_to_path(subject));
+ if (!subject_path) {
+ _log.warn("Copy message has non-path subject\n");
+ return false;
+ }
+
+ boost::optional<Raul::URI> dest_uri(atom_to_uri(dest));
+ if (!dest_uri) {
+ _log.warn("Copy message has non-URI destination\n");
+ return false;
+ }
+
+ _iface.copy(*subject_path, *dest_uri);
} else if (obj->body.otype == _uris.patch_Move) {
if (!subject) {
_log.warn("Move message has no subject\n");
diff --git a/src/Configuration.cpp b/src/Configuration.cpp
index a2d70dc4..bf464428 100644
--- a/src/Configuration.cpp
+++ b/src/Configuration.cpp
@@ -59,6 +59,7 @@ Configuration::Configuration(Forge& forge)
add("jackServer", "jack-server", 's', "JACK server name", GLOBAL, forge.String, forge.alloc(""));
add("uuid", "uuid", 'u', "JACK session UUID", SESSION, forge.String, Atom());
add("load", "load", 'l', "Load graph", SESSION, forge.String, Atom());
+ add("save", "save", 'o', "Save graph", SESSION, forge.String, Atom());
add("execute", "execute", 'x', "File of commands to execute", SESSION, forge.String, Atom());
add("path", "path", 'L', "Target path for loaded graph", SESSION, forge.String, Atom());
add("queueSize", "queue-size", 'q', "Event queue size", GLOBAL, forge.Int, forge.make(4096));
diff --git a/src/ingen/ingen.cpp b/src/ingen/ingen.cpp
index 24cfb029..164eded5 100644
--- a/src/ingen/ingen.cpp
+++ b/src/ingen/ingen.cpp
@@ -183,6 +183,22 @@ main(int argc, char** argv)
world, engine_interface.get(), graph, parent, symbol);
}
+ // Save the currently loaded graph
+ if (conf.option("save").is_valid()) {
+ const char* path = conf.option("save").ptr<char>();
+ if (serd_uri_string_has_scheme((const uint8_t*)path)) {
+ std::cout << "Saving to " << path << std::endl;
+ engine_interface->copy(Raul::Path("/"), Raul::URI(path));
+ } else {
+ SerdNode uri = serd_node_new_file_uri(
+ (const uint8_t*)path, NULL, NULL, true);
+ std::cout << "Saving to " << (const char*)uri.buf << std::endl;
+ engine_interface->copy(Raul::Path("/"),
+ Raul::URI((const char*)uri.buf));
+ serd_node_free(&uri);
+ }
+ }
+
// Set up signal handlers that will set quit_flag on interrupt
signal(SIGINT, ingen_interrupt);
signal(SIGTERM, ingen_interrupt);
diff --git a/src/server/events/Copy.cpp b/src/server/events/Copy.cpp
index 14009163..4e89bb88 100644
--- a/src/server/events/Copy.cpp
+++ b/src/server/events/Copy.cpp
@@ -14,8 +14,10 @@
along with Ingen. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "ingen/Serialiser.hpp"
#include "ingen/Store.hpp"
#include "raul/Path.hpp"
+#include "serd/serd.h"
#include "BlockImpl.hpp"
#include "Broadcaster.hpp"
@@ -38,6 +40,7 @@ Copy::Copy(Engine& engine,
: Event(engine, client, id, timestamp)
, _old_path(old_path)
, _new_uri(new_uri)
+ , _old_block(NULL)
, _parent(NULL)
, _block(NULL)
, _compiled_graph(NULL)
@@ -46,15 +49,7 @@ Copy::Copy(Engine& engine,
bool
Copy::pre_process()
{
- if (_old_path.empty() ||
- !Node::uri_is_path(_new_uri) ||
- _new_uri == Node::root_graph_uri()) {
- return Event::pre_process_done(Status::BAD_REQUEST);
- }
-
- // Only support a single source for now
- const Raul::Path new_path = Node::uri_to_path(_new_uri);
- if (!Raul::Symbol::is_valid(new_path.symbol())) {
+ if (_old_path.empty() || _new_uri == Node::root_graph_uri()) {
return Event::pre_process_done(Status::BAD_REQUEST);
}
@@ -66,17 +61,36 @@ Copy::pre_process()
return Event::pre_process_done(Status::NOT_FOUND, _old_path);
}
+ // Ensure it is a block (ports are not supported for now)
+ if (!(_old_block = dynamic_ptr_cast<BlockImpl>(i->second))) {
+ return Event::pre_process_done(Status::BAD_OBJECT_TYPE, _old_path);
+ }
+
+ if (Node::uri_is_path(_new_uri)) {
+ // Copy to path within the engine
+ return copy_to_engine();
+ } else if (_new_uri.scheme() == "file") {
+ // Copy to filesystem path (i.e. save)
+ return copy_to_filesystem();
+ } else {
+ return Event::pre_process_done(Status::BAD_REQUEST);
+ }
+}
+
+bool
+Copy::copy_to_engine()
+{
+ // Only support a single source for now
+ const Raul::Path new_path = Node::uri_to_path(_new_uri);
+ if (!Raul::Symbol::is_valid(new_path.symbol())) {
+ return Event::pre_process_done(Status::BAD_REQUEST);
+ }
+
// Ensure the new node doesn't already exists
if (_engine.store()->find(new_path) != _engine.store()->end()) {
return Event::pre_process_done(Status::EXISTS, new_path);
}
- // Get old node block, or fail (ports not supported for now)
- BlockImpl* old_block = dynamic_cast<BlockImpl*>(i->second.get());
- if (!old_block) {
- return Event::pre_process_done(Status::BAD_OBJECT_TYPE, _old_path);
- }
-
// Find new parent graph
const Raul::Path parent_path = new_path.parent();
const Store::iterator p = _engine.store()->find(parent_path);
@@ -89,7 +103,7 @@ Copy::pre_process()
// Create new block
if (!(_block = dynamic_cast<BlockImpl*>(
- old_block->duplicate(_engine, Raul::Symbol(new_path.symbol()), _parent)))) {
+ _old_block->duplicate(_engine, Raul::Symbol(new_path.symbol()), _parent)))) {
return Event::pre_process_done(Status::INTERNAL_ERROR);
}
@@ -107,6 +121,38 @@ Copy::pre_process()
return Event::pre_process_done(Status::SUCCESS);
}
+bool
+Copy::copy_to_filesystem()
+{
+ // Ensure source is a graph
+ SPtr<GraphImpl> graph = dynamic_ptr_cast<GraphImpl>(_old_block);
+ if (!graph) {
+ return Event::pre_process_done(Status::BAD_OBJECT_TYPE, _old_path);
+ }
+
+ // Parse filename from target URI
+ const uint8_t* uri = (const uint8_t*)_new_uri.c_str();
+ uint8_t* path = serd_file_uri_parse(uri, NULL);
+ const std::string filename = (const char*)path;
+ free(path);
+
+ if (!_engine.world()->serialiser()) {
+ return Event::pre_process_done(Status::INTERNAL_ERROR);
+ }
+
+ std::lock_guard<std::mutex> lock(_engine.world()->rdf_mutex());
+
+ if (filename.find(".ingen") != std::string::npos) {
+ _engine.world()->serialiser()->write_bundle(graph, _new_uri/*filename*/);
+ } else {
+ _engine.world()->serialiser()->start_to_file(graph->path(), _new_uri);
+ _engine.world()->serialiser()->serialise(graph);
+ _engine.world()->serialiser()->finish();
+ }
+
+ return Event::pre_process_done(Status::SUCCESS);
+}
+
void
Copy::execute(ProcessContext& context)
{
diff --git a/src/server/events/Copy.hpp b/src/server/events/Copy.hpp
index 26c0c815..e40bfa3b 100644
--- a/src/server/events/Copy.hpp
+++ b/src/server/events/Copy.hpp
@@ -59,8 +59,12 @@ public:
void post_process();
private:
+ bool copy_to_engine();
+ bool copy_to_filesystem();
+
const Raul::Path _old_path;
const Raul::URI _new_uri;
+ SPtr<BlockImpl> _old_block;
GraphImpl* _parent;
BlockImpl* _block;
CompiledGraph* _compiled_graph;