/* * Carla REST API Server * Copyright (C) 2018 Filipe Coelho * * This program 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 any later version. * * This program 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 more details. * * For a full copy of the GNU General Public License see the doc/GPL.txt file. */ /* NOTE * Even though Carla is GPL, restbed if AGPL. * As such, the resulting binary will be AGPL. * Take this into consideration before deploying it to any servers. */ #include "common.hpp" #include "carla-host.cpp" #include "carla-utils.cpp" #include "CarlaMutex.hpp" #include "CarlaStringList.hpp" // ------------------------------------------------------------------------------------------------------------------- std::vector> gSessions; CarlaStringList gSessionMessages; CarlaMutex gSessionMessagesMutex; // ------------------------------------------------------------------------------------------------------------------- void send_server_side_message(const char* const message) { const CarlaMutexLocker cml(gSessionMessagesMutex); gSessionMessages.append(message); } // ------------------------------------------------------------------------------------------------------------------- static void register_server_side_handler(const std::shared_ptr session) { const auto headers = std::multimap { { "Connection", "keep-alive" }, { "Cache-Control", "no-cache" }, { "Content-Type", "text/event-stream" }, { "Access-Control-Allow-Origin", "*" } //Only required for demo purposes. }; session->yield(OK, headers, [](const std::shared_ptr rsession) { gSessions.push_back(rsession); }); } static void event_stream_handler(void) { gSessions.erase( std::remove_if(gSessions.begin(), gSessions.end(), [](const std::shared_ptr &a) { return a->is_closed(); }), gSessions.end()); CarlaStringList messages; { const CarlaMutexLocker cml(gSessionMessagesMutex); if (gSessionMessages.count() > 0) gSessionMessages.moveTo(messages); } for (auto message : messages) { std::puts(message); for (auto session : gSessions) session->yield(OK, message); } } // ------------------------------------------------------------------------------------------------------------------- static void make_resource(Service& service, const char* const path, const std::function)>& callback) { std::shared_ptr resource = std::make_shared(); resource->set_path(path); resource->set_method_handler("GET", callback); service.publish(resource); } // ------------------------------------------------------------------------------------------------------------------- int main(int, const char**) { Service service; // server-side messages { std::shared_ptr resource = std::make_shared(); resource->set_path("/stream"); resource->set_method_handler("GET", register_server_side_handler); service.publish(resource); } // carla-host make_resource(service, "/get_engine_driver_count", handle_carla_get_engine_driver_count); make_resource(service, "/get_engine_driver_name/{index: .*}", handle_carla_get_engine_driver_name); make_resource(service, "/get_engine_driver_device_names/{index: .*}", handle_carla_get_engine_driver_device_names); make_resource(service, "/get_engine_driver_device_info/{index: .*}/{name: .*}", handle_carla_get_engine_driver_device_info); make_resource(service, "/engine_init/{driverName: .*}/{clientName: .*}", handle_carla_engine_init); make_resource(service, "/engine_close", handle_carla_engine_close); make_resource(service, "/is_engine_running", handle_carla_is_engine_running); make_resource(service, "/set_engine_about_to_close", handle_carla_set_engine_about_to_close); // ... make_resource(service, "/get_last_error", handle_carla_get_last_error); // carla-utils make_resource(service, "/get_complete_license_text", handle_carla_get_complete_license_text); make_resource(service, "/get_supported_file_extensions", handle_carla_get_supported_file_extensions); make_resource(service, "/get_supported_features", handle_carla_get_supported_features); make_resource(service, "/get_cached_plugin_count/{ptype: .*}/{pluginPath: .*}", handle_carla_get_cached_plugin_count); make_resource(service, "/get_cached_plugin_info/{ptype: .*}/{index: .*}", handle_carla_get_cached_plugin_info); // schedule events service.schedule(engine_idle_handler, std::chrono::milliseconds(33)); // ~30Hz service.schedule(event_stream_handler, std::chrono::milliseconds(500)); std::shared_ptr settings = std::make_shared(); settings->set_port(2228); settings->set_default_header("Connection", "close"); carla_stdout("Carla REST-API Server started"); service.start(settings); return 0; } // -------------------------------------------------------------------------------------------------------------------