diff --git a/CMakeLists.txt b/CMakeLists.txt index a3d1d8e..f66e701 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,6 @@ add_subdirectory(src) add_subdirectory(examples/simple) if(WIN32) - add_subdirectory(examples/simpleSync) add_subdirectory(examples/simplest) endif(WIN32) diff --git a/examples/simple/CMakeLists.txt b/examples/simple/CMakeLists.txt index 6072b7f..e891682 100644 --- a/examples/simple/CMakeLists.txt +++ b/examples/simple/CMakeLists.txt @@ -1,3 +1,3 @@ include_directories(${PROJECT_SOURCE_DIR}/include) -add_executable(simple-client-async simple.c) -target_link_libraries(simple-client-async discord-rpc) +add_executable(simple-client simple.c) +target_link_libraries(simple-client discord-rpc) diff --git a/examples/simpleSync/CMakeLists.txt b/examples/simpleSync/CMakeLists.txt deleted file mode 100644 index da023f5..0000000 --- a/examples/simpleSync/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -include_directories(${PROJECT_SOURCE_DIR}/include) -add_executable(simple-client-sync simpleSync.c) -target_link_libraries(simple-client-sync discord-rpc-sync) diff --git a/examples/simpleSync/simpleSync.c b/examples/simpleSync/simpleSync.c deleted file mode 100644 index 57619c6..0000000 --- a/examples/simpleSync/simpleSync.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - This is a simple example in C of using the rich presence API asyncronously. -*/ - -#define _CRT_SECURE_NO_WARNINGS /* thanks Microsoft */ - -#include -#include -#include -#include - -#include "discord-rpc.h" - -static const char* APPLICATION_ID = "12345678910"; -static int FrustrationLevel = 0; - -static void updateDiscordPresence() { - char buffer[256]; - DiscordRichPresence discordPresence; - memset(&discordPresence, 0, sizeof(discordPresence)); - discordPresence.state = "West of House"; - sprintf(buffer, "Frustration level: %d", FrustrationLevel); - discordPresence.details = buffer; - Discord_UpdatePresence(&discordPresence); -} - -static void handleDiscordReady() { - printf("\nDiscord: ready\n"); -} - -static void handleDiscordDisconnected(int errcode, const char* msg) { - printf("\nDiscord: disconnected\n"); -} - -static void handleDiscordWantsPresence() { - printf("\nDiscord: requests presence\n"); - updateDiscordPresence(); -} - -static int prompt(char* line, size_t size) { - int res; - char* nl; - printf("\n> "); - fflush(stdout); - res = fgets(line, size, stdin) ? 1 : 0; - line[size - 1] = 0; - nl = strchr(line, '\n'); - if (nl) { - *nl = 0; - } - return res; -} - -static void gameLoop() { - char line[512]; - char* space; - - printf("You are standing in an open field west of a white house.\n"); - while (prompt(line, sizeof(line))) { - if (time(NULL) & 1) { - printf("I don't understand that.\n"); - } else { - space = strchr(line, ' '); - if (space) { - *space = 0; - } - printf("I don't know the word \"%s\".\n", line); - } - - ++FrustrationLevel; - - updateDiscordPresence(); - Discord_Update(); - } -} - -int main() { - DiscordEventHandlers handlers; - memset(&handlers, 0, sizeof(handlers)); - handlers.ready = handleDiscordReady; - handlers.disconnected = handleDiscordDisconnected; - handlers.wantsPresence = handleDiscordWantsPresence; - Discord_Initialize(APPLICATION_ID, &handlers); - - gameLoop(); - - Discord_Shutdown(); - return 0; -} - diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6b581cc..888000e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,18 +1,15 @@ include_directories(${PROJECT_SOURCE_DIR}/include) -set(BASE_RPC_SRC ${PROJECT_SOURCE_DIR}/include/discord-rpc.h discord-rpc.cpp yolojson.h connection.h) +set(BASE_RPC_SRC ${PROJECT_SOURCE_DIR}/include/discord-rpc.h discord-rpc.cpp rpc_connection.h rpc_connection.cpp yolojson.h connection.h) if(WIN32) add_library(discord-rpc-simple STATIC ${PROJECT_SOURCE_DIR}/include/discord-rpc.h discord-rpc-simple.cpp) - add_library(discord-rpc-sync STATIC ${BASE_RPC_SRC} connection_win_sync.cpp) - target_include_directories(discord-rpc-sync PRIVATE ${RAPIDJSON}/include) - add_library(discord-rpc STATIC ${BASE_RPC_SRC} connection_win.cpp) - target_include_directories(discord-rpc PRIVATE ${RAPIDJSON}/include) endif(WIN32) if(UNIX) add_library(discord-rpc STATIC ${BASE_RPC_SRC} connection_unix.cpp) - target_include_directories(discord-rpc PRIVATE ${RAPIDJSON}/include) endif(UNIX) + +target_include_directories(discord-rpc PRIVATE ${RAPIDJSON}/include) \ No newline at end of file diff --git a/src/connection.h b/src/connection.h index f5b8cfb..6456b95 100644 --- a/src/connection.h +++ b/src/connection.h @@ -5,30 +5,11 @@ #include #include -enum class OPCODE : uint32_t { - HANDSHAKE = 0, - FRAME = 1, - CLOSE = 2, -}; - -struct RpcMessageFrame { - OPCODE opcode; - uint32_t length; - char message[64 * 1024 - 8]; -}; - -struct RpcConnection { - void (*onConnect)() = nullptr; - void (*onDisconnect)() = nullptr; - char appId[64]; - - static RpcConnection* Create(const char* applicationId); - static void Destroy(RpcConnection*&); - void Open(); - void Close(); - void Write(const void* data, size_t length); - RpcMessageFrame* Read(); - - RpcMessageFrame* GetNextFrame(); - void WriteFrame(RpcMessageFrame* frame); +struct BaseConnection { + static BaseConnection* Create(); + static void Destroy(BaseConnection*&); + bool Open(); + bool Close(); + bool Write(const void* data, size_t length); + bool Read(void* data, size_t& length); }; diff --git a/src/connection_win.cpp b/src/connection_win.cpp index 22060fb..afa4212 100644 --- a/src/connection_win.cpp +++ b/src/connection_win.cpp @@ -1,7 +1,6 @@ #include "connection.h" #include -#include "rapidjson/document.h" #define WIN32_LEAN_AND_MEAN #define NOMCX @@ -9,110 +8,75 @@ #define NOIME #include -#include "yolojson.h" - -const int RpcVersion = 1; -const int NumFrames = 3; - -struct WinRpcConnection : public RpcConnection { +struct BaseConnectionWin : public BaseConnection { HANDLE pipe{INVALID_HANDLE_VALUE}; - RpcMessageFrame frames[NumFrames]; - int nextFrame{0}; }; +static BaseConnectionWin Connection; static const wchar_t* PipeName = L"\\\\?\\pipe\\discord-ipc"; -/*static*/ RpcConnection* RpcConnection::Create(const char* applicationId) +/*static*/ BaseConnection* BaseConnection::Create() { - auto connection = new WinRpcConnection; - StringCopy(connection->appId, applicationId, sizeof(connection->appId)); - return connection; + return &Connection; } -/*static*/ void RpcConnection::Destroy(RpcConnection*& c) +/*static*/ void BaseConnection::Destroy(BaseConnection*& c) { - auto self = reinterpret_cast(c); - delete self; + auto self = reinterpret_cast(c); + self->Close(); c = nullptr; } -void RpcConnection::Open() +bool BaseConnection::Open() { - auto self = reinterpret_cast(this); + auto self = reinterpret_cast(this); for (;;) { self->pipe = ::CreateFileW(PipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); if (self->pipe != INVALID_HANDLE_VALUE) { - break; + return true; } if (GetLastError() != ERROR_PIPE_BUSY) { printf("Could not open pipe. Error: %d\n", GetLastError()); - return; + return false; } if (!WaitNamedPipeW(PipeName, 10000)) { printf("Could not open pipe: 10 second wait timed out.\n"); - return; + return false; } } - - RpcMessageFrame* frame = GetNextFrame(); - frame->opcode = OPCODE::HANDSHAKE; - char* msg = frame->message; - JsonWriteHandshakeObj(msg, RpcVersion, appId); - frame->length = msg - frame->message; - WriteFrame(frame); - - if (self->onConnect) { - self->onConnect(); - } } -void RpcConnection::Close() +bool BaseConnection::Close() { - auto self = reinterpret_cast(this); + auto self = reinterpret_cast(this); ::CloseHandle(self->pipe); self->pipe = INVALID_HANDLE_VALUE; - if (self->onDisconnect) { - self->onDisconnect(); - } + return true; } -void RpcConnection::Write(const void* data, size_t length) +bool BaseConnection::Write(const void* data, size_t length) { - auto self = reinterpret_cast(this); - const int retries = 3; - for (int i = 0; i < retries; ++i) { - if (self->pipe == INVALID_HANDLE_VALUE) { - self->Open(); - if (self->pipe == INVALID_HANDLE_VALUE) { - break; - } - } - BOOL success = ::WriteFile(self->pipe, data, length, nullptr, nullptr); - if (success) { - break; - } + auto self = reinterpret_cast(this); + BOOL success = ::WriteFile(self->pipe, data, length, nullptr, nullptr); + if (!success) { self->Close(); } + return success; } -RpcMessageFrame* RpcConnection::Read() +bool BaseConnection::Read(void* data, size_t length) { - // todo - return nullptr; + auto self = reinterpret_cast(this); + DWORD bytesAvailable = 0; + if (::PeekNamedPipe(self->pipe, nullptr, 0, nullptr, &bytesAvailable, nullptr)) { + if (bytesAvailable >= length) { + if (::ReadFile(self->pipe, data, length, nullptr, nullptr) == TRUE) { + return true; + } + } + } + return false; } -RpcMessageFrame* RpcConnection::GetNextFrame() -{ - auto self = reinterpret_cast(this); - auto result = &(self->frames[self->nextFrame]); - self->nextFrame = (self->nextFrame + 1) % NumFrames; - return result; -} - -void RpcConnection::WriteFrame(RpcMessageFrame* frame) -{ - auto self = reinterpret_cast(this); - self->Write(frame, 8 + frame->length); -} diff --git a/src/discord-rpc-simple.cpp b/src/discord-rpc-simple.cpp index fee3bd1..a6a0f69 100644 --- a/src/discord-rpc-simple.cpp +++ b/src/discord-rpc-simple.cpp @@ -2,8 +2,6 @@ #include -// todo: think about making per-platform versions of this whole file, or wrapping the platform specific parts -- win32 for first version - // I just want the basics #define WIN32_LEAN_AND_MEAN #define NOMCX diff --git a/src/discord-rpc.cpp b/src/discord-rpc.cpp index 9f8027f..9e09432 100644 --- a/src/discord-rpc.cpp +++ b/src/discord-rpc.cpp @@ -1,6 +1,6 @@ #include "discord-rpc.h" -#include "connection.h" +#include "rpc_connection.h" #include "yolojson.h" #include "rapidjson/document.h" @@ -25,7 +25,11 @@ extern "C" void Discord_Initialize(const char* applicationId, DiscordEventHandle MyConnection = RpcConnection::Create(applicationId); MyConnection->onConnect = []() { WasJustConnected = true; }; - MyConnection->onDisconnect = []() { WasJustDisconnected = true; }; + MyConnection->onDisconnect = [](int err, const char* message) { + LastErrorCode = err; + StringCopy(LastErrorMessage, message, sizeof(LastErrorMessage)); + WasJustDisconnected = true; + }; MyConnection->Open(); } diff --git a/src/rpc_connection.cpp b/src/rpc_connection.cpp new file mode 100644 index 0000000..df292c5 --- /dev/null +++ b/src/rpc_connection.cpp @@ -0,0 +1,16 @@ +#include "rpc_connection.h" + +RpcConnection Instance; + +/*static*/ RpcConnection* RpcConnection::Create(const char* applicationId) +{ + Instance.connection = BaseConnection::Create(); + StringCopy(Instance.appId, applicationId, sizeof(Instance.appId)); + return &Instance; +} + +/*static*/ void RpcConnection::Destroy(RpcConnection*& c) +{ + BaseConnection::Destroy(c->connection); +} + diff --git a/src/rpc_connection.h b/src/rpc_connection.h new file mode 100644 index 0000000..0013d4f --- /dev/null +++ b/src/rpc_connection.h @@ -0,0 +1,30 @@ +#pragma once + +#include "connection.h" + +struct RpcConnection { + enum class Opcode : uint32_t { + Handshake = 0, + Frame = 1, + Close = 2, + }; + + struct MessageFrame { + Opcode opcode; + uint32_t length; + char message[64 * 1024 - 8]; + }; + + BaseConnection* connection{nullptr}; + void (*onConnect)(){nullptr}; + void (*onDisconnect)(int errorCode, const char* message){nullptr}; + char appId[64]{}; + + static RpcConnection* Create(const char* applicationId); + static void Destroy(RpcConnection*&); + + void Open(); + void Close(); + void Write(const void* data, size_t length); + bool Read(void* data, size_t& length); +}; \ No newline at end of file