mirror of
https://github.com/holub/mame
synced 2025-10-04 16:34:53 +03:00
Discord plugin try 2 (#3640)
* plugins/discord: discord presence plugin [Carl] * plugins/discord: use domain sockets and pipes [Carl] * winptty: fix connecting to existing socket (nw) plugins/discord: show pause state (nw) * plugins/discord: fix pause behavior (nw)
This commit is contained in:
parent
eee8d0d2d9
commit
a99407afb5
106
plugins/discord/init.lua
Executable file
106
plugins/discord/init.lua
Executable file
@ -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("<I4I4", 0, #output) .. output)
|
||||||
|
local time = os.time()
|
||||||
|
local data = ""
|
||||||
|
repeat
|
||||||
|
local res = pipe:read(100)
|
||||||
|
data = data .. res
|
||||||
|
until #res == 0 and #data > 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("<I4I4", 1, #output) .. output)
|
||||||
|
local time = os.time()
|
||||||
|
local data = ""
|
||||||
|
repeat
|
||||||
|
local res = pipe:read(100)
|
||||||
|
data = data .. res
|
||||||
|
until #res == 0 and #data > 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
|
10
plugins/discord/plugin.json
Normal file
10
plugins/discord/plugin.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"plugin": {
|
||||||
|
"name": "discord",
|
||||||
|
"description": "Discord presence",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"author": "Carl",
|
||||||
|
"type": "plugin",
|
||||||
|
"start": "false"
|
||||||
|
}
|
||||||
|
}
|
@ -462,6 +462,7 @@ project ("ocore_" .. _OPTIONS["osd"])
|
|||||||
if BASE_TARGETOS=="unix" then
|
if BASE_TARGETOS=="unix" then
|
||||||
files {
|
files {
|
||||||
MAME_DIR .. "src/osd/modules/file/posixdir.cpp",
|
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.cpp",
|
||||||
MAME_DIR .. "src/osd/modules/file/posixfile.h",
|
MAME_DIR .. "src/osd/modules/file/posixfile.h",
|
||||||
MAME_DIR .. "src/osd/modules/file/posixptty.cpp",
|
MAME_DIR .. "src/osd/modules/file/posixptty.cpp",
|
||||||
|
@ -807,6 +807,7 @@ void lua_engine::initialize()
|
|||||||
return lua_yield(L, 0);
|
return lua_yield(L, 0);
|
||||||
});
|
});
|
||||||
emu["lang_translate"] = &lang_translate;
|
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)
|
* 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)
|
||||||
|
207
src/osd/modules/file/posixdomain.cpp
Normal file
207
src/osd/modules/file/posixdomain.cpp
Normal file
@ -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 <cassert>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
|
||||||
|
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<struct sockaddr const *>(&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<posix_osd_domain>(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<struct sockaddr const *>(&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<posix_osd_domain>(sock, false);
|
||||||
|
filesize = 0;
|
||||||
|
return osd_file::error::NONE;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
::close(sock);
|
||||||
|
return osd_file::error::OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
return posix_open_socket(path, openflags, file, filesize);
|
||||||
else if (posix_check_ptty_path(path))
|
else if (posix_check_ptty_path(path))
|
||||||
return posix_open_ptty(openflags, file, filesize, dst);
|
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
|
// select the file open modes
|
||||||
int access;
|
int access;
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
bool posix_check_socket_path(std::string const &path);
|
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);
|
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);
|
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);
|
osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name);
|
||||||
|
|
||||||
|
@ -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);
|
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)
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -63,7 +63,6 @@ int osd_setenv(const char *name, const char *value, int overwrite);
|
|||||||
|
|
||||||
char *osd_get_clipboard_text(void);
|
char *osd_get_clipboard_text(void);
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
dynamic_module: load functions from optional shared libraries
|
dynamic_module: load functions from optional shared libraries
|
||||||
|
|
||||||
|
@ -190,6 +190,15 @@ char *osd_get_clipboard_text(void)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// osd_getpid
|
||||||
|
//============================================================
|
||||||
|
|
||||||
|
int osd_getpid(void)
|
||||||
|
{
|
||||||
|
return getpid();
|
||||||
|
}
|
||||||
|
|
||||||
//============================================================
|
//============================================================
|
||||||
// dynamic_module_posix_impl
|
// dynamic_module_posix_impl
|
||||||
//============================================================
|
//============================================================
|
||||||
|
@ -125,6 +125,15 @@ char *osd_get_clipboard_text(void)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// osd_getpid
|
||||||
|
//============================================================
|
||||||
|
|
||||||
|
int osd_getpid(void)
|
||||||
|
{
|
||||||
|
return getpid();
|
||||||
|
}
|
||||||
|
|
||||||
//============================================================
|
//============================================================
|
||||||
// dynamic_module_posix_impl
|
// dynamic_module_posix_impl
|
||||||
//============================================================
|
//============================================================
|
||||||
|
@ -175,3 +175,13 @@ char *osd_get_clipboard_text(void)
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// osd_getpid
|
||||||
|
//============================================================
|
||||||
|
|
||||||
|
int osd_getpid(void)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -208,6 +208,15 @@ char *osd_get_clipboard_text(void)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// osd_getpid
|
||||||
|
//============================================================
|
||||||
|
|
||||||
|
int osd_getpid(void)
|
||||||
|
{
|
||||||
|
return GetCurrentProcessId();
|
||||||
|
}
|
||||||
|
|
||||||
//============================================================
|
//============================================================
|
||||||
// osd_dynamic_bind
|
// osd_dynamic_bind
|
||||||
//============================================================
|
//============================================================
|
||||||
|
@ -243,6 +243,14 @@ public:
|
|||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
const char *osd_getenv(const char *name);
|
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
|
osd_get_physical_drive_geometry: if the given path points to a physical
|
||||||
|
Loading…
Reference in New Issue
Block a user