(Discord RPC) Update
This commit is contained in:
parent
3cd320fa83
commit
a6030f89fe
|
@ -5,8 +5,7 @@
|
|||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
struct Backoff
|
||||
{
|
||||
struct Backoff {
|
||||
int64_t minAmount;
|
||||
int64_t maxAmount;
|
||||
int64_t current;
|
||||
|
|
|
@ -6,10 +6,9 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
/* not really connectiony, but need per-platform */
|
||||
int GetProcessId(void);
|
||||
int GetProcessId();
|
||||
|
||||
struct BaseConnection
|
||||
{
|
||||
struct BaseConnection {
|
||||
static BaseConnection* Create();
|
||||
static void Destroy(BaseConnection*&);
|
||||
bool isOpen{false};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include "discord_rpc.h"
|
||||
#include "discord_register.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
@ -11,11 +13,9 @@
|
|||
#include <file/file_path.h>
|
||||
#include <compat/strl.h>
|
||||
|
||||
#include <discord_rpc.h>
|
||||
|
||||
/* we want to register games so we can run them from
|
||||
* Discord client as discord-<appid>:// */
|
||||
void Discord_Register(const char *applicationId, const char *command)
|
||||
void Discord_Register(const char* applicationId, const char* command)
|
||||
{
|
||||
FILE* fp;
|
||||
int fileLen;
|
||||
|
@ -82,7 +82,9 @@ void Discord_Register(const char *applicationId, const char *command)
|
|||
fprintf(stderr, "Failed to register mime handler\n");
|
||||
}
|
||||
|
||||
void Discord_RegisterSteamGame(const char *applicationId, const char *steamId)
|
||||
void Discord_RegisterSteamGame(
|
||||
const char* applicationId,
|
||||
const char* steamId)
|
||||
{
|
||||
char command[256];
|
||||
snprintf(command, sizeof(command), "xdg-open steam://rungameid/%s", steamId);
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
#include "../include/discord_register.h"
|
||||
|
||||
static void RegisterCommand(const char* applicationId, const char* command)
|
||||
{
|
||||
/* There does not appear to be a way to register arbitrary commands on OSX, so instead we'll save the command
|
||||
|
@ -56,7 +58,9 @@ static void RegisterURL(const char* applicationId)
|
|||
|
||||
status = LSRegisterURL((__bridge CFURLRef)myURL, true);
|
||||
if (status != noErr)
|
||||
{
|
||||
fprintf(stderr, "Error in LSRegisterURL: %d\n", (int)status);
|
||||
}
|
||||
}
|
||||
|
||||
void Discord_Register(const char* applicationId, const char* command)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "discord_rpc.h"
|
||||
#include "discord_register.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMCX
|
||||
|
@ -52,8 +53,8 @@ static LSTATUS regset(HKEY hkey,
|
|||
const void* data,
|
||||
DWORD len)
|
||||
{
|
||||
LSTATUS ret;
|
||||
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)) !=
|
||||
|
@ -106,8 +107,9 @@ static void Discord_RegisterW(
|
|||
len = (DWORD)lstrlenW(protocolDescription) + 1;
|
||||
result =
|
||||
RegSetKeyValueW(key, NULL, NULL, REG_SZ, protocolDescription, len * sizeof(wchar_t));
|
||||
if (FAILED(result))
|
||||
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));
|
||||
|
@ -129,12 +131,11 @@ static void Discord_RegisterW(
|
|||
|
||||
void Discord_Register(const char* applicationId, const char* command)
|
||||
{
|
||||
wchar_t appId[32];
|
||||
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 =
|
||||
|
@ -171,8 +172,7 @@ void Discord_RegisterSteamGame(
|
|||
status = RegQueryValueExW(key,
|
||||
L"SteamExe", NULL, NULL, (BYTE*)steamPath, &pathBytes);
|
||||
RegCloseKey(key);
|
||||
if (status != ERROR_SUCCESS || pathBytes < 1)
|
||||
{
|
||||
if (status != ERROR_SUCCESS || pathBytes < 1) {
|
||||
fprintf(stderr, "Error reading SteamExe key\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <retro_common_api.h>
|
||||
#include "discord_rpc.h"
|
||||
|
||||
#include "backoff.h"
|
||||
#include "discord_register.h"
|
||||
#include "msg_queue.h"
|
||||
#include "rpc_connection.h"
|
||||
#include "serialization.h"
|
||||
|
@ -15,23 +15,14 @@
|
|||
#include <thread>
|
||||
#endif
|
||||
|
||||
|
||||
/* Forward declarations */
|
||||
#if defined(__cplusplus) && !defined(CXX_BUILD)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void Discord_Register(const char *a, const char *b);
|
||||
void Discord_RegisterSteamGame(const char *a, const char *b);
|
||||
|
||||
#if defined(__cplusplus) && !defined(CXX_BUILD)
|
||||
}
|
||||
#endif
|
||||
constexpr size_t MaxMessageSize{16 * 1024};
|
||||
constexpr size_t MessageQueueSize{8};
|
||||
constexpr size_t JoinQueueSize{8};
|
||||
|
||||
struct QueuedMessage
|
||||
{
|
||||
size_t length;
|
||||
char buffer[16384];
|
||||
char buffer[MaxMessageSize];
|
||||
|
||||
void Copy(const QueuedMessage& other)
|
||||
{
|
||||
|
@ -59,32 +50,25 @@ struct User
|
|||
* from future changes in these sizes */
|
||||
};
|
||||
|
||||
static int Pid{0};
|
||||
static int Nonce{1};
|
||||
static int LastErrorCode{0};
|
||||
static int LastDisconnectErrorCode{0};
|
||||
|
||||
static char JoinGameSecret[256];
|
||||
static char SpectateGameSecret[256];
|
||||
static char LastErrorMessage[256];
|
||||
static char LastDisconnectErrorMessage[256];
|
||||
|
||||
static RpcConnection* Connection{nullptr};
|
||||
|
||||
static DiscordEventHandlers QueuedHandlers{};
|
||||
static DiscordEventHandlers Handlers{};
|
||||
|
||||
static std::atomic_bool WasJustConnected{false};
|
||||
static std::atomic_bool WasJustDisconnected{false};
|
||||
static std::atomic_bool GotErrorMessage{false};
|
||||
static std::atomic_bool WasJoinGame{false};
|
||||
static std::atomic_bool WasSpectateGame{false};
|
||||
|
||||
static char JoinGameSecret[256];
|
||||
static char SpectateGameSecret[256];
|
||||
static int LastErrorCode{0};
|
||||
static char LastErrorMessage[256];
|
||||
static int LastDisconnectErrorCode{0};
|
||||
static char LastDisconnectErrorMessage[256];
|
||||
static std::mutex PresenceMutex;
|
||||
static std::mutex HandlerMutex;
|
||||
static QueuedMessage QueuedPresence{};
|
||||
static MsgQueue<QueuedMessage, 8> SendQueue;
|
||||
static MsgQueue<User, 8> JoinAskQueue;
|
||||
static MsgQueue<QueuedMessage, MessageQueueSize> SendQueue;
|
||||
static MsgQueue<User, JoinQueueSize> JoinAskQueue;
|
||||
static User connectedUser;
|
||||
|
||||
/* We want to auto connect, and retry on failure,
|
||||
|
@ -92,18 +76,19 @@ static User connectedUser;
|
|||
* backoff from 0.5 seconds to 1 minute */
|
||||
static Backoff ReconnectTimeMs(500, 60 * 1000);
|
||||
static auto NextConnect = std::chrono::system_clock::now();
|
||||
static int Pid{0};
|
||||
static int Nonce{1};
|
||||
|
||||
#ifndef DISCORD_DISABLE_IO_THREAD
|
||||
static void Discord_UpdateConnection(void);
|
||||
class IoThreadHolder
|
||||
{
|
||||
private:
|
||||
class IoThreadHolder {
|
||||
private:
|
||||
std::atomic_bool keepRunning{true};
|
||||
std::mutex waitForIOMutex;
|
||||
std::condition_variable waitForIOActivity;
|
||||
std::thread ioThread;
|
||||
|
||||
public:
|
||||
public:
|
||||
void Start()
|
||||
{
|
||||
keepRunning.store(true);
|
||||
|
@ -131,9 +116,8 @@ class IoThreadHolder
|
|||
~IoThreadHolder() { Stop(); }
|
||||
};
|
||||
#else
|
||||
class IoThreadHolder
|
||||
{
|
||||
public:
|
||||
class IoThreadHolder {
|
||||
public:
|
||||
void Start() {}
|
||||
void Stop() {}
|
||||
void Notify() {}
|
||||
|
@ -142,7 +126,7 @@ class IoThreadHolder
|
|||
|
||||
static IoThreadHolder* IoThread{nullptr};
|
||||
|
||||
static void UpdateReconnectTime(void)
|
||||
static void UpdateReconnectTime()
|
||||
{
|
||||
NextConnect = std::chrono::system_clock::now() +
|
||||
std::chrono::duration<int64_t, std::milli>{ReconnectTimeMs.nextDelay()};
|
||||
|
@ -176,17 +160,17 @@ static void Discord_UpdateConnection(void)
|
|||
if (!Connection->Read(message))
|
||||
break;
|
||||
|
||||
const char *evtName = GetStrMember(&message, "evt");
|
||||
const char *nonce = GetStrMember(&message, "nonce");
|
||||
const char* evtName = GetStrMember(&message, "evt");
|
||||
const char* nonce = GetStrMember(&message, "nonce");
|
||||
|
||||
if (nonce)
|
||||
{
|
||||
/* in responses only --
|
||||
* should use to match up response when needed. */
|
||||
|
||||
if (evtName && !strcmp(evtName, "ERROR"))
|
||||
if (evtName && strcmp(evtName, "ERROR") == 0)
|
||||
{
|
||||
JsonValue *data = GetObjMember(&message, "data");
|
||||
auto data = GetObjMember(&message, "data");
|
||||
LastErrorCode = GetIntMember(data, "code");
|
||||
StringCopy(LastErrorMessage, GetStrMember(data, "message", ""));
|
||||
GotErrorMessage.store(true);
|
||||
|
@ -198,40 +182,39 @@ static void Discord_UpdateConnection(void)
|
|||
if (!evtName)
|
||||
continue;
|
||||
|
||||
JsonValue *data = GetObjMember(&message, "data");
|
||||
auto data = GetObjMember(&message, "data");
|
||||
|
||||
if (!strcmp(evtName, "ACTIVITY_JOIN"))
|
||||
if (strcmp(evtName, "ACTIVITY_JOIN") == 0)
|
||||
{
|
||||
const char *secret = GetStrMember(data, "secret");
|
||||
auto secret = GetStrMember(data, "secret");
|
||||
if (secret)
|
||||
{
|
||||
StringCopy(JoinGameSecret, secret);
|
||||
WasJoinGame.store(true);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(evtName, "ACTIVITY_SPECTATE"))
|
||||
else if (strcmp(evtName, "ACTIVITY_SPECTATE") == 0)
|
||||
{
|
||||
const char *secret = GetStrMember(data, "secret");
|
||||
auto secret = GetStrMember(data, "secret");
|
||||
if (secret)
|
||||
{
|
||||
StringCopy(SpectateGameSecret, secret);
|
||||
WasSpectateGame.store(true);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(evtName, "ACTIVITY_JOIN_REQUEST"))
|
||||
else if (strcmp(evtName, "ACTIVITY_JOIN_REQUEST") == 0)
|
||||
{
|
||||
JsonValue *user = GetObjMember(data, "user");
|
||||
const char *userId = GetStrMember(user, "id");
|
||||
const char *username = GetStrMember(user, "username");
|
||||
const char *avatar = GetStrMember(user, "avatar");
|
||||
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);
|
||||
const char *discriminator = GetStrMember(user,
|
||||
"discriminator");
|
||||
auto discriminator = GetStrMember(user, "discriminator");
|
||||
if (discriminator)
|
||||
StringCopy(joinReq->discriminator, discriminator);
|
||||
if (avatar)
|
||||
|
@ -338,16 +321,16 @@ extern "C" DISCORD_EXPORT void Discord_Initialize(
|
|||
Connection->onConnect = [](JsonDocument& readyMessage)
|
||||
{
|
||||
Discord_UpdateHandlers(&QueuedHandlers);
|
||||
JsonValue *data = GetObjMember(&readyMessage, "data");
|
||||
JsonValue *user = GetObjMember(data, "user");
|
||||
const char *userId = GetStrMember(user, "id");
|
||||
const char *username = GetStrMember(user, "username");
|
||||
const char *avatar = GetStrMember(user, "avatar");
|
||||
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)
|
||||
{
|
||||
StringCopy(connectedUser.userId, userId);
|
||||
StringCopy(connectedUser.username, username);
|
||||
const char *discriminator = GetStrMember(user, "discriminator");
|
||||
auto discriminator = GetStrMember(user, "discriminator");
|
||||
if (discriminator)
|
||||
StringCopy(connectedUser.discriminator, discriminator);
|
||||
if (avatar)
|
||||
|
|
|
@ -36,8 +36,8 @@ void RpcConnection::Open()
|
|||
JsonDocument message;
|
||||
if (Read(message))
|
||||
{
|
||||
const char *cmd = GetStrMember(&message, "cmd");
|
||||
const char *evt = GetStrMember(&message, "evt");
|
||||
auto cmd = GetStrMember(&message, "cmd");
|
||||
auto evt = GetStrMember(&message, "evt");
|
||||
if (cmd && evt
|
||||
&& !strcmp(cmd, "DISPATCH")
|
||||
&& !strcmp(evt, "READY"))
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
/* I took this from the buffer size libuv uses for named pipes;
|
||||
* I suspect ours would usually be much smaller. */
|
||||
#define MAX_RPC_FRAMESIZE 65536
|
||||
constexpr size_t MaxRpcFrameSize = 64 * 1024;
|
||||
|
||||
struct RpcConnection
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ struct RpcConnection
|
|||
|
||||
struct MessageFrame : public MessageFrameHeader
|
||||
{
|
||||
char message[MAX_RPC_FRAMESIZE - sizeof(MessageFrameHeader)];
|
||||
char message[MaxRpcFrameSize - sizeof(MessageFrameHeader)];
|
||||
};
|
||||
|
||||
enum class State : uint32_t
|
||||
|
|
Loading…
Reference in New Issue