diff --git a/plugins/discord/init.lua b/plugins/discord/init.lua new file mode 100755 index 00000000000..2b534b98377 --- /dev/null +++ b/plugins/discord/init.lua @@ -0,0 +1,106 @@ +-- license:BSD-3-Clause +-- copyright-holders:Carl +local exports = {} +exports.name = "discord" +exports.version = "0.0.1" +exports.description = "Discord presence" +exports.license = "The BSD 3-Clause License" +exports.author = { name = "Carl" } + +local discord = exports + +function discord.startplugin() + local pipe = emu.file("rw") + local json = require("json") + local nonce = 1 + local starttime = 0 + + local function init() + local path + if package.config:sub(1,1) == '\\' then + path = "\\\\.\\pipe\\discord-ipc-0" + else + path = os.getenv("XDG_RUNTIME_DIR") or os.getenv("TMPDIR") or os.getenv("TMP") or os.getenv("TEMP") or '/tmp' + path = "domain." .. path .. "/discord-ipc-0" + end + local err = pipe:open(path) + if err then + error("discord: unable to connect, " .. err .. "\n") + end + local output = json.stringify({v = 1, client_id = "453309506152169472"}) + --print(output) + pipe:write(string.pack(" 0 or time + 1 < os.time() + --print(data) + if data:find("code", 1, true) then + error("discord: bad RPC reply, " .. data:sub(8) .. "\n") + end + end + + local function update(status) + local running = emu.romname() ~= "___empty" + local state = not running and "In menu" or status + local details = running and manager:machine():system().description or nil + if emu.softname() ~= "" then + for name, dev in pairs(manager:machine().images) do + if dev:longname() then + details = details .. " (" .. dev:longname() .. ")" + break + end + end + end + local status = { + cmd = "SET_ACTIVITY", + args = { + pid = emu.pid(), + activity = { + state = state, + details = details, + timestamps = { + start = starttime + } + } + }, + nonce = nonce + } + nonce = nonce + 1 + local output = json.stringify(status) + --print(output) + pipe:write(string.pack(" 0 or time + 1 < os.time() + --print(data) + end + + do + local stat, err = pcall(init) + if not stat then + emu.print_error(err) + return + end + end + + emu.register_start(function() + starttime = os.time() + update("Playing") + end) + + emu.register_pause(function() + update("Paused") + end) + + emu.register_resume(function() + update("Playing") + end) +end + +return exports diff --git a/plugins/discord/plugin.json b/plugins/discord/plugin.json new file mode 100644 index 00000000000..df2eb695158 --- /dev/null +++ b/plugins/discord/plugin.json @@ -0,0 +1,10 @@ +{ + "plugin": { + "name": "discord", + "description": "Discord presence", + "version": "0.0.1", + "author": "Carl", + "type": "plugin", + "start": "false" + } +} diff --git a/scripts/src/osd/sdl.lua b/scripts/src/osd/sdl.lua index 718ca6e551e..9ef57e0ba7c 100644 --- a/scripts/src/osd/sdl.lua +++ b/scripts/src/osd/sdl.lua @@ -462,6 +462,7 @@ project ("ocore_" .. _OPTIONS["osd"]) if BASE_TARGETOS=="unix" then files { MAME_DIR .. "src/osd/modules/file/posixdir.cpp", + MAME_DIR .. "src/osd/modules/file/posixdomain.cpp", MAME_DIR .. "src/osd/modules/file/posixfile.cpp", MAME_DIR .. "src/osd/modules/file/posixfile.h", MAME_DIR .. "src/osd/modules/file/posixptty.cpp", diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 846d24dbbd0..c4e7bbbbfdd 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -807,6 +807,7 @@ void lua_engine::initialize() return lua_yield(L, 0); }); emu["lang_translate"] = &lang_translate; + emu["pid"] = &osd_getpid; /* * emu.file([opt] searchpath, flags) - flags can be as in osdcore "OPEN_FLAG_*" or lua style with 'rwc' with addtional c for create *and truncate* (be careful) diff --git a/src/osd/modules/file/posixdomain.cpp b/src/osd/modules/file/posixdomain.cpp new file mode 100644 index 00000000000..633187819a7 --- /dev/null +++ b/src/osd/modules/file/posixdomain.cpp @@ -0,0 +1,207 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb +//============================================================ +// +// sdldomain.c - SDL socket (unix) access functions +// +// SDLMAME by Olivier Galibert and R. Belmont +// +//============================================================ + +#include "posixfile.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +namespace { +char const *const posixfile_domain_identifier = "domain."; + + +class posix_osd_domain : public osd_file +{ +public: + posix_osd_domain(posix_osd_domain const &) = delete; + posix_osd_domain(posix_osd_domain &&) = delete; + posix_osd_domain& operator=(posix_osd_domain const &) = delete; + posix_osd_domain& operator=(posix_osd_domain &&) = delete; + + posix_osd_domain(int sock, bool listening) + : m_sock(sock) + , m_listening(listening) + { + assert(m_sock >= 0); + } + + virtual ~posix_osd_domain() + { + ::close(m_sock); + } + + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(m_sock, &readfds); + + struct timeval timeout; + timeout.tv_sec = timeout.tv_usec = 0; + + if (select(m_sock + 1, &readfds, nullptr, nullptr, &timeout) < 0) + { + char line[80]; + std::sprintf(line, "%s : %s : %d ", __func__, __FILE__, __LINE__); + std::perror(line); + return errno_to_file_error(errno); + } + else if (FD_ISSET(m_sock, &readfds)) + { + if (!m_listening) + { + // connected socket + ssize_t const result = ::read(m_sock, buffer, count); + if (result < 0) + { + return errno_to_file_error(errno); + } + else + { + actual = std::uint32_t(size_t(result)); + return error::NONE; + } + } + else + { + // listening socket + int const accepted = ::accept(m_sock, nullptr, nullptr); + if (accepted < 0) + { + return errno_to_file_error(errno); + } + else + { + ::close(m_sock); + m_sock = accepted; + m_listening = false; + actual = 0; + + return error::NONE; + } + } + } + else + { + return error::FAILURE; + } + } + + virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + ssize_t const result = ::write(m_sock, buffer, count); + if (result < 0) + return errno_to_file_error(errno); + + actual = std::uint32_t(size_t(result)); + return error::NONE; + } + + virtual error truncate(std::uint64_t offset) override + { + // doesn't make sense on socket + return error::INVALID_ACCESS; + } + + virtual error flush() override + { + // there's no simple way to flush buffers on a socket anyway + return error::NONE; + } + +private: + int m_sock; + bool m_listening; +}; + +} // anonymous namespace + + +bool posix_check_domain_path(std::string const &path) +{ + if (strncmp(path.c_str(), posixfile_domain_identifier, strlen(posixfile_domain_identifier)) == 0) + return true; + return false; +} + + +osd_file::error posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) +{ + struct sockaddr_un sau; + memset(&sau, 0, sizeof(sau)); + sau.sun_family = AF_UNIX; + strncpy(sau.sun_path, &path.c_str()[strlen(posixfile_domain_identifier)], sizeof(sau.sun_path)-1); + + int const sock = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return errno_to_file_error(errno); + + fcntl(sock, F_SETFL, O_NONBLOCK); + + // listening socket support + if (openflags & OPEN_FLAG_CREATE) + { + if (::bind(sock, reinterpret_cast(&sau), sizeof(struct sockaddr_un)) < 0) + { + int const err = errno; + ::close(sock); + return errno_to_file_error(err); + } + + // start to listen... + if (::listen(sock, 1) < 0) + { + int const err = errno; + ::close(sock); + return errno_to_file_error(err); + } + + // mark socket as "listening" + try + { + file = std::make_unique(sock, true); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + ::close(sock); + return osd_file::error::OUT_OF_MEMORY; + } + } + else + { + if (::connect(sock, reinterpret_cast(&sau), sizeof(struct sockaddr_un)) < 0) + { + ::close(sock); + return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure + } + try + { + file = std::make_unique(sock, false); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + ::close(sock); + return osd_file::error::OUT_OF_MEMORY; + } + } +} diff --git a/src/osd/modules/file/posixfile.cpp b/src/osd/modules/file/posixfile.cpp index 967202eb61c..832b6810db4 100644 --- a/src/osd/modules/file/posixfile.cpp +++ b/src/osd/modules/file/posixfile.cpp @@ -217,6 +217,8 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, return posix_open_socket(path, openflags, file, filesize); else if (posix_check_ptty_path(path)) return posix_open_ptty(openflags, file, filesize, dst); + else if (posix_check_domain_path(path)) + return posix_open_domain(path, openflags, file, filesize); // select the file open modes int access; diff --git a/src/osd/modules/file/posixfile.h b/src/osd/modules/file/posixfile.h index 2339a52ceec..6f585ff827a 100644 --- a/src/osd/modules/file/posixfile.h +++ b/src/osd/modules/file/posixfile.h @@ -22,6 +22,9 @@ bool posix_check_socket_path(std::string const &path); osd_file::error posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize); +bool posix_check_domain_path(std::string const &path); +osd_file::error posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize); + bool posix_check_ptty_path(std::string const &path); osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name); diff --git a/src/osd/modules/file/winptty.cpp b/src/osd/modules/file/winptty.cpp index ab0efae37ff..943f1fbaa52 100644 --- a/src/osd/modules/file/winptty.cpp +++ b/src/osd/modules/file/winptty.cpp @@ -88,10 +88,19 @@ osd_file::error win_open_ptty(std::string const &path, std::uint32_t openflags, { osd::text::tstring t_name = osd::text::to_tstring(path); - HANDLE pipe = CreateNamedPipe(t_name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, nullptr); + HANDLE pipe = CreateFileW(t_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); if (INVALID_HANDLE_VALUE == pipe) - return osd_file::error::ACCESS_DENIED; + { + pipe = CreateNamedPipe(t_name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, nullptr); + if (INVALID_HANDLE_VALUE == pipe) + return osd_file::error::ACCESS_DENIED; + } + else + { + DWORD state = PIPE_NOWAIT; + SetNamedPipeHandleState(pipe, &state, NULL, NULL); + } try { diff --git a/src/osd/modules/lib/osdlib.h b/src/osd/modules/lib/osdlib.h index afcc5229371..d080d1edd85 100644 --- a/src/osd/modules/lib/osdlib.h +++ b/src/osd/modules/lib/osdlib.h @@ -63,7 +63,6 @@ int osd_setenv(const char *name, const char *value, int overwrite); char *osd_get_clipboard_text(void); - /*----------------------------------------------------------------------------- dynamic_module: load functions from optional shared libraries diff --git a/src/osd/modules/lib/osdlib_macosx.cpp b/src/osd/modules/lib/osdlib_macosx.cpp index 1f6dec46c76..b476261df41 100644 --- a/src/osd/modules/lib/osdlib_macosx.cpp +++ b/src/osd/modules/lib/osdlib_macosx.cpp @@ -190,6 +190,15 @@ char *osd_get_clipboard_text(void) return result; } +//============================================================ +// osd_getpid +//============================================================ + +int osd_getpid(void) +{ + return getpid(); +} + //============================================================ // dynamic_module_posix_impl //============================================================ diff --git a/src/osd/modules/lib/osdlib_unix.cpp b/src/osd/modules/lib/osdlib_unix.cpp index da3ddc24dea..0bcf34d04b2 100644 --- a/src/osd/modules/lib/osdlib_unix.cpp +++ b/src/osd/modules/lib/osdlib_unix.cpp @@ -125,6 +125,15 @@ char *osd_get_clipboard_text(void) #endif +//============================================================ +// osd_getpid +//============================================================ + +int osd_getpid(void) +{ + return getpid(); +} + //============================================================ // dynamic_module_posix_impl //============================================================ diff --git a/src/osd/modules/lib/osdlib_uwp.cpp b/src/osd/modules/lib/osdlib_uwp.cpp index 864177d9544..dcf995fbd7f 100644 --- a/src/osd/modules/lib/osdlib_uwp.cpp +++ b/src/osd/modules/lib/osdlib_uwp.cpp @@ -175,3 +175,13 @@ char *osd_get_clipboard_text(void) return result; } + +//============================================================ +// osd_getpid +//============================================================ + +int osd_getpid(void) +{ + return -1; +} + diff --git a/src/osd/modules/lib/osdlib_win32.cpp b/src/osd/modules/lib/osdlib_win32.cpp index d4dc3327f17..fb4b29e62af 100644 --- a/src/osd/modules/lib/osdlib_win32.cpp +++ b/src/osd/modules/lib/osdlib_win32.cpp @@ -208,6 +208,15 @@ char *osd_get_clipboard_text(void) return result; } +//============================================================ +// osd_getpid +//============================================================ + +int osd_getpid(void) +{ + return GetCurrentProcessId(); +} + //============================================================ // osd_dynamic_bind //============================================================ diff --git a/src/osd/osdcore.h b/src/osd/osdcore.h index 2bfc7cb5950..ac1571f2dd2 100644 --- a/src/osd/osdcore.h +++ b/src/osd/osdcore.h @@ -243,6 +243,14 @@ public: -----------------------------------------------------------------------------*/ const char *osd_getenv(const char *name); +/*----------------------------------------------------------------------------- + osd_getpid: gets process id + + Return value: + + process id +-----------------------------------------------------------------------------*/ +int osd_getpid(); /*----------------------------------------------------------------------------- osd_get_physical_drive_geometry: if the given path points to a physical