From 79887329f008ba184aac8d7c606859986a9ef20e Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 15 Aug 2008 05:15:31 +0000 Subject: Add primitive read-only HTTP interface (point browser to http://localhost:16180/). git-svn-id: http://svn.drobilla.net/lad/ingen@1390 a436a847-0d15-0410-975c-d299462d15a1 --- src/libs/engine/Engine.cpp | 20 ++++++ src/libs/engine/Engine.hpp | 4 ++ src/libs/engine/HTTPEngineReceiver.cpp | 125 +++++++++++++++++++++++++++++++++ src/libs/engine/HTTPEngineReceiver.hpp | 59 ++++++++++++++++ src/libs/engine/JackAudioDriver.cpp | 3 +- src/libs/engine/Makefile.am | 14 +++- src/libs/engine/OSCEngineReceiver.hpp | 2 +- 7 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 src/libs/engine/HTTPEngineReceiver.cpp create mode 100644 src/libs/engine/HTTPEngineReceiver.hpp (limited to 'src/libs/engine') diff --git a/src/libs/engine/Engine.cpp b/src/libs/engine/Engine.cpp index 0decdf25..0a6d048a 100644 --- a/src/libs/engine/Engine.cpp +++ b/src/libs/engine/Engine.cpp @@ -39,6 +39,7 @@ #include "CreatePatchEvent.hpp" #include "EnablePatchEvent.hpp" #include "OSCEngineReceiver.hpp" +#include "HTTPEngineReceiver.hpp" #include "PostProcessor.hpp" #include "ProcessSlave.hpp" #include "ThreadManager.hpp" @@ -164,6 +165,17 @@ Engine::start_osc_driver(int port) _event_source = SharedPtr(new OSCEngineReceiver( *this, pre_processor_queue_size, port)); } + + +void +Engine::start_http_driver(int port) +{ +#ifdef HAVE_SOUP + // FIXE: leak + HTTPEngineReceiver* server = new HTTPEngineReceiver(*this, port); + server->activate(); +#endif +} SharedPtr @@ -276,6 +288,14 @@ Engine::deactivate() _activated = false; } + + +void +Engine::process_events(ProcessContext& context) +{ + if (_event_source) + _event_source->process(*_post_processor, context); +} } // namespace Ingen diff --git a/src/libs/engine/Engine.hpp b/src/libs/engine/Engine.hpp index be7a3ee7..c2a59f3e 100644 --- a/src/libs/engine/Engine.hpp +++ b/src/libs/engine/Engine.hpp @@ -46,6 +46,7 @@ class QueuedEvent; class QueuedEngineInterface; class Driver; class ProcessSlave; +class ProcessContext; /** The main class for the Engine. @@ -71,12 +72,15 @@ public: virtual void start_jack_driver(); virtual void start_osc_driver(int port); + virtual void start_http_driver(int port); virtual SharedPtr new_queued_interface(); virtual bool activate(size_t parallelism); virtual void deactivate(); + void process_events(ProcessContext& context); + virtual bool activated() { return _activated; } Raul::Maid* maid() const { return _maid; } diff --git a/src/libs/engine/HTTPEngineReceiver.cpp b/src/libs/engine/HTTPEngineReceiver.cpp new file mode 100644 index 00000000..baa522ba --- /dev/null +++ b/src/libs/engine/HTTPEngineReceiver.cpp @@ -0,0 +1,125 @@ +/* This file is part of Ingen. + * Copyright (C) 2007 Dave Robillard + * + * 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 +#include +#include +#include "types.hpp" +#include +#include +#include "interface/ClientInterface.hpp" +#include "engine/ThreadManager.hpp" +#include "HTTPEngineReceiver.hpp" +#include "QueuedEventSource.hpp" +#include "ClientBroadcaster.hpp" +#include "ObjectStore.hpp" + +using namespace std; + +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"); +} + + +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; + + if (msg->method != SOUP_METHOD_GET) { + soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + return; + } + + // FIXME: not thread safe! + + ObjectStore* store = me->_engine.object_store(); + if (!Path::is_valid(path)) { + soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); + return; + } + + ObjectStore::Objects::iterator start = store->find(path); + if (start == store->objects().end()) { + soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); + return; + } + + ObjectStore::Objects::iterator end = store->objects().find_descendants_end(start); + + string response; + for (ObjectStore::Objects::iterator i = start; i != end; ++i) + response.append(i->first).append("\n"); + + soup_message_set_status (msg, SOUP_STATUS_OK); + soup_message_set_response (msg, "text/plain", SOUP_MEMORY_COPY, + response.c_str(), response.length()); +} + + +/** 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 diff --git a/src/libs/engine/HTTPEngineReceiver.hpp b/src/libs/engine/HTTPEngineReceiver.hpp new file mode 100644 index 00000000..34c425b2 --- /dev/null +++ b/src/libs/engine/HTTPEngineReceiver.hpp @@ -0,0 +1,59 @@ +/* This file is part of Ingen. + * Copyright (C) 2008 Dave Robillard + * + * 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 HTTPENGINERECEIVER_H +#define HTTPENGINERECEIVER_H + +#include CONFIG_H_PATH +#include +#include +#include +#include +#include "QueuedEngineInterface.hpp" + +namespace Ingen { + +class HTTPEngineReceiver : public QueuedEngineInterface +{ +public: + HTTPEngineReceiver(Engine& engine, uint16_t port); + ~HTTPEngineReceiver(); + + void activate(); + void deactivate(); + +private: + struct ReceiveThread : public Raul::Thread { + ReceiveThread(HTTPEngineReceiver& receiver) : _receiver(receiver) {} + virtual void _run(); + private: + HTTPEngineReceiver& _receiver; + }; + + friend class ReceiveThread; + + static void message_callback(SoupServer* server, SoupMessage* msg, const char* path, + GHashTable *query, SoupClientContext* client, void* data); + + ReceiveThread* _receive_thread; + SoupServer* _server; +}; + + +} // namespace Ingen + +#endif // HTTPENGINERECEIVER_H diff --git a/src/libs/engine/JackAudioDriver.cpp b/src/libs/engine/JackAudioDriver.cpp index ea49e492..eff04653 100644 --- a/src/libs/engine/JackAudioDriver.cpp +++ b/src/libs/engine/JackAudioDriver.cpp @@ -314,8 +314,7 @@ JackAudioDriver::_process_cb(jack_nframes_t nframes) // Process events that came in during the last cycle // (Aiming for jitter-free 1 block event latency, ideally) - if (_engine.event_source()) - _engine.event_source()->process(*_engine.post_processor(), _process_context); + _engine.process_events(_process_context); // Set buffers of patch ports to Jack port buffers (zero-copy processing) for (Raul::List::iterator i = _ports.begin(); i != _ports.end(); ++i) { diff --git a/src/libs/engine/Makefile.am b/src/libs/engine/Makefile.am index 3ce73124..0f069e10 100644 --- a/src/libs/engine/Makefile.am +++ b/src/libs/engine/Makefile.am @@ -11,10 +11,11 @@ libingen_engine_la_CXXFLAGS = \ @JACK_CFLAGS@ \ @LASH_CFLAGS@ \ @LIBLO_CFLAGS@ \ + @LV2_OSC_CFLAGS@ \ @RAUL_CFLAGS@ \ @REDLANDMM_CFLAGS@ \ @SLV2_CFLAGS@ \ - @LV2_OSC_CFLAGS@ + @SOUP_CFLAGS@ libingen_engine_la_LDFLAGS = -no-undefined -module -avoid-version libingen_engine_la_LIBADD = \ @@ -23,10 +24,11 @@ libingen_engine_la_LIBADD = \ @JACK_LIBS@ \ @LASH_LIBS@ \ @LIBLO_LIBS@ \ + @LV2_OSC_LIBS@ \ @RAUL_LIBS@ \ @REDLANDMM_LIBS@ \ @SLV2_LIBS@ \ - @LV2_OSC_LIBS@ + @SOUP_LIBS@ AM_CFLAGS=-std=c99 @@ -196,3 +198,11 @@ libingen_engine_la_SOURCES += \ LV2Node.cpp endif +if WITH_SOUP +libingen_engine_la_SOURCES += \ + HTTPEngineReceiver.cpp \ + HTTPEngineReceiver.hpp +endif + + + diff --git a/src/libs/engine/OSCEngineReceiver.hpp b/src/libs/engine/OSCEngineReceiver.hpp index 0f9d4685..a998054f 100644 --- a/src/libs/engine/OSCEngineReceiver.hpp +++ b/src/libs/engine/OSCEngineReceiver.hpp @@ -73,7 +73,7 @@ private: ReceiveThread(OSCEngineReceiver& receiver) : _receiver(receiver) {} virtual void _run(); private: - OSCEngineReceiver& _receiver; + OSCEngineReceiver& _receiver; }; friend class ReceiveThread; -- cgit v1.2.1