Permalink
Browse files

Added initial HTTP/HTTPS webserver/websocket server support (nw)

  • Loading branch information...
1 parent 47c4f47 commit 63e3f487751eb096152e6e6bd90d8b47643a496b @mmicko mmicko committed Jan 4, 2017
View
@@ -39,6 +39,7 @@ includedirs {
files {
MAME_DIR .. "src/emu/emu.h",
MAME_DIR .. "src/emu/main.h",
+ MAME_DIR .. "src/emu/main.cpp",
MAME_DIR .. "src/emu/gamedrv.h",
MAME_DIR .. "src/emu/hashfile.cpp",
MAME_DIR .. "src/emu/hashfile.h",
View
@@ -31,6 +31,7 @@ project "utils"
MAME_DIR .. "src/lib/util/avhuff.h",
MAME_DIR .. "src/lib/util/aviio.cpp",
MAME_DIR .. "src/lib/util/aviio.h",
+ MAME_DIR .. "src/lib/util/base64.hpp",
MAME_DIR .. "src/lib/util/bitmap.cpp",
MAME_DIR .. "src/lib/util/bitmap.h",
MAME_DIR .. "src/lib/util/cdrom.cpp",
@@ -41,13 +42,18 @@ project "utils"
MAME_DIR .. "src/lib/util/chdcd.h",
MAME_DIR .. "src/lib/util/chdcodec.cpp",
MAME_DIR .. "src/lib/util/chdcodec.h",
+ MAME_DIR .. "src/lib/util/client_http.hpp",
+ MAME_DIR .. "src/lib/util/client_https.hpp",
+ MAME_DIR .. "src/lib/util/client_ws.hpp",
+ MAME_DIR .. "src/lib/util/client_wss.hpp",
MAME_DIR .. "src/lib/util/corealloc.h",
MAME_DIR .. "src/lib/util/corefile.cpp",
MAME_DIR .. "src/lib/util/corefile.h",
MAME_DIR .. "src/lib/util/corestr.cpp",
MAME_DIR .. "src/lib/util/corestr.h",
MAME_DIR .. "src/lib/util/coreutil.cpp",
MAME_DIR .. "src/lib/util/coreutil.h",
+ MAME_DIR .. "src/lib/util/crypto.hpp",
MAME_DIR .. "src/lib/util/delegate.cpp",
MAME_DIR .. "src/lib/util/delegate.h",
MAME_DIR .. "src/lib/util/flac.cpp",
@@ -71,14 +77,21 @@ project "utils"
MAME_DIR .. "src/lib/util/options.h",
MAME_DIR .. "src/lib/util/palette.cpp",
MAME_DIR .. "src/lib/util/palette.h",
+ MAME_DIR .. "src/lib/util/path_to_regex.cpp",
+ MAME_DIR .. "src/lib/util/path_to_regex.h",
MAME_DIR .. "src/lib/util/plaparse.cpp",
MAME_DIR .. "src/lib/util/plaparse.h",
MAME_DIR .. "src/lib/util/png.cpp",
MAME_DIR .. "src/lib/util/png.h",
MAME_DIR .. "src/lib/util/pool.cpp",
MAME_DIR .. "src/lib/util/pool.h",
+ MAME_DIR .. "src/lib/util/server_http.hpp",
+ MAME_DIR .. "src/lib/util/server_https.hpp",
+ MAME_DIR .. "src/lib/util/server_ws.hpp",
+ MAME_DIR .. "src/lib/util/server_wss.hpp",
MAME_DIR .. "src/lib/util/sha1.cpp",
MAME_DIR .. "src/lib/util/sha1.h",
+ MAME_DIR .. "src/lib/util/sha1.hpp",
MAME_DIR .. "src/lib/util/strformat.cpp",
MAME_DIR .. "src/lib/util/strformat.h",
MAME_DIR .. "src/lib/util/timeconv.cpp",
View
@@ -203,6 +203,12 @@ const options_entry emu_options::s_option_entries[] =
{ OPTION_PLUGIN, nullptr, OPTION_STRING, "list of plugins to enable" },
{ OPTION_NO_PLUGIN, nullptr, OPTION_STRING, "list of plugins to disable" },
{ OPTION_LANGUAGE ";lang", "English", OPTION_STRING, "display language" },
+
+ { nullptr, nullptr, OPTION_HEADER, "HTTP SERVER OPTIONS" },
+ { OPTION_HTTP, "0", OPTION_BOOLEAN, "HTTP server enable" },
+ { OPTION_HTTP_PORT, "8080", OPTION_INTEGER, "HTTP server port" },
+ { OPTION_HTTP_ROOT, "web", OPTION_STRING, "HTTP server document root" },
+
{ nullptr }
};
View
@@ -190,6 +190,10 @@
#define OPTION_LANGUAGE "language"
+#define OPTION_HTTP "http"
+#define OPTION_HTTP_PORT "http_port"
+#define OPTION_HTTP_ROOT "http_root"
+
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
@@ -381,6 +385,11 @@ class emu_options : public core_options
const char *language() const { return value(OPTION_LANGUAGE); }
+ // Web server specific optopns
+ bool http() const { return value(OPTION_HTTP); }
+ short http_port() const { return int_value(OPTION_HTTP_PORT); }
+ const char *http_root() const { return value(OPTION_HTTP_ROOT); }
+
// cache frequently used options in members
void update_cached_options();
View
@@ -84,6 +84,9 @@
#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"
#if defined(EMSCRIPTEN)
#include <emscripten.h>
@@ -332,6 +335,8 @@ int running_machine::run(bool quiet)
if (m_saveload_schedule != SLS_NONE)
handle_saveload();
+ export_http_api();
+
// 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)
@@ -1176,7 +1181,30 @@ running_machine::logerror_callback_item::logerror_callback_item(logerror_callbac
{
}
-
+void running_machine::export_http_api()
+{
+ m_manager.http_server()->on_get("/api/machine", [this](auto response, auto request)
+ {
+ rapidjson::StringBuffer s;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(s);
+ writer.StartObject();
+ writer.Key("name");
+ writer.String(m_basename.c_str());
+
+ writer.Key("devices");
+ writer.StartArray();
+
+ device_iterator iter(root_device());
+ for (device_t &device : iter)
+ writer.String(device.tag());
+
+ writer.EndArray();
+ writer.EndObject();
+
+ response->type("application/json");
+ response->status(200).send(s.GetString());
+ });
+}
//**************************************************************************
// SYSTEM TIME
View
@@ -239,6 +239,7 @@ class running_machine
void add_logerror_callback(logerror_callback callback);
void set_ui_active(bool active) { m_ui_active = active; }
void debug_break();
+ void export_http_api();
// TODO: Do saves and loads still require scheduling?
void immediate_save(const char *filename);
View
@@ -0,0 +1,186 @@
+// license:BSD-3-Clause
+// copyright-holders:Nicola Salmoria, Aaron Giles
+/***************************************************************************
+
+main.cpp
+
+Controls execution of the core MAME system.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "main.h"
+#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();
+ }
+ m_server_thread.join();
+}
+
+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);
+ std::string doc_root = options().http_root();
+
+ m_server->on_get([this, doc_root](auto response, auto request) {
+ 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);
+
+ });
+ m_server->start();
+ }
+}
+
+void machine_manager::start_context()
+{
+ m_server_thread = std::thread([this]() {
+ m_io_context->run();
+ });
+}
+
View
@@ -65,15 +65,23 @@ class emulator_info
// ======================> machine_manager
class ui_manager;
+namespace asio
+{
+ class io_context;
+}
+namespace webpp
+{
+ class http_server;
+}
class machine_manager
{
DISABLE_COPYING(machine_manager);
protected:
// construction/destruction
- machine_manager(emu_options &options, osd_interface &osd) : m_osd(osd), m_options(options), m_machine(nullptr) { }
+ 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; }
@@ -87,10 +95,17 @@ class machine_manager
virtual void ui_initialize(running_machine& machine) { }
virtual void update_machine() { }
+
+ 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::thread m_server_thread;
};
@@ -309,9 +309,13 @@ int cli_frontend::execute(int argc, char **argv)
load_translation(m_options);
+ manager->start_http_server();
+
manager->start_luaengine();
- start_execution(manager, argc, argv, option_errors);
+ manager->start_context();
+
+ start_execution(manager, argc, argv, option_errors);
}
// handle exceptions of various types
catch (emu_fatalerror &fatal)
Oops, something went wrong.

0 comments on commit 63e3f48

Please sign in to comment.