diff options
Diffstat (limited to 'src/emu')
-rw-r--r-- | src/emu/emu.h | 3 | ||||
-rw-r--r-- | src/emu/http.cpp | 213 | ||||
-rw-r--r-- | src/emu/http.h | 57 | ||||
-rw-r--r-- | src/emu/machine.cpp | 13 | ||||
-rw-r--r-- | src/emu/main.cpp | 188 | ||||
-rw-r--r-- | src/emu/main.h | 28 |
6 files changed, 291 insertions, 211 deletions
diff --git a/src/emu/emu.h b/src/emu/emu.h index 58e6d4786f3..66832b06dea 100644 --- a/src/emu/emu.h +++ b/src/emu/emu.h @@ -30,6 +30,9 @@ #include "eminline.h" #include "profiler.h" +// http interface helpers +#include "http.h" + // commonly-referenced utilities imported from lib/util #include "palette.h" #include "unicode.h" diff --git a/src/emu/http.cpp b/src/emu/http.cpp new file mode 100644 index 00000000000..856f4dd0e7c --- /dev/null +++ b/src/emu/http.cpp @@ -0,0 +1,213 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + +http.cpp + +HTTP server handling + +***************************************************************************/ + +#include "emu.h" +#include "server_ws.hpp" +#include "server_http.hpp" +#include <fstream> + +const static struct mapping +{ + const char* extension; + const char* mime_type; +} mappings[] = +{ + { "aac", "audio/aac" }, + { "aat", "application/font-sfnt" }, + { "aif", "audio/x-aif" }, + { "arj", "application/x-arj-compressed" }, + { "asf", "video/x-ms-asf" }, + { "avi", "video/x-msvideo" }, + { "bmp", "image/bmp" }, + { "cff", "application/font-sfnt" }, + { "css", "text/css" }, + { "csv", "text/csv" }, + { "doc", "application/msword" }, + { "eps", "application/postscript" }, + { "exe", "application/octet-stream" }, + { "gif", "image/gif" }, + { "gz", "application/x-gunzip" }, + { "htm", "text/html" }, + { "html", "text/html" }, + { "ico", "image/x-icon" }, + { "ief", "image/ief" }, + { "jpeg", "image/jpeg" }, + { "jpg", "image/jpeg" }, + { "jpm", "image/jpm" }, + { "jpx", "image/jpx" }, + { "js", "application/javascript" }, + { "json", "application/json" }, + { "m3u", "audio/x-mpegurl" }, + { "m4v", "video/x-m4v" }, + { "mid", "audio/x-midi" }, + { "mov", "video/quicktime" }, + { "mp3", "audio/mpeg" }, + { "mp4", "video/mp4" }, + { "mpeg", "video/mpeg" }, + { "mpg", "video/mpeg" }, + { "oga", "audio/ogg" }, + { "ogg", "audio/ogg" }, + { "ogv", "video/ogg" }, + { "otf", "application/font-sfnt" }, + { "pct", "image/x-pct" }, + { "pdf", "application/pdf" }, + { "pfr", "application/font-tdpfr" }, + { "pict", "image/pict" }, + { "png", "image/png" }, + { "ppt", "application/x-mspowerpoint" }, + { "ps", "application/postscript" }, + { "qt", "video/quicktime" }, + { "ra", "audio/x-pn-realaudio" }, + { "ram", "audio/x-pn-realaudio" }, + { "rar", "application/x-arj-compressed" }, + { "rgb", "image/x-rgb" }, + { "rtf", "application/rtf" }, + { "sgm", "text/sgml" }, + { "shtm", "text/html" }, + { "shtml", "text/html" }, + { "sil", "application/font-sfnt" }, + { "svg", "image/svg+xml" }, + { "swf", "application/x-shockwave-flash" }, + { "tar", "application/x-tar" }, + { "tgz", "application/x-tar-gz" }, + { "tif", "image/tiff" }, + { "tiff", "image/tiff" }, + { "torrent", "application/x-bittorrent" }, + { "ttf", "application/font-sfnt" }, + { "txt", "text/plain" }, + { "wav", "audio/x-wav" }, + { "webm", "video/webm" }, + { "woff", "application/font-woff" }, + { "wrl", "model/vrml" }, + { "xhtml", "application/xhtml+xml" }, + { "xls", "application/x-msexcel" }, + { "xml", "text/xml" }, + { "xsl", "application/xml" }, + { "xslt", "application/xml" }, + { "zip", "application/x-zip-compressed" } +}; + +static std::string extension_to_type(const std::string& extension) +{ + for (mapping m : mappings) + { + if (m.extension == extension) + { + return m.mime_type; + } + } + + return "text/plain"; +} + +http_manager::http_manager(bool active, short port, const char *root) + : m_io_context(std::make_shared<asio::io_context>()) +{ + if (!active) return; + + m_server = std::make_unique<webpp::http_server>(); + m_server->m_config.port = port; + m_server->set_io_context(m_io_context); + m_wsserver = std::make_unique<webpp::ws_server>(); + + auto& endpoint = m_wsserver->endpoint["/"]; + + m_server->on_get([this, root](auto response, auto request) { + std::string doc_root = root; + + std::string path = request->path; + // If path ends in slash (i.e. is a directory) then add "index.html". + if (path[path.size() - 1] == '/') + { + path += "index.html"; + } + + std::size_t last_qmark_pos = path.find_last_of("?"); + if (last_qmark_pos != std::string::npos) + path = path.substr(0, last_qmark_pos - 1); + + // Determine the file extension. + std::size_t last_slash_pos = path.find_last_of("/"); + std::size_t last_dot_pos = path.find_last_of("."); + std::string extension; + if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos) + { + extension = path.substr(last_dot_pos + 1); + } + + // Open the file to send back. + std::string full_path = doc_root + path; + std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary); + if (!is) + { + response->status(400).send("Error"); + } + else + { + // Fill out the reply to be sent to the client. + std::string content; + char buf[512]; + while (is.read(buf, sizeof(buf)).gcount() > 0) + content.append(buf, size_t(is.gcount())); + + response->type(extension_to_type(extension)); + response->status(200).send(content); + } + }); + + endpoint.on_open = [&](auto connection) { + auto send_stream = std::make_shared<webpp::ws_server::SendStream>(); + *send_stream << "update_machine"; + m_wsserver->send(connection, send_stream); + }; + + m_server->on_upgrade = [this](auto socket, auto request) { + auto connection = std::make_shared<webpp::ws_server::Connection>(socket); + connection->method = std::move(request->method); + connection->path = std::move(request->path); + connection->http_version = std::move(request->http_version); + connection->header = std::move(request->header); + connection->remote_endpoint_address = std::move(request->remote_endpoint_address); + connection->remote_endpoint_port = request->remote_endpoint_port; + m_wsserver->upgrade(connection); + }; + + m_server->start(); + + m_server_thread = std::thread([this]() { + m_io_context->run(); + }); +} + +http_manager::~http_manager() +{ + if (!m_server) return; + + m_server->stop(); + if (m_server_thread.joinable()) + m_server_thread.join(); +} + + +void http_manager::update() +{ + if (!m_server) return; + + m_server->clear(); + for (auto handler : m_handlers) + { + m_server->on_get(handler.first, [handler](auto response, auto request) + { + std::tuple<std::string,int, std::string> output = handler.second(request->path); + response->type(std::get<2>(output)); + response->status(std::get<1>(output)).send(std::get<0>(output).c_str()); + }); + } +} diff --git a/src/emu/http.h b/src/emu/http.h new file mode 100644 index 00000000000..9f9f2e739b6 --- /dev/null +++ b/src/emu/http.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + +http.cpp + +HTTP server handling + +***************************************************************************/ + +#pragma once + +#ifndef __EMU_H__ +#error Dont include this file directly; include emu.h instead. +#endif + +#ifndef MAME_EMU_HTTP_H +#define MAME_EMU_HTTP_H + +#include <thread> +#include <time.h> + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> http_manager +namespace asio +{ + class io_context; +} +namespace webpp +{ + class http_server; + class ws_server; +} + +class http_manager +{ + DISABLE_COPYING(http_manager); +public: + http_manager(bool active, short port, const char *root); + virtual ~http_manager(); + + void clear() { m_handlers.clear(); update(); } + void add(const char *url, std::function<std::tuple<std::string,int,std::string>(std::string)> func) { m_handlers.emplace(url, func); } + void update(); +private: + std::shared_ptr<asio::io_context> m_io_context; + std::unique_ptr<webpp::http_server> m_server; + std::unique_ptr<webpp::ws_server> m_wsserver; + std::thread m_server_thread; + std::unordered_map<const char *, std::function<std::tuple<std::string, int, std::string>(std::string)>> m_handlers; +}; + + +#endif /* MAME_EMU_HTTP_H */ diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp index bdd7ad4fc47..33868cd8d57 100644 --- a/src/emu/machine.cpp +++ b/src/emu/machine.cpp @@ -84,7 +84,6 @@ #include "network.h" #include "ui/uimain.h" #include <time.h> -#include "server_http.hpp" #include "rapidjson/include/rapidjson/writer.h" #include "rapidjson/include/rapidjson/stringbuffer.h" @@ -291,6 +290,8 @@ int running_machine::run(bool quiet) // use try/catch for deep error recovery try { + m_manager.http()->clear(); + // move to the init phase m_current_phase = MACHINE_PHASE_INIT; @@ -339,6 +340,8 @@ int running_machine::run(bool quiet) export_http_api(); + m_manager.http()->update(); + // run the CPUs until a reset or exit m_hard_reset_pending = false; while ((!m_hard_reset_pending && !m_exit_pending) || m_saveload_schedule != SLS_NONE) @@ -363,6 +366,7 @@ int running_machine::run(bool quiet) g_profiler.stop(); } + m_manager.http()->clear(); // and out via the exit phase m_current_phase = MACHINE_PHASE_EXIT; @@ -1185,9 +1189,7 @@ running_machine::logerror_callback_item::logerror_callback_item(logerror_callbac void running_machine::export_http_api() { - if (!options().http()) return; - - m_manager.http_server()->on_get("/api/machine", [this](auto response, auto request) + m_manager.http()->add("/api/machine", [this](std::string) { rapidjson::StringBuffer s; rapidjson::Writer<rapidjson::StringBuffer> writer(s); @@ -1205,8 +1207,7 @@ void running_machine::export_http_api() writer.EndArray(); writer.EndObject(); - response->type("application/json"); - response->status(200).send(s.GetString()); + return std::make_tuple(std::string(s.GetString()), 200, "application/json"); }); } diff --git a/src/emu/main.cpp b/src/emu/main.cpp index 9d0e1e3aff4..59aa1eddc0a 100644 --- a/src/emu/main.cpp +++ b/src/emu/main.cpp @@ -10,198 +10,16 @@ Controls execution of the core MAME system. #include "emu.h" #include "emuopts.h" -#include "main.h" -#include "server_ws.hpp" -#include "server_http.hpp" -#include <fstream> - -const static struct mapping -{ - const char* extension; - const char* mime_type; -} mappings[] = -{ - { "aac", "audio/aac" }, - { "aat", "application/font-sfnt" }, - { "aif", "audio/x-aif" }, - { "arj", "application/x-arj-compressed" }, - { "asf", "video/x-ms-asf" }, - { "avi", "video/x-msvideo" }, - { "bmp", "image/bmp" }, - { "cff", "application/font-sfnt" }, - { "css", "text/css" }, - { "csv", "text/csv" }, - { "doc", "application/msword" }, - { "eps", "application/postscript" }, - { "exe", "application/octet-stream" }, - { "gif", "image/gif" }, - { "gz", "application/x-gunzip" }, - { "htm", "text/html" }, - { "html", "text/html" }, - { "ico", "image/x-icon" }, - { "ief", "image/ief" }, - { "jpeg", "image/jpeg" }, - { "jpg", "image/jpeg" }, - { "jpm", "image/jpm" }, - { "jpx", "image/jpx" }, - { "js", "application/javascript" }, - { "json", "application/json" }, - { "m3u", "audio/x-mpegurl" }, - { "m4v", "video/x-m4v" }, - { "mid", "audio/x-midi" }, - { "mov", "video/quicktime" }, - { "mp3", "audio/mpeg" }, - { "mp4", "video/mp4" }, - { "mpeg", "video/mpeg" }, - { "mpg", "video/mpeg" }, - { "oga", "audio/ogg" }, - { "ogg", "audio/ogg" }, - { "ogv", "video/ogg" }, - { "otf", "application/font-sfnt" }, - { "pct", "image/x-pct" }, - { "pdf", "application/pdf" }, - { "pfr", "application/font-tdpfr" }, - { "pict", "image/pict" }, - { "png", "image/png" }, - { "ppt", "application/x-mspowerpoint" }, - { "ps", "application/postscript" }, - { "qt", "video/quicktime" }, - { "ra", "audio/x-pn-realaudio" }, - { "ram", "audio/x-pn-realaudio" }, - { "rar", "application/x-arj-compressed" }, - { "rgb", "image/x-rgb" }, - { "rtf", "application/rtf" }, - { "sgm", "text/sgml" }, - { "shtm", "text/html" }, - { "shtml", "text/html" }, - { "sil", "application/font-sfnt" }, - { "svg", "image/svg+xml" }, - { "swf", "application/x-shockwave-flash" }, - { "tar", "application/x-tar" }, - { "tgz", "application/x-tar-gz" }, - { "tif", "image/tiff" }, - { "tiff", "image/tiff" }, - { "torrent", "application/x-bittorrent" }, - { "ttf", "application/font-sfnt" }, - { "txt", "text/plain" }, - { "wav", "audio/x-wav" }, - { "webm", "video/webm" }, - { "woff", "application/font-woff" }, - { "wrl", "model/vrml" }, - { "xhtml", "application/xhtml+xml" }, - { "xls", "application/x-msexcel" }, - { "xml", "text/xml" }, - { "xsl", "application/xml" }, - { "xslt", "application/xml" }, - { "zip", "application/x-zip-compressed" } -}; - -static std::string extension_to_type(const std::string& extension) -{ - for (mapping m : mappings) - { - if (m.extension == extension) - { - return m.mime_type; - } - } - - return "text/plain"; -} machine_manager::machine_manager(emu_options& options, osd_interface& osd) : m_osd(osd), m_options(options), - m_machine(nullptr), - m_io_context(std::make_shared<asio::io_context>()) -{ -} - -machine_manager::~machine_manager() -{ - if (options().http()) - m_server->stop(); - if (m_server_thread.joinable()) - m_server_thread.join(); + m_machine(nullptr) +{ } void machine_manager::start_http_server() { - if (options().http()) - { - m_server = std::make_unique<webpp::http_server>(); - m_server->m_config.port = options().http_port(); - m_server->set_io_context(m_io_context); - m_wsserver = std::make_unique<webpp::ws_server>(); - - auto& endpoint = m_wsserver->endpoint["/"]; - - m_server->on_get([this](auto response, auto request) { - std::string doc_root = this->options().http_root(); - - std::string path = request->path; - // If path ends in slash (i.e. is a directory) then add "index.html". - if (path[path.size() - 1] == '/') - { - path += "index.html"; - } - - std::size_t last_qmark_pos = path.find_last_of("?"); - if (last_qmark_pos != std::string::npos) - path = path.substr(0, last_qmark_pos - 1); - - // Determine the file extension. - std::size_t last_slash_pos = path.find_last_of("/"); - std::size_t last_dot_pos = path.find_last_of("."); - std::string extension; - if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos) - { - extension = path.substr(last_dot_pos + 1); - } - - // Open the file to send back. - std::string full_path = doc_root + path; - std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary); - if (!is) - { - response->status(400).send("Error"); - } - - // Fill out the reply to be sent to the client. - std::string content; - char buf[512]; - while (is.read(buf, sizeof(buf)).gcount() > 0) - content.append(buf, size_t(is.gcount())); - - response->type(extension_to_type(extension)); - response->status(200).send(content); - - }); - - endpoint.on_open = [&](auto connection) { - auto send_stream = std::make_shared<webpp::ws_server::SendStream>(); - *send_stream << "update_machine"; - m_wsserver->send(connection, send_stream); - }; - - m_server->on_upgrade = [this](auto socket, auto request) { - auto connection = std::make_shared<webpp::ws_server::Connection>(socket); - connection->method = std::move(request->method); - connection->path = std::move(request->path); - connection->http_version = std::move(request->http_version); - connection->header = std::move(request->header); - connection->remote_endpoint_address = std::move(request->remote_endpoint_address); - connection->remote_endpoint_port = request->remote_endpoint_port; - m_wsserver->upgrade(connection); - }; - m_server->start(); - } -} - -void machine_manager::start_context() -{ - m_server_thread = std::thread([this]() { - m_io_context->run(); - }); + m_http = std::make_unique<http_manager>(options().http(), options().http_port(), options().http_root()); } diff --git a/src/emu/main.h b/src/emu/main.h index b13bdee5dc3..e1e9626747f 100644 --- a/src/emu/main.h +++ b/src/emu/main.h @@ -67,15 +67,6 @@ public: // ======================> machine_manager class ui_manager; -namespace asio -{ - class io_context; -} -namespace webpp -{ - class http_server; - class ws_server; -} class machine_manager { @@ -84,7 +75,7 @@ protected: // construction/destruction machine_manager(emu_options& options, osd_interface& osd); public: - virtual ~machine_manager(); + virtual ~machine_manager() { } osd_interface &osd() const { return m_osd; } emu_options &options() const { return m_options; } @@ -99,18 +90,15 @@ public: virtual void ui_initialize(running_machine& machine) { } virtual void update_machine() { } - + + http_manager *http() { return m_http.get(); } void start_http_server(); - void start_context(); - webpp::http_server* http_server() const { return m_server.get(); } + protected: - osd_interface & m_osd; // reference to OSD system - emu_options & m_options; // reference to options - running_machine * m_machine; - std::shared_ptr<asio::io_context> m_io_context; - std::unique_ptr<webpp::http_server> m_server; - std::unique_ptr<webpp::ws_server> m_wsserver; - std::thread m_server_thread; + osd_interface & m_osd; // reference to OSD system + emu_options & m_options; // reference to options + running_machine * m_machine; + std::unique_ptr<http_manager> m_http; }; |