diff --git a/deps/discord-rpc/src/discord_register_linux.c b/deps/discord-rpc/src/discord_register_linux.c new file mode 100644 index 0000000000..60c1cc7d23 --- /dev/null +++ b/deps/discord-rpc/src/discord_register_linux.c @@ -0,0 +1,98 @@ +#include "discord_rpc.h" +#include "discord_register.h" +#include + +#include +#include +#include +#include +#include +#include + +static bool Mkdir(const char* path) +{ + int result = mkdir(path, 0755); + if (result == 0) + return true; + if (errno == EEXIST) + return true; + return false; +} + +/* we want to register games so we can run them from + * Discord client as discord-:// */ +void Discord_Register(const char* applicationId, const char* command) +{ + FILE* fp; + int fileLen; + char xdgMimeCommand[1024]; + char desktopFilename[256]; + char desktopFilePath[1024]; + char desktopFile[2048]; + /* Add a desktop file and update some MIME handlers + * so that xdg-open does the right thing. */ + char exePath[1024]; + const char* home = getenv("HOME"); + if (!home) + return; + + if (!command || !command[0]) + { + ssize_t size = readlink("/proc/self/exe", exePath, sizeof(exePath)); + if (size <= 0 || size >= (ssize_t)sizeof(exePath)) + return; + exePath[size] = '\0'; + command = exePath; + } + + { + const char* desktopFileFormat = "[Desktop Entry]\n" + "Name=Game %s\n" + "Exec=%s\n" /* note: it really wants that %u in there */ + "Type=Application\n" + "NoDisplay=true\n" + "Categories=Discord;Games;\n" + "MimeType=x-scheme-handler/discord-%s;\n"; + fileLen = snprintf( + desktopFile, sizeof(desktopFile), desktopFileFormat, applicationId, command, applicationId); + if (fileLen <= 0) + return; + } + + snprintf(desktopFilename, sizeof(desktopFilename), "/discord-%s.desktop", applicationId); + + snprintf(desktopFilePath, sizeof(desktopFilePath), "%s/.local", home); + if (!Mkdir(desktopFilePath)) + return; + strcat(desktopFilePath, "/share"); + if (!Mkdir(desktopFilePath)) + return; + strcat(desktopFilePath, "/applications"); + if (!Mkdir(desktopFilePath)) + return; + strcat(desktopFilePath, desktopFilename); + + fp = fopen(desktopFilePath, "w"); + if (!fp) + return; + + fwrite(desktopFile, 1, fileLen, fp); + fclose(fp); + + snprintf(xdgMimeCommand, + sizeof(xdgMimeCommand), + "xdg-mime default discord-%s.desktop x-scheme-handler/discord-%s", + applicationId, + applicationId); + if (system(xdgMimeCommand) < 0) + fprintf(stderr, "Failed to register mime handler\n"); +} + +void Discord_RegisterSteamGame( + const char* applicationId, + const char* steamId) +{ + char command[256]; + sprintf(command, "xdg-open steam://rungameid/%s", steamId); + Discord_Register(applicationId, command); +} diff --git a/deps/discord-rpc/src/discord_register_linux.cpp b/deps/discord-rpc/src/discord_register_linux.cpp deleted file mode 100644 index 4e31ad2290..0000000000 --- a/deps/discord-rpc/src/discord_register_linux.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "discord_rpc.h" -#include "discord_register.h" -#include - -#include -#include -#include -#include -#include -#include - -static bool Mkdir(const char* path) -{ - int result = mkdir(path, 0755); - if (result == 0) { - return true; - } - if (errno == EEXIST) { - return true; - } - return false; -} - -// we want to register games so we can run them from Discord client as discord-:// -extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command) -{ - // Add a desktop file and update some mime handlers so that xdg-open does the right thing. - - const char* home = getenv("HOME"); - if (!home) { - return; - } - - char exePath[1024]; - if (!command || !command[0]) { - ssize_t size = readlink("/proc/self/exe", exePath, sizeof(exePath)); - if (size <= 0 || size >= (ssize_t)sizeof(exePath)) { - return; - } - exePath[size] = '\0'; - command = exePath; - } - - const char* destopFileFormat = "[Desktop Entry]\n" - "Name=Game %s\n" - "Exec=%s\n" // note: it really wants that %u in there - "Type=Application\n" - "NoDisplay=true\n" - "Categories=Discord;Games;\n" - "MimeType=x-scheme-handler/discord-%s;\n"; - char desktopFile[2048]; - int fileLen = snprintf( - desktopFile, sizeof(desktopFile), destopFileFormat, applicationId, command, applicationId); - if (fileLen <= 0) { - return; - } - - char desktopFilename[256]; - snprintf(desktopFilename, sizeof(desktopFilename), "/discord-%s.desktop", applicationId); - - char desktopFilePath[1024]; - snprintf(desktopFilePath, sizeof(desktopFilePath), "%s/.local", home); - if (!Mkdir(desktopFilePath)) { - return; - } - strcat(desktopFilePath, "/share"); - if (!Mkdir(desktopFilePath)) { - return; - } - strcat(desktopFilePath, "/applications"); - if (!Mkdir(desktopFilePath)) { - return; - } - strcat(desktopFilePath, desktopFilename); - - FILE* fp = fopen(desktopFilePath, "w"); - if (fp) { - fwrite(desktopFile, 1, fileLen, fp); - fclose(fp); - } - else { - return; - } - - char xdgMimeCommand[1024]; - snprintf(xdgMimeCommand, - sizeof(xdgMimeCommand), - "xdg-mime default discord-%s.desktop x-scheme-handler/discord-%s", - applicationId, - applicationId); - if (system(xdgMimeCommand) < 0) { - fprintf(stderr, "Failed to register mime handler\n"); - } -} - -extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, - const char* steamId) -{ - char command[256]; - sprintf(command, "xdg-open steam://rungameid/%s", steamId); - Discord_Register(applicationId, command); -} diff --git a/deps/discord-rpc/src/discord_register_win.c b/deps/discord-rpc/src/discord_register_win.c new file mode 100644 index 0000000000..1a03603b80 --- /dev/null +++ b/deps/discord-rpc/src/discord_register_win.c @@ -0,0 +1,191 @@ +#include "discord_rpc.h" +#include "discord_register.h" + +#define WIN32_LEAN_AND_MEAN +#define NOMCX +#define NOSERVICE +#define NOIME +#include +#include +#include +#include + +/** + * Updated fixes for MinGW and WinXP + * This block is written the way it does not involve changing the rest of the code + * Checked to be compiling + * 1) strsafe.h belongs to Windows SDK and cannot be added to MinGW + * #include guarded, functions redirected to substitutes + * 2) RegSetKeyValueW and LSTATUS are not declared in + * The entire function is rewritten + */ +#ifdef __MINGW32__ +/* strsafe.h fixes */ +static HRESULT StringCbPrintfW(LPWSTR pszDest, + size_t cbDest, LPCWSTR pszFormat, ...) +{ + HRESULT ret; + va_list va; + va_start(va, pszFormat); + cbDest /= 2; /* Size is divided by 2 to convert from bytes to wide characters - causes segfault */ + /* othervise */ + ret = vsnwprintf(pszDest, cbDest, pszFormat, va); + pszDest[cbDest - 1] = 0; /* Terminate the string in case a buffer overflow; -1 will be returned */ + va_end(va); + return ret; +} +#else +#include +#endif /* __MINGW32__ */ + +/* winreg.h fixes */ +#ifndef LSTATUS +#define LSTATUS LONG +#endif +#ifdef RegSetKeyValueW +#undefine RegSetKeyValueW +#endif +#define RegSetKeyValueW regset +static LSTATUS regset(HKEY hkey, + LPCWSTR subkey, + LPCWSTR name, + DWORD type, + const void* data, + DWORD len) +{ + HKEY htkey = hkey, hsubkey = NULL; + LSTATUS ret; + if (subkey && subkey[0]) + { + if ((ret = RegCreateKeyExW(hkey, subkey, 0, 0, 0, KEY_ALL_ACCESS, 0, &hsubkey, 0)) != + ERROR_SUCCESS) + return ret; + htkey = hsubkey; + } + ret = RegSetValueExW(htkey, name, 0, type, (const BYTE*)data, len); + if (hsubkey && hsubkey != hkey) + RegCloseKey(hsubkey); + return ret; +} + +static void Discord_RegisterW( + const wchar_t* applicationId, const wchar_t* command) +{ + /* https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx + * we want to register games so we can run them as discord-:// + * Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions. */ + + DWORD len; + LSTATUS result; + wchar_t urlProtocol = 0; + wchar_t keyName[256]; + wchar_t protocolName[64]; + wchar_t protocolDescription[128]; + wchar_t exeFilePath[MAX_PATH]; + DWORD exeLen = GetModuleFileNameW(NULL, exeFilePath, MAX_PATH); + wchar_t openCommand[1024]; + + if (command && command[0]) + StringCbPrintfW(openCommand, sizeof(openCommand), L"%S", command); + else + StringCbPrintfW(openCommand, sizeof(openCommand), L"%S", exeFilePath); + + StringCbPrintfW(protocolName, sizeof(protocolName), + L"discord-%S", applicationId); + StringCbPrintfW( + protocolDescription, sizeof(protocolDescription), + L"URL:Run game %S protocol", applicationId); + StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%S", protocolName); + HKEY key; + LSTATUS status = + RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL); + if (status != ERROR_SUCCESS) + { + fprintf(stderr, "Error creating key\n"); + return; + } + len = (DWORD)lstrlenW(protocolDescription) + 1; + result = + RegSetKeyValueW(key, NULL, NULL, REG_SZ, protocolDescription, len * sizeof(wchar_t)); + if (FAILED(result)) { + fprintf(stderr, "Error writing description\n"); + } + + len = (DWORD)lstrlenW(protocolDescription) + 1; + result = RegSetKeyValueW(key, NULL, L"URL Protocol", REG_SZ, &urlProtocol, sizeof(wchar_t)); + if (FAILED(result)) + fprintf(stderr, "Error writing description\n"); + + result = RegSetKeyValueW( + key, L"DefaultIcon", NULL, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t)); + if (FAILED(result)) + fprintf(stderr, "Error writing icon\n"); + + len = (DWORD)lstrlenW(openCommand) + 1; + result = RegSetKeyValueW( + key, L"shell\\open\\command", NULL, REG_SZ, openCommand, len * sizeof(wchar_t)); + if (FAILED(result)) + fprintf(stderr, "Error writing command\n"); + RegCloseKey(key); +} + +void Discord_Register(const char* applicationId, const char* command) +{ + wchar_t openCommand[1024]; + const wchar_t* wcommand = NULL; + wchar_t appId[32]; + + MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); + if (command && command[0]) + { + const int commandBufferLen = + sizeof(openCommand) / sizeof(*openCommand); + MultiByteToWideChar(CP_UTF8, 0, command, -1, + openCommand, commandBufferLen); + wcommand = openCommand; + } + + Discord_RegisterW(appId, wcommand); +} + +void Discord_RegisterSteamGame( + const char* applicationId, + const char* steamId) +{ + DWORD pathChars, pathBytes, i; + HKEY key; + wchar_t steamPath[MAX_PATH]; + wchar_t command[1024]; + wchar_t appId[32]; + wchar_t wSteamId[32]; + MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); + MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32); + LSTATUS status = RegOpenKeyExW(HKEY_CURRENT_USER, + L"Software\\Valve\\Steam", 0, KEY_READ, &key); + if (status != ERROR_SUCCESS) + { + fprintf(stderr, "Error opening Steam key\n"); + return; + } + + pathBytes = sizeof(steamPath); + status = RegQueryValueExW(key, + L"SteamExe", NULL, NULL, (BYTE*)steamPath, &pathBytes); + RegCloseKey(key); + if (status != ERROR_SUCCESS || pathBytes < 1) { + fprintf(stderr, "Error reading SteamExe key\n"); + return; + } + + pathChars = pathBytes / sizeof(wchar_t); + for (i = 0; i < pathChars; ++i) + { + if (steamPath[i] == L'/') + steamPath[i] = L'\\'; + } + + StringCbPrintfW(command, sizeof(command), + L"\"%s\" steam://rungameid/%s", steamPath, wSteamId); + + Discord_RegisterW(appId, command); +} diff --git a/deps/discord-rpc/src/discord_register_win.cpp b/deps/discord-rpc/src/discord_register_win.cpp deleted file mode 100644 index 60b1db3e08..0000000000 --- a/deps/discord-rpc/src/discord_register_win.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "discord_rpc.h" -#include "discord_register.h" - -#define WIN32_LEAN_AND_MEAN -#define NOMCX -#define NOSERVICE -#define NOIME -#include -#include -#include -#include - -/** - * Updated fixes for MinGW and WinXP - * This block is written the way it does not involve changing the rest of the code - * Checked to be compiling - * 1) strsafe.h belongs to Windows SDK and cannot be added to MinGW - * #include guarded, functions redirected to substitutes - * 2) RegSetKeyValueW and LSTATUS are not declared in - * The entire function is rewritten - */ -#ifdef __MINGW32__ -/// strsafe.h fixes -static HRESULT StringCbPrintfW(LPWSTR pszDest, size_t cbDest, LPCWSTR pszFormat, ...) -{ - HRESULT ret; - va_list va; - va_start(va, pszFormat); - cbDest /= 2; // Size is divided by 2 to convert from bytes to wide characters - causes segfault - // othervise - ret = vsnwprintf(pszDest, cbDest, pszFormat, va); - pszDest[cbDest - 1] = 0; // Terminate the string in case a buffer overflow; -1 will be returned - va_end(va); - return ret; -} -#else -#include -#endif // __MINGW32__ - -/// winreg.h fixes -#ifndef LSTATUS -#define LSTATUS LONG -#endif -#ifdef RegSetKeyValueW -#undefine RegSetKeyValueW -#endif -#define RegSetKeyValueW regset -static LSTATUS regset(HKEY hkey, - LPCWSTR subkey, - LPCWSTR name, - DWORD type, - const void* data, - DWORD len) -{ - HKEY htkey = hkey, hsubkey = nullptr; - LSTATUS ret; - if (subkey && subkey[0]) { - if ((ret = RegCreateKeyExW(hkey, subkey, 0, 0, 0, KEY_ALL_ACCESS, 0, &hsubkey, 0)) != - ERROR_SUCCESS) - return ret; - htkey = hsubkey; - } - ret = RegSetValueExW(htkey, name, 0, type, (const BYTE*)data, len); - if (hsubkey && hsubkey != hkey) - RegCloseKey(hsubkey); - return ret; -} - -static void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* command) -{ - // https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx - // we want to register games so we can run them as discord-:// - // Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions. - - wchar_t exeFilePath[MAX_PATH]; - DWORD exeLen = GetModuleFileNameW(nullptr, exeFilePath, MAX_PATH); - wchar_t openCommand[1024]; - - if (command && command[0]) { - StringCbPrintfW(openCommand, sizeof(openCommand), L"%S", command); - } - else { - // StringCbCopyW(openCommand, sizeof(openCommand), exeFilePath); - StringCbPrintfW(openCommand, sizeof(openCommand), L"%S", exeFilePath); - } - - wchar_t protocolName[64]; - StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%S", applicationId); - wchar_t protocolDescription[128]; - StringCbPrintfW( - protocolDescription, sizeof(protocolDescription), L"URL:Run game %S protocol", applicationId); - wchar_t urlProtocol = 0; - - wchar_t keyName[256]; - StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%S", protocolName); - HKEY key; - auto status = - RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr); - if (status != ERROR_SUCCESS) { - fprintf(stderr, "Error creating key\n"); - return; - } - DWORD len; - LSTATUS result; - len = (DWORD)lstrlenW(protocolDescription) + 1; - result = - RegSetKeyValueW(key, nullptr, nullptr, REG_SZ, protocolDescription, len * sizeof(wchar_t)); - if (FAILED(result)) { - fprintf(stderr, "Error writing description\n"); - } - - len = (DWORD)lstrlenW(protocolDescription) + 1; - result = RegSetKeyValueW(key, nullptr, L"URL Protocol", REG_SZ, &urlProtocol, sizeof(wchar_t)); - if (FAILED(result)) { - fprintf(stderr, "Error writing description\n"); - } - - result = RegSetKeyValueW( - key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t)); - if (FAILED(result)) { - fprintf(stderr, "Error writing icon\n"); - } - - len = (DWORD)lstrlenW(openCommand) + 1; - result = RegSetKeyValueW( - key, L"shell\\open\\command", nullptr, REG_SZ, openCommand, len * sizeof(wchar_t)); - if (FAILED(result)) { - fprintf(stderr, "Error writing command\n"); - } - RegCloseKey(key); -} - -extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command) -{ - wchar_t appId[32]; - MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); - - wchar_t openCommand[1024]; - const wchar_t* wcommand = nullptr; - if (command && command[0]) { - const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand); - MultiByteToWideChar(CP_UTF8, 0, command, -1, openCommand, commandBufferLen); - wcommand = openCommand; - } - - Discord_RegisterW(appId, wcommand); -} - -extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, - const char* steamId) -{ - wchar_t appId[32]; - MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); - - wchar_t wSteamId[32]; - MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32); - - HKEY key; - auto status = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", 0, KEY_READ, &key); - if (status != ERROR_SUCCESS) { - fprintf(stderr, "Error opening Steam key\n"); - return; - } - - wchar_t steamPath[MAX_PATH]; - DWORD pathBytes = sizeof(steamPath); - status = RegQueryValueExW(key, L"SteamExe", nullptr, nullptr, (BYTE*)steamPath, &pathBytes); - RegCloseKey(key); - if (status != ERROR_SUCCESS || pathBytes < 1) { - fprintf(stderr, "Error reading SteamExe key\n"); - return; - } - - DWORD pathChars = pathBytes / sizeof(wchar_t); - for (DWORD i = 0; i < pathChars; ++i) { - if (steamPath[i] == L'/') { - steamPath[i] = L'\\'; - } - } - - wchar_t command[1024]; - StringCbPrintfW(command, sizeof(command), L"\"%s\" steam://rungameid/%s", steamPath, wSteamId); - - Discord_RegisterW(appId, command); -} diff --git a/deps/discord-rpc/src/discord_rpc.cpp b/deps/discord-rpc/src/discord_rpc.cpp index 2e44c939ce..743bc12ace 100644 --- a/deps/discord-rpc/src/discord_rpc.cpp +++ b/deps/discord-rpc/src/discord_rpc.cpp @@ -19,20 +19,21 @@ constexpr size_t MaxMessageSize{16 * 1024}; constexpr size_t MessageQueueSize{8}; constexpr size_t JoinQueueSize{8}; -struct QueuedMessage { - size_t length; - char buffer[MaxMessageSize]; +struct QueuedMessage +{ + size_t length; + char buffer[MaxMessageSize]; - void Copy(const QueuedMessage& other) - { - length = other.length; - if (length) { - memcpy(buffer, other.buffer, length); - } - } + void Copy(const QueuedMessage& other) + { + length = other.length; + if (length) + memcpy(buffer, other.buffer, length); + } }; -struct User { +struct User +{ // snowflake (64bit int), turned into a ascii decimal string, at most 20 chars +1 null // terminator = 21 char userId[32]; @@ -104,9 +105,8 @@ public: { keepRunning.exchange(false); Notify(); - if (ioThread.joinable()) { + if (ioThread.joinable()) ioThread.join(); - } } ~IoThreadHolder() { Stop(); } @@ -123,7 +123,7 @@ static IoThreadHolder* IoThread{nullptr}; static void UpdateReconnectTime() { - NextConnect = std::chrono::system_clock::now() + + NextConnect = std::chrono::system_clock::now() + std::chrono::duration{ReconnectTimeMs.nextDelay()}; } @@ -133,102 +133,111 @@ extern "C" DISCORD_EXPORT void Discord_UpdateConnection(void) static void Discord_UpdateConnection(void) #endif { - if (!Connection) { + if (!Connection) return; - } - if (!Connection->IsOpen()) { - if (std::chrono::system_clock::now() >= NextConnect) { + if (!Connection->IsOpen()) + { + if (std::chrono::system_clock::now() >= NextConnect) + { UpdateReconnectTime(); Connection->Open(); } } - else { + else + { // reads - for (;;) { + for (;;) + { JsonDocument message; - if (!Connection->Read(message)) { + if (!Connection->Read(message)) break; - } const char* evtName = GetStrMember(&message, "evt"); const char* nonce = GetStrMember(&message, "nonce"); - if (nonce) { + if (nonce) + { // in responses only -- should use to match up response when needed. - if (evtName && strcmp(evtName, "ERROR") == 0) { + if (evtName && strcmp(evtName, "ERROR") == 0) + { auto data = GetObjMember(&message, "data"); LastErrorCode = GetIntMember(data, "code"); StringCopy(LastErrorMessage, GetStrMember(data, "message", "")); GotErrorMessage.store(true); } } - else { + else + { // should have evt == name of event, optional data - if (evtName == nullptr) { + if (evtName == nullptr) continue; - } auto data = GetObjMember(&message, "data"); - if (strcmp(evtName, "ACTIVITY_JOIN") == 0) { + if (strcmp(evtName, "ACTIVITY_JOIN") == 0) + { auto secret = GetStrMember(data, "secret"); - if (secret) { + if (secret) + { StringCopy(JoinGameSecret, secret); WasJoinGame.store(true); } } - else if (strcmp(evtName, "ACTIVITY_SPECTATE") == 0) { - auto secret = GetStrMember(data, "secret"); - if (secret) { - StringCopy(SpectateGameSecret, secret); - WasSpectateGame.store(true); - } + else if (strcmp(evtName, "ACTIVITY_SPECTATE") == 0) + { + auto secret = GetStrMember(data, "secret"); + if (secret) + { + StringCopy(SpectateGameSecret, secret); + WasSpectateGame.store(true); + } } - else if (strcmp(evtName, "ACTIVITY_JOIN_REQUEST") == 0) { - auto user = GetObjMember(data, "user"); - auto userId = GetStrMember(user, "id"); - auto username = GetStrMember(user, "username"); - auto avatar = GetStrMember(user, "avatar"); - auto joinReq = JoinAskQueue.GetNextAddMessage(); - if (userId && username && joinReq) { - StringCopy(joinReq->userId, userId); - StringCopy(joinReq->username, username); - auto discriminator = GetStrMember(user, "discriminator"); - if (discriminator) { - StringCopy(joinReq->discriminator, discriminator); - } - if (avatar) { - StringCopy(joinReq->avatar, avatar); - } - else { - joinReq->avatar[0] = 0; - } - JoinAskQueue.CommitAdd(); - } + else if (strcmp(evtName, "ACTIVITY_JOIN_REQUEST") == 0) + { + auto user = GetObjMember(data, "user"); + auto userId = GetStrMember(user, "id"); + auto username = GetStrMember(user, "username"); + auto avatar = GetStrMember(user, "avatar"); + auto joinReq = JoinAskQueue.GetNextAddMessage(); + if (userId && username && joinReq) + { + StringCopy(joinReq->userId, userId); + StringCopy(joinReq->username, username); + auto discriminator = GetStrMember(user, "discriminator"); + if (discriminator) + StringCopy(joinReq->discriminator, discriminator); + if (avatar) + StringCopy(joinReq->avatar, avatar); + else + joinReq->avatar[0] = 0; + JoinAskQueue.CommitAdd(); + } } } } // writes - if (QueuedPresence.length) { - QueuedMessage local; - { - std::lock_guard guard(PresenceMutex); - local.Copy(QueuedPresence); - QueuedPresence.length = 0; - } - if (!Connection->Write(local.buffer, local.length)) { - // if we fail to send, requeue - std::lock_guard guard(PresenceMutex); - QueuedPresence.Copy(local); - } + if (QueuedPresence.length) + { + QueuedMessage local; + { + std::lock_guard guard(PresenceMutex); + local.Copy(QueuedPresence); + QueuedPresence.length = 0; + } + if (!Connection->Write(local.buffer, local.length)) { + // if we fail to send, requeue + std::lock_guard guard(PresenceMutex); + QueuedPresence.Copy(local); + } } - while (SendQueue.HavePendingSends()) { + while (SendQueue.HavePendingSends()) + { auto qmessage = SendQueue.GetNextSendMessage(); Connection->Write(qmessage->buffer, qmessage->length); SendQueue.CommitSend(); @@ -236,13 +245,6 @@ static void Discord_UpdateConnection(void) } } -static void SignalIOActivity() -{ - if (IoThread != nullptr) { - IoThread->Notify(); - } -} - static bool RegisterForEvent(const char* evtName) { auto qmessage = SendQueue.GetNextAddMessage(); @@ -250,7 +252,8 @@ static bool RegisterForEvent(const char* evtName) qmessage->length = JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); SendQueue.CommitAdd(); - SignalIOActivity(); + if (IoThread) + IoThread->Notify(); return true; } return false; @@ -263,7 +266,8 @@ static bool DeregisterForEvent(const char* evtName) qmessage->length = JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); SendQueue.CommitAdd(); - SignalIOActivity(); + if (IoThread) + IoThread->Notify(); return true; } return false; @@ -308,31 +312,31 @@ extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId, } Connection = RpcConnection::Create(applicationId); - Connection->onConnect = [](JsonDocument& readyMessage) { + Connection->onConnect = [](JsonDocument& readyMessage) + { Discord_UpdateHandlers(&QueuedHandlers); auto data = GetObjMember(&readyMessage, "data"); auto user = GetObjMember(data, "user"); auto userId = GetStrMember(user, "id"); auto username = GetStrMember(user, "username"); auto avatar = GetStrMember(user, "avatar"); - if (userId && username) { + if (userId && username) + { StringCopy(connectedUser.userId, userId); StringCopy(connectedUser.username, username); auto discriminator = GetStrMember(user, "discriminator"); - if (discriminator) { + if (discriminator) StringCopy(connectedUser.discriminator, discriminator); - } - if (avatar) { + if (avatar) StringCopy(connectedUser.avatar, avatar); - } - else { + else connectedUser.avatar[0] = 0; - } } WasJustConnected.exchange(true); ReconnectTimeMs.reset(); }; - Connection->onDisconnect = [](int err, const char* message) { + Connection->onDisconnect = [](int err, const char* message) + { LastDisconnectErrorCode = err; StringCopy(LastDisconnectErrorMessage, message); { @@ -348,13 +352,13 @@ extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId, extern "C" DISCORD_EXPORT void Discord_Shutdown(void) { - if (!Connection) { + if (!Connection) return; - } - Connection->onConnect = nullptr; + Connection->onConnect = nullptr; Connection->onDisconnect = nullptr; Handlers = {}; - if (IoThread != nullptr) { + if (IoThread != nullptr) + { IoThread->Stop(); delete IoThread; IoThread = nullptr; @@ -370,7 +374,8 @@ extern "C" DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* QueuedPresence.length = JsonWriteRichPresenceObj( QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence); } - SignalIOActivity(); + if (IoThread) + IoThread->Notify(); } extern "C" DISCORD_EXPORT void Discord_ClearPresence(void) @@ -381,15 +386,16 @@ extern "C" DISCORD_EXPORT void Discord_ClearPresence(void) extern "C" DISCORD_EXPORT void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int reply) { // if we are not connected, let's not batch up stale messages for later - if (!Connection || !Connection->IsOpen()) { + if (!Connection || !Connection->IsOpen()) return; - } auto qmessage = SendQueue.GetNextAddMessage(); - if (qmessage) { + if (qmessage) + { qmessage->length = JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++); SendQueue.CommitAdd(); - SignalIOActivity(); + if (IoThread) + IoThread->Notify(); } } @@ -399,24 +405,25 @@ extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void) // of times inbetween calls here. Externally, we want the sequence to seem sane, so any other // signals are book-ended by calls to ready and disconnect. - if (!Connection) { + if (!Connection) return; - } bool wasDisconnected = WasJustDisconnected.exchange(false); - bool isConnected = Connection->IsOpen(); + bool isConnected = Connection->IsOpen(); - if (isConnected) { + if (isConnected) + { // if we are connected, disconnect cb first std::lock_guard guard(HandlerMutex); - if (wasDisconnected && Handlers.disconnected) { + if (wasDisconnected && Handlers.disconnected) Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage); - } } - if (WasJustConnected.exchange(false)) { + if (WasJustConnected.exchange(false)) + { std::lock_guard guard(HandlerMutex); - if (Handlers.ready) { + if (Handlers.ready) + { DiscordUser du{connectedUser.userId, connectedUser.username, connectedUser.discriminator, @@ -425,25 +432,25 @@ extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void) } } - if (GotErrorMessage.exchange(false)) { + if (GotErrorMessage.exchange(false)) + { std::lock_guard guard(HandlerMutex); - if (Handlers.errored) { + if (Handlers.errored) Handlers.errored(LastErrorCode, LastErrorMessage); - } } - if (WasJoinGame.exchange(false)) { + if (WasJoinGame.exchange(false)) + { std::lock_guard guard(HandlerMutex); - if (Handlers.joinGame) { + if (Handlers.joinGame) Handlers.joinGame(JoinGameSecret); - } } - if (WasSpectateGame.exchange(false)) { + if (WasSpectateGame.exchange(false)) + { std::lock_guard guard(HandlerMutex); - if (Handlers.spectateGame) { + if (Handlers.spectateGame) Handlers.spectateGame(SpectateGameSecret); - } } // Right now this batches up any requests and sends them all in a burst; I could imagine a world @@ -451,11 +458,13 @@ extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void) // is sent. I left it this way because I could also imagine wanting to process these all and // maybe show them in one common dialog and/or start fetching the avatars in parallel, and if // not it should be trivial for the implementer to make a queue themselves. - while (JoinAskQueue.HavePendingSends()) { + while (JoinAskQueue.HavePendingSends()) + { auto req = JoinAskQueue.GetNextSendMessage(); { std::lock_guard guard(HandlerMutex); - if (Handlers.joinRequest) { + if (Handlers.joinRequest) + { DiscordUser du{req->userId, req->username, req->discriminator, req->avatar}; Handlers.joinRequest(&du); } @@ -463,38 +472,37 @@ extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void) JoinAskQueue.CommitSend(); } - if (!isConnected) { + if (!isConnected) + { // if we are not connected, disconnect message last std::lock_guard guard(HandlerMutex); - if (wasDisconnected && Handlers.disconnected) { + if (wasDisconnected && Handlers.disconnected) Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage); - } } } +#ifndef HANDLE_EVENT_REGISTRATION +#define HANDLE_EVENT_REGISTRATION(handler_name, event) \ + if (!Handlers.handler_name && newHandlers->handler_name) \ + RegisterForEvent(event); \ + else if (Handlers.handler_name && !newHandlers->handler_name) \ + DeregisterForEvent(event) +#endif + extern "C" DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* newHandlers) { - if (newHandlers) { -#define HANDLE_EVENT_REGISTRATION(handler_name, event) \ - if (!Handlers.handler_name && newHandlers->handler_name) { \ - RegisterForEvent(event); \ - } \ - else if (Handlers.handler_name && !newHandlers->handler_name) { \ - DeregisterForEvent(event); \ - } + if (newHandlers) + { + std::lock_guard guard(HandlerMutex); + HANDLE_EVENT_REGISTRATION(joinGame, "ACTIVITY_JOIN"); + HANDLE_EVENT_REGISTRATION(spectateGame, "ACTIVITY_SPECTATE"); + HANDLE_EVENT_REGISTRATION(joinRequest, "ACTIVITY_JOIN_REQUEST"); - std::lock_guard guard(HandlerMutex); - HANDLE_EVENT_REGISTRATION(joinGame, "ACTIVITY_JOIN") - HANDLE_EVENT_REGISTRATION(spectateGame, "ACTIVITY_SPECTATE") - HANDLE_EVENT_REGISTRATION(joinRequest, "ACTIVITY_JOIN_REQUEST") - -#undef HANDLE_EVENT_REGISTRATION - - Handlers = *newHandlers; - } - else { - std::lock_guard guard(HandlerMutex); - Handlers = {}; - } - return; + Handlers = *newHandlers; + } + else + { + std::lock_guard guard(HandlerMutex); + Handlers = {}; + } } diff --git a/deps/discord-rpc/src/dllmain.cpp b/deps/discord-rpc/src/dllmain.cpp deleted file mode 100644 index fbfc2950d7..0000000000 --- a/deps/discord-rpc/src/dllmain.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -// outsmart GCC's missing-declarations warning -BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID); -BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID) -{ - return TRUE; -} diff --git a/deps/discord-rpc/src/msg_queue.h b/deps/discord-rpc/src/msg_queue.h index 77f380e705..f8df267a2a 100644 --- a/deps/discord-rpc/src/msg_queue.h +++ b/deps/discord-rpc/src/msg_queue.h @@ -2,8 +2,8 @@ #include -// A simple queue. No locks, but only works with a single thread as producer and a single thread as -// a consumer. Mutex up as needed. +/* A simple queue. No locks, but only works with a single thread as producer and a single thread as + * a consumer. Mutex up as needed. */ template class MsgQueue { @@ -17,10 +17,9 @@ public: ElementType* GetNextAddMessage() { - // if we are falling behind, bail - if (pendingSends_.load() >= QueueSize) { + /* if we are falling behind, bail */ + if (pendingSends_.load() >= QueueSize) return nullptr; - } auto index = (nextAdd_++) % QueueSize; return &queue_[index]; } diff --git a/deps/discord-rpc/src/rpc_connection.cpp b/deps/discord-rpc/src/rpc_connection.cpp index bf9e4cc7a4..9e11b7ee4b 100644 --- a/deps/discord-rpc/src/rpc_connection.cpp +++ b/deps/discord-rpc/src/rpc_connection.cpp @@ -22,50 +22,49 @@ static RpcConnection Instance; void RpcConnection::Open() { - if (state == State::Connected) { + if (state == State::Connected) return; + + if (state == State::Disconnected) + { + if (!connection->Open()) + return; } - if (state == State::Disconnected) { - if (connection->Open()) { - } - else { - return; - } + if (state == State::SentHandshake) + { + JsonDocument message; + if (Read(message)) + { + auto cmd = GetStrMember(&message, "cmd"); + auto evt = GetStrMember(&message, "evt"); + if (cmd && evt + && !strcmp(cmd, "DISPATCH") + && !strcmp(evt, "READY")) + { + state = State::Connected; + if (onConnect) + onConnect(message); + } + } } - - if (state == State::SentHandshake) { - JsonDocument message; - if (Read(message)) { - auto cmd = GetStrMember(&message, "cmd"); - auto evt = GetStrMember(&message, "evt"); - if (cmd && evt && !strcmp(cmd, "DISPATCH") && !strcmp(evt, "READY")) { - state = State::Connected; - if (onConnect) { - onConnect(message); - } - } - } - } - else { + else + { sendFrame.opcode = Opcode::Handshake; sendFrame.length = (uint32_t)JsonWriteHandshakeObj( sendFrame.message, sizeof(sendFrame.message), RpcVersion, appId); - if (connection->Write(&sendFrame, sizeof(MessageFrameHeader) + sendFrame.length)) { + if (connection->Write(&sendFrame, sizeof(MessageFrameHeader) + sendFrame.length)) state = State::SentHandshake; - } - else { + else Close(); - } } } void RpcConnection::Close() { - if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) { + if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) onDisconnect(lastErrorCode, lastErrorMessage); - } connection->Close(); state = State::Disconnected; } @@ -75,7 +74,8 @@ bool RpcConnection::Write(const void* data, size_t length) sendFrame.opcode = Opcode::Frame; memcpy(sendFrame.message, data, length); sendFrame.length = (uint32_t)length; - if (!connection->Write(&sendFrame, sizeof(MessageFrameHeader) + length)) { + if (!connection->Write(&sendFrame, sizeof(MessageFrameHeader) + length)) + { Close(); return false; } @@ -84,14 +84,16 @@ bool RpcConnection::Write(const void* data, size_t length) bool RpcConnection::Read(JsonDocument& message) { - if (state != State::Connected && state != State::SentHandshake) { + if (state != State::Connected && state != State::SentHandshake) return false; - } MessageFrame readFrame; - for (;;) { + for (;;) + { bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader)); - if (!didRead) { - if (!connection->isOpen) { + if (!didRead) + { + if (!connection->isOpen) + { lastErrorCode = (int)ErrorCode::PipeClosed; StringCopy(lastErrorMessage, "Pipe closed"); Close(); @@ -99,9 +101,11 @@ bool RpcConnection::Read(JsonDocument& message) return false; } - if (readFrame.length > 0) { + if (readFrame.length > 0) + { didRead = connection->Read(readFrame.message, readFrame.length); - if (!didRead) { + if (!didRead) + { lastErrorCode = (int)ErrorCode::ReadCorrupt; StringCopy(lastErrorMessage, "Partial data in frame"); Close(); @@ -110,32 +114,33 @@ bool RpcConnection::Read(JsonDocument& message) readFrame.message[readFrame.length] = 0; } - switch (readFrame.opcode) { - case Opcode::Close: { - message.ParseInsitu(readFrame.message); - lastErrorCode = GetIntMember(&message, "code"); - StringCopy(lastErrorMessage, GetStrMember(&message, "message", "")); - Close(); - return false; - } - case Opcode::Frame: - message.ParseInsitu(readFrame.message); - return true; - case Opcode::Ping: - readFrame.opcode = Opcode::Pong; - if (!connection->Write(&readFrame, sizeof(MessageFrameHeader) + readFrame.length)) { - Close(); - } - break; - case Opcode::Pong: - break; - case Opcode::Handshake: - default: - // something bad happened - lastErrorCode = (int)ErrorCode::ReadCorrupt; - StringCopy(lastErrorMessage, "Bad ipc frame"); - Close(); - return false; + switch (readFrame.opcode) + { + case Opcode::Close: + { + message.ParseInsitu(readFrame.message); + lastErrorCode = GetIntMember(&message, "code"); + StringCopy(lastErrorMessage, GetStrMember(&message, "message", "")); + Close(); + return false; + } + case Opcode::Frame: + message.ParseInsitu(readFrame.message); + return true; + case Opcode::Ping: + readFrame.opcode = Opcode::Pong; + if (!connection->Write(&readFrame, sizeof(MessageFrameHeader) + readFrame.length)) + Close(); + break; + case Opcode::Pong: + break; + case Opcode::Handshake: + default: + // something bad happened + lastErrorCode = (int)ErrorCode::ReadCorrupt; + StringCopy(lastErrorMessage, "Bad ipc frame"); + Close(); + return false; } } } diff --git a/griffin/griffin.c b/griffin/griffin.c index 01e4527ea8..d064b3b297 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1526,6 +1526,15 @@ HTTP SERVER ============================================================ */ #if defined(HAVE_DISCORD) #include "../discord/discord.c" + +#if defined(_WIN32) +#include "../deps/discord-rpc/src/discord_register_win.c" +#endif + +#if defined(__linux__) +#include "../deps/discord-rpc/src/discord_register_linux.c" +#endif + #endif /*============================================================ diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index ecc3b93c30..a5223d11ba 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -144,12 +144,8 @@ FONTS #include "../deps/discord-rpc/src/serialization.cpp" #if defined(_WIN32) -#include "../deps/discord-rpc/src/discord_register_win.cpp" #include "../deps/discord-rpc/src/connection_win.cpp" #endif -#if defined(__linux__) -#include "../deps/discord-rpc/src/discord_register_linux.cpp" -#endif #if defined(__unix__) || defined(__APPLE__) #include "../deps/discord-rpc/src/connection_unix.cpp" #endif