summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/emu/emu.h3
-rw-r--r--src/emu/http.cpp213
-rw-r--r--src/emu/http.h57
-rw-r--r--src/emu/machine.cpp13
-rw-r--r--src/emu/main.cpp188
-rw-r--r--src/emu/main.h28
-rw-r--r--src/frontend/mame/clifront.cpp4
-rw-r--r--src/lib/util/server_http.hpp4
8 files changed, 296 insertions, 214 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;
};
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index 164730fd475..dcd7983021e 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -231,9 +231,7 @@ void cli_frontend::start_execution(mame_machine_manager *manager, std::vector<st
manager->start_http_server();
manager->start_luaengine();
-
- manager->start_context();
-
+
if (!option_errors.empty())
osd_printf_error("Error in command line:\n%s\n", strtrimspace(option_errors).c_str());
diff --git a/src/lib/util/server_http.hpp b/src/lib/util/server_http.hpp
index 63cfb505fb3..d50ccc05bc7 100644
--- a/src/lib/util/server_http.hpp
+++ b/src/lib/util/server_http.hpp
@@ -197,6 +197,10 @@ namespace webpp {
}
}
}
+ void clear()
+ {
+ m_resource.clear();
+ }
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Request>, const std::error_code&)> on_error;