/* * 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 "CarlaHost.h" #include "CarlaUtils.h" #include "CarlaUtils.hpp" #include #include // #include // #include // using namespace std; using namespace restbed; #if 0 void post_method_handler(const std::shared_ptr session) { const std::shared_ptr request = session->get_request(); const string body = "Hello, " + request->get_path_parameter("id"); session->close(OK, body, { { "Content-Length", ::to_string( body.size( ) ) } } ); } #endif CARLA_BACKEND_START_NAMESPACE enum { kStrBufSize = 1023, kJsonBufSize = 4095, kSizeBufSize = 31, }; // static buffer to returned content static char strBuf[kStrBufSize+1]; static char jsonBuf[kJsonBufSize+1]; // static buffer to returned content size static char sizeBuf[kSizeBufSize+1]; void prepare_size() { const std::size_t size = std::strlen(strBuf); std::snprintf(sizeBuf, kSizeBufSize, P_SIZE, size); sizeBuf[kSizeBufSize] = '\0'; } void prepare_buffer_uint(const uint value) { std::snprintf(strBuf, kStrBufSize, "%u", value); strBuf[kStrBufSize] = '\0'; } void prepare_buffer_string(const char* const string) { std::strncpy(strBuf, string, kStrBufSize); strBuf[kStrBufSize] = '\0'; } void prepare_buffer_string_array(const char* const* const array) { size_t bytesRead = 0; strBuf[0] = '\0'; for (int i=0; array[i] != nullptr && bytesRead < kStrBufSize; ++i) { const std::size_t size = std::strlen(array[i]); if (bytesRead + size > kStrBufSize) break; std::strncpy(strBuf+bytesRead, array[i], kStrBufSize); bytesRead += size; strBuf[bytesRead] = '\n'; bytesRead += 1; } strBuf[bytesRead] = '\0'; } char* prepare_buffer_json_start() { std::strcpy(jsonBuf, "{"); return jsonBuf + 1; } char* prepare_buffer_json_add_uint(char* bufPtr, const char* const key, const uint value) { prepare_buffer_uint(value); if (bufPtr != jsonBuf+1) { *bufPtr = ','; bufPtr += 1; } *bufPtr++ = '"'; std::strcpy(bufPtr, key); bufPtr += std::strlen(key); *bufPtr++ = '"'; *bufPtr++ = ':'; std::strcpy(bufPtr, strBuf); bufPtr += std::strlen(strBuf); return bufPtr; } void prepare_buffer_json_end(char* const bufPtr) { std::strcpy(bufPtr, "}"); const std::size_t size = std::strlen(jsonBuf); std::snprintf(sizeBuf, kSizeBufSize, P_SIZE, size); sizeBuf[kSizeBufSize] = '\0'; } void handle_carla_get_complete_license_text(const std::shared_ptr session) { prepare_buffer_string(carla_get_complete_license_text()); prepare_size(); session->close(OK, strBuf, { { "Content-Length", sizeBuf } } ); } void handle_carla_get_supported_file_extensions(const std::shared_ptr session) { prepare_buffer_string_array(carla_get_supported_file_extensions()); prepare_size(); session->close(OK, strBuf, { { "Content-Length", sizeBuf } } ); } void handle_carla_get_supported_features(const std::shared_ptr session) { prepare_buffer_string_array(carla_get_supported_features()); prepare_size(); session->close(OK, strBuf, { { "Content-Length", sizeBuf } } ); } void handle_carla_get_cached_plugin_count(const std::shared_ptr session) { PluginType ptype = PLUGIN_LV2; const char* pluginPath = nullptr; prepare_buffer_uint(carla_get_cached_plugin_count(ptype, pluginPath)); prepare_size(); session->close(OK, strBuf, { { "Content-Length", sizeBuf } } ); } void handle_carla_get_cached_plugin_info(const std::shared_ptr session) { PluginType ptype = PLUGIN_LV2; const uint index = 0; // REMOVE THIS carla_get_cached_plugin_count(ptype, nullptr); const CarlaCachedPluginInfo* const info = carla_get_cached_plugin_info(ptype, index); char* bufPtr; bufPtr = prepare_buffer_json_start(); bufPtr = prepare_buffer_json_add_uint(bufPtr, "category", info->category); bufPtr = prepare_buffer_json_add_uint(bufPtr, "hints", info->hints); bufPtr = prepare_buffer_json_add_uint(bufPtr, "audioIns", info->audioIns); bufPtr = prepare_buffer_json_add_uint(bufPtr, "audioOuts", info->audioOuts); bufPtr = prepare_buffer_json_add_uint(bufPtr, "midiIns", info->midiIns); bufPtr = prepare_buffer_json_add_uint(bufPtr, "midiOuts", info->midiOuts); bufPtr = prepare_buffer_json_add_uint(bufPtr, "parameterIns", info->parameterIns); bufPtr = prepare_buffer_json_add_uint(bufPtr, "parameterOuts", info->parameterOuts); // const char* name; // const char* label; // const char* maker; // const char* copyright; prepare_buffer_json_end(bufPtr); session->close(OK, jsonBuf, { { "Content-Length", sizeBuf } } ); } // CARLA_EXPORT const CarlaCachedPluginInfo* carla_get_cached_plugin_info(PluginType ptype, uint index); CARLA_BACKEND_END_NAMESPACE 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**) { CARLA_BACKEND_USE_NAMESPACE; Service service; 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", handle_carla_get_cached_plugin_count); make_resource(service, "/get_cached_plugin_info", handle_carla_get_cached_plugin_info); 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; }