From a7d83f19b08eb4c6f79a82fe60c2b86db13f4420 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 24 Nov 2018 13:44:03 +0100 Subject: Squashed 'waflib/' changes from 6e726eb1..5ea8f99f 5ea8f99f Improve test output spacing 0e23b29f Raise exception when test suite fails to ensure non-zero exit status d6de073b Show run time of unit tests 5b655541 Add short configure option for ultra-strict flags 4687ba6d Use gtest-like test output 258903d9 Fix failure count in test group summaries da07e738 Fix verbose tests with Python 3 git-subtree-dir: waflib git-subtree-split: 5ea8f99f6e1246079c1fe6bb590c38a53aadd40d --- src/AtomWriter.cpp | 652 ----------------------------------------------------- 1 file changed, 652 deletions(-) delete mode 100644 src/AtomWriter.cpp (limited to 'src/AtomWriter.cpp') diff --git a/src/AtomWriter.cpp b/src/AtomWriter.cpp deleted file mode 100644 index f235aafc..00000000 --- a/src/AtomWriter.cpp +++ /dev/null @@ -1,652 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2017 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or 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 Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -/** @page protocol Ingen Protocol - * @tableofcontents - * - * @section introduction Controlling Ingen - * - * Ingen is controlled via a simple RDF-based protocol. This conceptual - * protocol can be used in two concrete ways: - * - * 1. When Ingen is running as a process, a socket accepts messages in - * (textual) Turtle syntax, and responds in the same syntax. Transfers are - * delimited by NULL characters in the stream, so the client knows when to - * finish parsing to interpret responses. By default, Ingen listens on - * unix:///tmp/ingen.sock and tcp://localhost:16180 - * - * 2. When Ingen is running as an LV2 plugin, the control and notify ports - * accept and respond using (binary) LV2 atoms. Messages are read and written - * as events with atom:Object bodies. The standard rules for LV2 event - * transmission apply, but note that the graph manipulations described here are - * executed asynchronously and not with sample accuracy, so the response may - * come at a later frame or cycle. - * - * For documentation purposes, this page discusses messages in Turtle syntax, - * but the same protocol is used in the LV2 case, just in a more compact binary - * encoding. - * - * Conceptually, Ingen represents a tree of objects, each of which has a path - * (like /main/in or /main/osc/out) and a set of properties. A property is a - * URI key and some value. All changes to Ingen are represented as - * manipulations of this tree of dictionaries. The core of the protocol is - * based on the LV2 patch extension, which defines several messages for - * manipulating data in this model which resemble HTTP methods. - */ - -#include -#include -#include - -#include - -#include "ingen/AtomSink.hpp" -#include "ingen/AtomWriter.hpp" -#include "ingen/Node.hpp" -#include "ingen/URIMap.hpp" -#include "raul/Path.hpp" -#include "serd/serd.h" - -namespace Ingen { - -AtomWriter::AtomWriter(URIMap& map, URIs& uris, AtomSink& sink) - : _map(map) - , _uris(uris) - , _sink(sink) -{ - lv2_atom_forge_init(&_forge, &map.urid_map_feature()->urid_map); - _out.set_forge_sink(&_forge); -} - -void -AtomWriter::finish_msg() -{ - assert(!_forge.stack); - _sink.write(_out.atom()); - _out.clear(); -} - -void -AtomWriter::message(const Message& message) -{ - boost::apply_visitor(*this, message); -} - -/** @page protocol - * @subsection Bundles - * - * An [ingen:BundleStart](http://drobilla.net/ns/ingen#BundleStart) marks the - * start of a bundle in the operation stream. A bundle groups a series of - * messages for coarse-grained undo or atomic execution. - * - * @code{.ttl} - * [] a ingen:BundleStart . - * @endcode - - * An [ingen:BundleEnd](http://drobilla.net/ns/ingen#BundleEnd) marks the end - * of a bundle in the operation stream. - * - * @code{.ttl} - * [] a ingen:BundleEnd . - * @endcode - */ -void -AtomWriter::operator()(const BundleBegin& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.ingen_BundleStart, message.seq); - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -void -AtomWriter::operator()(const BundleEnd& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.ingen_BundleEnd, message.seq); - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -void -AtomWriter::forge_uri(const URI& uri) -{ - if (serd_uri_string_has_scheme((const uint8_t*)uri.c_str())) { - lv2_atom_forge_urid(&_forge, _map.map_uri(uri.c_str())); - } else { - lv2_atom_forge_uri(&_forge, uri.c_str(), uri.length()); - } -} - -void -AtomWriter::forge_properties(const Properties& properties) -{ - for (auto p : properties) { - lv2_atom_forge_key(&_forge, _map.map_uri(p.first.c_str())); - if (p.second.type() == _forge.URI) { - forge_uri(URI(p.second.ptr())); - } else { - lv2_atom_forge_atom(&_forge, p.second.size(), p.second.type()); - lv2_atom_forge_write(&_forge, p.second.get_body(), p.second.size()); - } - } -} - -void -AtomWriter::forge_arc(const Raul::Path& tail, const Raul::Path& head) -{ - LV2_Atom_Forge_Frame arc; - lv2_atom_forge_object(&_forge, &arc, 0, _uris.ingen_Arc); - lv2_atom_forge_key(&_forge, _uris.ingen_tail); - forge_uri(path_to_uri(tail)); - lv2_atom_forge_key(&_forge, _uris.ingen_head); - forge_uri(path_to_uri(head)); - lv2_atom_forge_pop(&_forge, &arc); -} - -void -AtomWriter::forge_request(LV2_Atom_Forge_Frame* frame, LV2_URID type, int32_t id) -{ - lv2_atom_forge_object(&_forge, frame, 0, type); - - if (id) { - lv2_atom_forge_key(&_forge, _uris.patch_sequenceNumber); - lv2_atom_forge_int(&_forge, id); - } -} - -void -AtomWriter::forge_context(Resource::Graph ctx) -{ - switch (ctx) { - case Resource::Graph::EXTERNAL: - lv2_atom_forge_key(&_forge, _uris.patch_context); - forge_uri(_uris.ingen_externalContext); - break; - case Resource::Graph::INTERNAL: - lv2_atom_forge_key(&_forge, _uris.patch_context); - forge_uri(_uris.ingen_internalContext); - break; - default: break; - } -} - -/** @page protocol - * @section methods Methods - * @subsection Put - * - * Send a [Put](http://lv2plug.in/ns/ext/patch#Put) to set properties on an - * object, creating it if necessary. - * - * If the object already exists, all existing object properties with keys that - * match any property in the message are first removed. Other properties are - * left unchanged. - * - * If the object does not yet exist, the message must contain sufficient - * information to create it, including at least one rdf:type property. - * - * @code{.ttl} - * [] - * a patch:Put ; - * patch:subject ; - * patch:body [ - * a ingen:Block ; - * lv2:prototype - * ] . - * @endcode - */ -void -AtomWriter::operator()(const Put& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.patch_Put, message.seq); - forge_context(message.ctx); - lv2_atom_forge_key(&_forge, _uris.patch_subject); - forge_uri(message.uri); - lv2_atom_forge_key(&_forge, _uris.patch_body); - - LV2_Atom_Forge_Frame body; - lv2_atom_forge_object(&_forge, &body, 0, 0); - forge_properties(message.properties); - lv2_atom_forge_pop(&_forge, &body); - - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * @subsection Patch - * - * Send a [Patch](http://lv2plug.in/ns/ext/patch#Patch) to manipulate the - * properties of an object. A set of properties are first removed, then - * another is added. Analogous to WebDAV PROPPATCH. - * - * The special value [patch:wildcard](http://lv2plug.in/ns/ext/patch#wildcard) - * may be used to specify that any value with the given key should be removed. - * - * @code{.ttl} - * [] - * a patch:Patch ; - * patch:subject ; - * patch:add [ - * lv2:name "Osckillator" ; - * ingen:canvasX 32.0 ; - * ingen:canvasY 32.0 ; - * ] ; - * patch:remove [ - * eg:name "Old name" ; # Remove specific value - * ingen:canvasX patch:wildcard ; # Remove all - * ingen:canvasY patch:wildcard ; # Remove all - * ] . - * @endcode - */ -void -AtomWriter::operator()(const Delta& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.patch_Patch, message.seq); - forge_context(message.ctx); - lv2_atom_forge_key(&_forge, _uris.patch_subject); - forge_uri(message.uri); - - lv2_atom_forge_key(&_forge, _uris.patch_remove); - LV2_Atom_Forge_Frame remove_obj; - lv2_atom_forge_object(&_forge, &remove_obj, 0, 0); - forge_properties(message.remove); - lv2_atom_forge_pop(&_forge, &remove_obj); - - lv2_atom_forge_key(&_forge, _uris.patch_add); - LV2_Atom_Forge_Frame add_obj; - lv2_atom_forge_object(&_forge, &add_obj, 0, 0); - forge_properties(message.add); - lv2_atom_forge_pop(&_forge, &add_obj); - - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * @subsection Copy - * - * Send a [Copy](http://lv2plug.in/ns/ext/copy#Copy) to copy an object from - * its current location (subject) to another (destination). - * - * If both the subject and destination are inside Ingen, like block paths, then the old object - * is copied by, for example, creating a new plugin instance. - * - * If the subject is a filename (file URI or atom:Path) and the destination is - * inside Ingen, then the subject must be an Ingen graph file or bundle, which - * is loaded to the specified destination path. - * - * If the subject is inside Ingen and the destination is a filename, then the - * subject is saved to an Ingen bundle at the given destination. - * - * @code{.ttl} - * [] - * a patch:Copy ; - * patch:subject ; - * patch:destination . - * @endcode - */ -void -AtomWriter::operator()(const Copy& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.patch_Copy, message.seq); - lv2_atom_forge_key(&_forge, _uris.patch_subject); - forge_uri(message.old_uri); - lv2_atom_forge_key(&_forge, _uris.patch_destination); - forge_uri(message.new_uri); - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * @subsection Move - * - * Send a [Move](http://lv2plug.in/ns/ext/move#Move) to move an object from its - * current location (subject) to another (destination). - * - * Both subject and destination must be paths in Ingen with the same parent, - * moving between graphs is currently not supported. - * - * @code{.ttl} - * [] - * a patch:Move ; - * patch:subject ; - * patch:destination . - * @endcode - */ -void -AtomWriter::operator()(const Move& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.patch_Move, message.seq); - lv2_atom_forge_key(&_forge, _uris.patch_subject); - forge_uri(path_to_uri(message.old_path)); - lv2_atom_forge_key(&_forge, _uris.patch_destination); - forge_uri(path_to_uri(message.new_path)); - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * @subsection Delete - * - * Send a [Delete](http://lv2plug.in/ns/ext/delete#Delete) to remove an - * object from the engine and destroy it. - * - * All properties of the object are lost, as are all references to the object - * (e.g. any connections to it). - * - * @code{.ttl} - * [] - * a patch:Delete ; - * patch:subject . - * @endcode - */ -void -AtomWriter::operator()(const Del& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.patch_Delete, message.seq); - lv2_atom_forge_key(&_forge, _uris.patch_subject); - forge_uri(message.uri); - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * @subsection Set - * - * Send a [Set](http://lv2plug.in/ns/ext/patch#Set) to set a property on an - * object. Any existing value for that property is removed. - * - * @code{.ttl} - * [] - * a patch:Set ; - * patch:subject ; - * patch:property lv2:name ; - * patch:value "Oscwellator" . - * @endcode - */ -void -AtomWriter::operator()(const SetProperty& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.patch_Set, message.seq); - forge_context(message.ctx); - lv2_atom_forge_key(&_forge, _uris.patch_subject); - forge_uri(message.subject); - lv2_atom_forge_key(&_forge, _uris.patch_property); - lv2_atom_forge_urid(&_forge, _map.map_uri(message.predicate.c_str())); - lv2_atom_forge_key(&_forge, _uris.patch_value); - lv2_atom_forge_atom(&_forge, message.value.size(), message.value.type()); - lv2_atom_forge_write(&_forge, message.value.get_body(), message.value.size()); - - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * @subsection Undo - * - * Use [ingen:Undo](http://drobilla.net/ns/ingen#Undo) to undo the last change - * to the engine. Undo transactions can be delimited using bundle markers, if - * the last operations(s) received were in a bundle, then an Undo will undo the - * effects of that entire bundle. - * - * @code{.ttl} - * [] a ingen:Undo . - * @endcode - */ -void -AtomWriter::operator()(const Undo& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.ingen_Undo, message.seq); - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * @subsection Undo - * - * Use [ingen:Redo](http://drobilla.net/ns/ingen#Redo) to redo the last undone change. - * - * @code{.ttl} - * [] a ingen:Redo . - * @endcode - */ -void -AtomWriter::operator()(const Redo& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.ingen_Redo, message.seq); - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * @subsection Get - * - * Send a [Get](http://lv2plug.in/ns/ext/patch#Get) to get the description - * of the subject. - * - * @code{.ttl} - * [] - * a patch:Get ; - * patch:subject . - * @endcode - */ -void -AtomWriter::operator()(const Get& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.patch_Get, message.seq); - lv2_atom_forge_key(&_forge, _uris.patch_subject); - forge_uri(message.subject); - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * - * @section arcs Arc Manipulation - */ - -/** @page protocol - * @subsection Connect Connecting Ports - * - * Ports are connected by putting an arc with the desired tail (an output port) - * and head (an input port). The tail and head must both be within the - * subject, which must be a graph. - * - * @code{.ttl} - * [] - * a patch:Put ; - * patch:subject ; - * patch:body [ - * a ingen:Arc ; - * ingen:tail ; - * ingen:head ; - * ] . - * @endcode - */ -void -AtomWriter::operator()(const Connect& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.patch_Put, message.seq); - lv2_atom_forge_key(&_forge, _uris.patch_subject); - forge_uri(path_to_uri(Raul::Path::lca(message.tail, message.head))); - lv2_atom_forge_key(&_forge, _uris.patch_body); - forge_arc(message.tail, message.head); - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * @subsection Disconnect Disconnecting Ports - * - * Ports are disconnected by deleting the arc between them. The description of - * the arc is the same as in the put command used to create the connection. - * - * @code{.ttl} - * [] - * a patch:Delete ; - * patch:body [ - * a ingen:Arc ; - * ingen:tail ; - * ingen:head ; - * ] . - * @endcode - */ -void -AtomWriter::operator()(const Disconnect& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.patch_Delete, message.seq); - lv2_atom_forge_key(&_forge, _uris.patch_body); - forge_arc(message.tail, message.head); - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * @subsection DisconnectAll Fully Disconnecting Anything - * - * All arcs to or from anything can be removed by giving the special property - * ingen:incidentTo rather than a specific head and tail. This works for both - * ports and blocks (where the effect is to disconnect everything from ports on - * that block). - * - * @code{.ttl} - * [] - * a patch:Delete ; - * patch:subject ; - * patch:body [ - * a ingen:Arc ; - * ingen:incidentTo - * ] . - * @endcode - */ -void -AtomWriter::operator()(const DisconnectAll& message) -{ - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.patch_Delete, message.seq); - - lv2_atom_forge_key(&_forge, _uris.patch_subject); - forge_uri(path_to_uri(message.graph)); - - lv2_atom_forge_key(&_forge, _uris.patch_body); - LV2_Atom_Forge_Frame arc; - lv2_atom_forge_object(&_forge, &arc, 0, _uris.ingen_Arc); - lv2_atom_forge_key(&_forge, _uris.ingen_incidentTo); - forge_uri(path_to_uri(message.path)); - lv2_atom_forge_pop(&_forge, &arc); - - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -/** @page protocol - * @section Responses - * - * Ingen responds to requests if the patch:sequenceNumber property is set. For - * example: - * @code{.ttl} - * [] - * a patch:Get ; - * patch:sequenceNumber 42 ; - * patch:subject . - * @endcode - * - * Might receive a response like: - * @code{.ttl} - * [] - * a patch:Response ; - * patch:sequenceNumber 42 ; - * patch:subject ; - * patch:body 0 . - * @endcode - * - * Where 0 is a status code, 0 meaning success and any other value being an - * error. Information about status codes, including error message strings, - * are defined in ingen.lv2/errors.ttl. - * - * Note that a response is only a status response, operations that manipulate - * the graph may generate new data on the stream, e.g. the above get request - * would also receive a put that describes /main/osc in the stream immediately - * following the response. - */ -void -AtomWriter::operator()(const Response& response) -{ - const auto& subject = response.subject; - if (!response.id) { - return; - } - - LV2_Atom_Forge_Frame msg; - forge_request(&msg, _uris.patch_Response, 0); - lv2_atom_forge_key(&_forge, _uris.patch_sequenceNumber); - lv2_atom_forge_int(&_forge, response.id); - if (!subject.empty()) { - lv2_atom_forge_key(&_forge, _uris.patch_subject); - lv2_atom_forge_uri(&_forge, subject.c_str(), subject.length()); - } - lv2_atom_forge_key(&_forge, _uris.patch_body); - lv2_atom_forge_int(&_forge, static_cast(response.status)); - lv2_atom_forge_pop(&_forge, &msg); - finish_msg(); -} - -void -AtomWriter::operator()(const Error&) -{ -} - -/** @page protocol - * @section loading Loading and Unloading Bundles - * - * The property ingen:loadedBundle on the engine can be used to load - * or unload bundles from Ingen's world. For example: - * - * @code{.ttl} - * # Load /old.lv2 - * [] - * a patch:Put ; - * patch:subject ; - * patch:body [ - * ingen:loadedBundle - * ] . - * - * # Replace /old.lv2 with /new.lv2 - * [] - * a patch:Patch ; - * patch:subject ; - * patch:remove [ - * ingen:loadedBundle - * ]; - * patch:add [ - * ingen:loadedBundle - * ] . - * @endcode - */ - -} // namespace Ingen -- cgit v1.2.1