diff options
Diffstat (limited to 'src/engine/HTTPEngineReceiver.cpp')
-rw-r--r-- | src/engine/HTTPEngineReceiver.cpp | 207 |
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 |