summaryrefslogtreecommitdiffstats
path: root/src/engine/HTTPEngineReceiver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/HTTPEngineReceiver.cpp')
-rw-r--r--src/engine/HTTPEngineReceiver.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/engine/HTTPEngineReceiver.cpp b/src/engine/HTTPEngineReceiver.cpp
new file mode 100644
index 00000000..1b21e184
--- /dev/null
+++ b/src/engine/HTTPEngineReceiver.cpp
@@ -0,0 +1,207 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 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 <cstdlib>
+#include <cstdio>
+#include <string>
+#include <boost/format.hpp>
+#include "types.hpp"
+#include <raul/SharedPtr.hpp>
+#include <raul/AtomLiblo.hpp>
+#include "interface/ClientInterface.hpp"
+#include "module/Module.hpp"
+#include "serialisation/serialisation.hpp"
+#include "serialisation/Serialiser.hpp"
+#include "serialisation/Parser.hpp"
+#include "engine/ThreadManager.hpp"
+#include "HTTPEngineReceiver.hpp"
+#include "QueuedEventSource.hpp"
+#include "ClientBroadcaster.hpp"
+#include "EngineStore.hpp"
+
+using namespace std;
+using namespace Ingen::Shared;
+
+namespace Ingen {
+
+
+HTTPEngineReceiver::HTTPEngineReceiver(Engine& engine, uint16_t port)
+ : QueuedEngineInterface(engine, 2, 2)
+ , _server(soup_server_new(SOUP_SERVER_PORT, port, NULL))
+{
+ _receive_thread = new ReceiveThread(*this);
+
+ soup_server_add_handler(_server, NULL, message_callback, this, NULL);
+
+ cout << "Started HTTP server on port " << soup_server_get_port(_server) << endl;
+ Thread::set_name("HTTP receiver");
+
+ if (!engine.world()->serialisation_module)
+ engine.world()->serialisation_module = Ingen::Shared::load_module("ingen_serialisation");
+
+ if (engine.world()->serialisation_module) {
+ if (!engine.world()->serialiser)
+ engine.world()->serialiser = SharedPtr<Serialiser>(
+ Ingen::Serialisation::new_serialiser(engine.world(), engine.engine_store()));
+
+ if (!engine.world()->parser)
+ engine.world()->parser = SharedPtr<Parser>(
+ Ingen::Serialisation::new_parser());
+ } else {
+ cerr << "WARNING: Failed to load ingen_serialisation module, HTTP disabled." << endl;
+ }
+}
+
+
+HTTPEngineReceiver::~HTTPEngineReceiver()
+{
+ deactivate();
+
+ if (_server != NULL) {
+ soup_server_quit(_server);
+ _server = NULL;
+ }
+}
+
+
+void
+HTTPEngineReceiver::activate()
+{
+ QueuedEventSource::activate();
+ _receive_thread->set_name("HTTP Receiver");
+ _receive_thread->start();
+}
+
+
+void
+HTTPEngineReceiver::deactivate()
+{
+ cout << "[HTTPEngineReceiver] Stopped HTTP listening thread" << endl;
+ _receive_thread->stop();
+ QueuedEventSource::deactivate();
+}
+
+
+void
+HTTPEngineReceiver::message_callback(SoupServer* server, SoupMessage* msg, const char* path,
+ GHashTable *query, SoupClientContext* client, void* data)
+{
+ HTTPEngineReceiver* me = (HTTPEngineReceiver*)data;
+
+ SharedPtr<Store> store = me->_engine.world()->store;
+ if (!store) {
+ soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ if (!Path::is_valid(path)) {
+ soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
+ const string& err = (boost::format("Bad path: %1%") % path).str();
+ soup_message_set_response (msg, "text/plain", SOUP_MEMORY_COPY,
+ err.c_str(), err.length());
+ return;
+ }
+
+ if (msg->method == SOUP_METHOD_GET) {
+ Glib::RWLock::ReaderLock lock(store->lock());
+
+ // Find object
+ Store::const_iterator start = store->find(path);
+ if (start == store->end()) {
+ soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
+ const string& err = (boost::format("No such object: %1%") % path).str();
+ soup_message_set_response (msg, "text/plain", SOUP_MEMORY_COPY,
+ err.c_str(), err.length());
+ return;
+ }
+
+ // Get serialiser
+ SharedPtr<Serialiser> serialiser = me->_engine.world()->serialiser;
+ if (!serialiser) {
+ soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
+ soup_message_set_response (msg, "text/plain", SOUP_MEMORY_STATIC,
+ "No serialiser available\n", 24);
+ return;
+ }
+
+#if 0
+ SoupMessageHeaders* in_head = msg->request_headers;
+ const char* str = soup_message_headers_get(in_head, "Accept");
+ cout << "Accept: " << str << endl;
+#endif
+
+ // Serialise object
+ const string response = serialiser->to_string(start->second,
+ "http://example.org", GraphObject::Variables());
+
+#if 0
+ FILE* xhtml_file = fopen("/home/dave/ingen_ui.xhtml", "r");
+ string response;
+ while (!feof(xhtml_file)) {
+ int c = fgetc(xhtml_file);
+ if (c != EOF)
+ response += (char)c;
+ }
+ fclose(xhtml_file);
+#endif
+
+ soup_message_set_status (msg, SOUP_STATUS_OK);
+ soup_message_set_response (msg, "text/plain", SOUP_MEMORY_COPY,
+ response.c_str(), response.length());
+
+ } else if (msg->method == SOUP_METHOD_PUT) {
+ Glib::RWLock::WriterLock lock(store->lock());
+
+ // Be sure object doesn't exist
+ Store::const_iterator start = store->find(path);
+ if (start != store->end()) {
+ soup_message_set_status (msg, SOUP_STATUS_CONFLICT);
+ return;
+ }
+
+ // Get parser
+ SharedPtr<Parser> parser = me->_engine.world()->parser;
+ if (!parser) {
+ soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ //cout << "POST: " << msg->request_body->data << endl;
+
+ // Load object
+ soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
+ } else if (msg->method == SOUP_METHOD_POST) {
+ //cout << "PUT: " << msg->request_body->data << endl;
+ soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
+ } else {
+ soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
+ }
+}
+
+
+/** Override the semaphore driven _run method of QueuedEngineInterface
+ * to wait on HTTP requests and process them immediately in this thread.
+ */
+void
+HTTPEngineReceiver::ReceiveThread::_run()
+{
+ soup_server_run(_receiver._server);
+}
+
+
+} // namespace Ingen