This commit is contained in:
Chris Marsh 2017-07-25 09:27:48 -07:00
parent 866e6d1104
commit 7a6172a300
10 changed files with 176 additions and 78 deletions

62
.clang-format Normal file
View file

@ -0,0 +1,62 @@
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: true
AlignEscapedNewlinesLeft: true
AlignOperands: false
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AlwaysBreakAfterDefinitionReturnType: false
AlwaysBreakTemplateDeclarations: true
AlwaysBreakBeforeMultilineStrings: false
BreakBeforeBraces: Stroustrup
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: true
BinPackParameters: false
BinPackArguments: false
ColumnLimit: 100
CommentPragmas: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach ]
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 9999999
PointerAlignment: Left
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: true
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Never
...

View file

@ -14,7 +14,8 @@
static const char* APPLICATION_ID = "338030514596216832"; static const char* APPLICATION_ID = "338030514596216832";
static int FrustrationLevel = 0; static int FrustrationLevel = 0;
static void updateDiscordPresence() { static void updateDiscordPresence()
{
char buffer[256]; char buffer[256];
DiscordRichPresence discordPresence; DiscordRichPresence discordPresence;
memset(&discordPresence, 0, sizeof(discordPresence)); memset(&discordPresence, 0, sizeof(discordPresence));
@ -24,24 +25,29 @@ static void updateDiscordPresence() {
Discord_UpdatePresence(&discordPresence); Discord_UpdatePresence(&discordPresence);
} }
static void handleDiscordReady() { static void handleDiscordReady()
{
printf("\nDiscord: ready\n"); printf("\nDiscord: ready\n");
} }
static void handleDiscordDisconnected(int errcode, const char* message) { static void handleDiscordDisconnected(int errcode, const char* message)
{
printf("\nDiscord: disconnected (%d: %s)\n", errcode, message); printf("\nDiscord: disconnected (%d: %s)\n", errcode, message);
} }
static void handleDiscordError(int errcode, const char* message) { static void handleDiscordError(int errcode, const char* message)
{
printf("\nDiscord: error (%d: %s)\n", errcode, message); printf("\nDiscord: error (%d: %s)\n", errcode, message);
} }
static void handleDiscordPresenceRequested() { static void handleDiscordPresenceRequested()
{
printf("\nDiscord: requests presence\n"); printf("\nDiscord: requests presence\n");
updateDiscordPresence(); updateDiscordPresence();
} }
static int prompt(char* line, size_t size) { static int prompt(char* line, size_t size)
{
int res; int res;
char* nl; char* nl;
printf("\n> "); printf("\n> ");
@ -55,7 +61,8 @@ static int prompt(char* line, size_t size) {
return res; return res;
} }
static void gameLoop() { static void gameLoop()
{
char line[512]; char line[512];
char* space; char* space;
@ -63,7 +70,8 @@ static void gameLoop() {
while (prompt(line, sizeof(line))) { while (prompt(line, sizeof(line))) {
if (time(NULL) & 1) { if (time(NULL) & 1) {
printf("I don't understand that.\n"); printf("I don't understand that.\n");
} else { }
else {
space = strchr(line, ' '); space = strchr(line, ' ');
if (space) { if (space) {
*space = 0; *space = 0;
@ -72,9 +80,9 @@ static void gameLoop() {
} }
++FrustrationLevel; ++FrustrationLevel;
updateDiscordPresence(); updateDiscordPresence();
#ifdef DISCORD_DISABLE_IO_THREAD #ifdef DISCORD_DISABLE_IO_THREAD
Discord_UpdateConnection(); Discord_UpdateConnection();
#endif #endif
@ -82,7 +90,8 @@ static void gameLoop() {
} }
} }
int main() { int main()
{
DiscordEventHandlers handlers; DiscordEventHandlers handlers;
memset(&handlers, 0, sizeof(handlers)); memset(&handlers, 0, sizeof(handlers));
handlers.ready = handleDiscordReady; handlers.ready = handleDiscordReady;
@ -92,8 +101,7 @@ int main() {
Discord_Initialize(APPLICATION_ID, &handlers); Discord_Initialize(APPLICATION_ID, &handlers);
gameLoop(); gameLoop();
Discord_Shutdown(); Discord_Shutdown();
return 0; return 0;
} }

View file

@ -3,7 +3,7 @@
//#define DISCORD_DISABLE_IO_THREAD //#define DISCORD_DISABLE_IO_THREAD
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -47,6 +47,6 @@ void Discord_UpdateConnection();
void Discord_UpdatePresence(const DiscordRichPresence* presence); void Discord_UpdatePresence(const DiscordRichPresence* presence);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif

View file

@ -4,8 +4,7 @@
#include <algorithm> #include <algorithm>
#include <random> #include <random>
struct Backoff struct Backoff {
{
int64_t minAmount; int64_t minAmount;
int64_t maxAmount; int64_t maxAmount;
int64_t current; int64_t current;
@ -13,16 +12,15 @@ struct Backoff
std::mt19937_64 randGenerator; std::mt19937_64 randGenerator;
std::uniform_real_distribution<> randDistribution; std::uniform_real_distribution<> randDistribution;
double rand01() { double rand01() { return randDistribution(randGenerator); }
return randDistribution(randGenerator);
}
Backoff(int64_t min, int64_t max) Backoff(int64_t min, int64_t max)
: minAmount(min) : minAmount(min)
, maxAmount(max) , maxAmount(max)
, current(min) , current(min)
, fails(0) , fails(0)
{} {
}
void reset() void reset()
{ {
@ -38,4 +36,3 @@ struct Backoff
return current; return current;
} }
}; };

View file

@ -16,7 +16,7 @@ struct BaseConnectionWin : public BaseConnection {
}; };
static BaseConnectionWin Connection; static BaseConnectionWin Connection;
//static const wchar_t* PipeName = L"\\\\?\\pipe\\discord-ipc"; // static const wchar_t* PipeName = L"\\\\?\\pipe\\discord-ipc";
static const wchar_t* PipeName = L"\\\\?\\pipe\\discord-ipc-0"; static const wchar_t* PipeName = L"\\\\?\\pipe\\discord-ipc-0";
/*static*/ BaseConnection* BaseConnection::Create() /*static*/ BaseConnection* BaseConnection::Create()
@ -35,7 +35,8 @@ bool BaseConnection::Open()
{ {
auto self = reinterpret_cast<BaseConnectionWin*>(this); auto self = reinterpret_cast<BaseConnectionWin*>(this);
for (;;) { for (;;) {
self->pipe = ::CreateFileW(PipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); self->pipe = ::CreateFileW(
PipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (self->pipe != INVALID_HANDLE_VALUE) { if (self->pipe != INVALID_HANDLE_VALUE) {
return true; return true;
} }
@ -77,4 +78,3 @@ bool BaseConnection::Read(void* data, size_t length)
} }
return false; return false;
} }

View file

@ -53,10 +53,12 @@ static std::thread IoThread;
static void UpdateReconnectTime() static void UpdateReconnectTime()
{ {
NextConnect = std::chrono::system_clock::now() + std::chrono::duration<int64_t, std::milli>{ReconnectTimeMs.nextDelay()}; NextConnect = std::chrono::system_clock::now() +
std::chrono::duration<int64_t, std::milli>{ReconnectTimeMs.nextDelay()};
} }
static QueuedMessage* SendQueueGetNextAddMessage() { static QueuedMessage* SendQueueGetNextAddMessage()
{
// if we are falling behind, bail // if we are falling behind, bail
if (SendQueuePendingSends.load() >= MessageQueueSize) { if (SendQueuePendingSends.load() >= MessageQueueSize) {
return nullptr; return nullptr;
@ -64,11 +66,13 @@ static QueuedMessage* SendQueueGetNextAddMessage() {
auto index = (SendQueueNextAdd++) % MessageQueueSize; auto index = (SendQueueNextAdd++) % MessageQueueSize;
return &SendQueue[index]; return &SendQueue[index];
} }
static QueuedMessage* SendQueueGetNextSendMessage() { static QueuedMessage* SendQueueGetNextSendMessage()
{
auto index = (SendQueueNextSend++) % MessageQueueSize; auto index = (SendQueueNextSend++) % MessageQueueSize;
return &SendQueue[index]; return &SendQueue[index];
} }
static void SendQueueCommitMessage() { static void SendQueueCommitMessage()
{
SendQueuePendingSends++; SendQueuePendingSends++;
} }
@ -145,7 +149,7 @@ extern "C" void Discord_UpdateConnection()
void DiscordRpcIo() void DiscordRpcIo()
{ {
const std::chrono::duration<int64_t, std::milli> maxWait{500LL}; const std::chrono::duration<int64_t, std::milli> maxWait{500LL};
while (KeepRunning.load()) { while (KeepRunning.load()) {
Discord_UpdateConnection(); Discord_UpdateConnection();
@ -166,7 +170,8 @@ bool RegisterForEvent(const char* evtName)
{ {
auto qmessage = SendQueueGetNextAddMessage(); auto qmessage = SendQueueGetNextAddMessage();
if (qmessage) { if (qmessage) {
qmessage->length = JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); qmessage->length =
JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
SendQueueCommitMessage(); SendQueueCommitMessage();
SignalIOActivity(); SignalIOActivity();
return true; return true;
@ -233,7 +238,8 @@ extern "C" void Discord_UpdatePresence(const DiscordRichPresence* presence)
{ {
auto qmessage = SendQueueGetNextAddMessage(); auto qmessage = SendQueueGetNextAddMessage();
if (qmessage) { if (qmessage) {
qmessage->length = JsonWriteRichPresenceObj(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, Pid, presence); qmessage->length = JsonWriteRichPresenceObj(
qmessage->buffer, sizeof(qmessage->buffer), Nonce++, Pid, presence);
SendQueueCommitMessage(); SendQueueCommitMessage();
SignalIOActivity(); SignalIOActivity();
} }

View file

@ -44,7 +44,8 @@ void RpcConnection::Open()
if (evt == message.MemberEnd() || !evt->value.IsString()) { if (evt == message.MemberEnd() || !evt->value.IsString()) {
return; return;
} }
if (!strcmp(cmd->value.GetString(), "DISPATCH") && !strcmp(evt->value.GetString(), "READY")) { if (!strcmp(cmd->value.GetString(), "DISPATCH") &&
!strcmp(evt->value.GetString(), "READY")) {
state = State::Connected; state = State::Connected;
if (onConnect) { if (onConnect) {
onConnect(); onConnect();
@ -54,7 +55,8 @@ void RpcConnection::Open()
} }
else { else {
sendFrame.opcode = Opcode::Handshake; sendFrame.opcode = Opcode::Handshake;
sendFrame.length = JsonWriteHandshakeObj(sendFrame.message, sizeof(sendFrame.message), RpcVersion, appId); sendFrame.length =
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; state = State::SentHandshake;
@ -110,8 +112,7 @@ bool RpcConnection::Read(JsonDocument& message)
} }
switch (readFrame.opcode) { switch (readFrame.opcode) {
case Opcode::Close: case Opcode::Close: {
{
message.ParseInsitu(readFrame.message); message.ParseInsitu(readFrame.message);
lastErrorCode = message["code"].GetInt(); lastErrorCode = message["code"].GetInt();
const auto& m = message["message"]; const auto& m = message["message"];

View file

@ -3,7 +3,8 @@
#include "connection.h" #include "connection.h"
#include "serialization.h" #include "serialization.h"
// I took this from the buffer size libuv uses for named pipes; I suspect ours would usually be much smaller. // I took this from the buffer size libuv uses for named pipes; I suspect ours would usually be much
// smaller.
constexpr size_t MaxRpcFrameSize = 64 * 1024; constexpr size_t MaxRpcFrameSize = 64 * 1024;
struct RpcConnection { struct RpcConnection {
@ -43,9 +44,7 @@ struct RpcConnection {
static RpcConnection* Create(const char* applicationId); static RpcConnection* Create(const char* applicationId);
static void Destroy(RpcConnection*&); static void Destroy(RpcConnection*&);
inline bool IsOpen() const { inline bool IsOpen() const { return state == State::Connected; }
return state == State::Connected;
}
void Open(); void Open();
void Close(); void Close();

View file

@ -5,13 +5,15 @@
MallocAllocator MallocAllocatorInst; MallocAllocator MallocAllocatorInst;
// it's ever so slightly faster to not have to strlen the key // it's ever so slightly faster to not have to strlen the key
template<typename T> template <typename T>
void WriteKey(JsonWriter& w, T& k) { void WriteKey(JsonWriter& w, T& k)
{
w.Key(k, sizeof(T) - 1); w.Key(k, sizeof(T) - 1);
} }
template<typename T> template <typename T>
void WriteOptionalString(JsonWriter& w, T& k, const char* value) { void WriteOptionalString(JsonWriter& w, T& k, const char* value)
{
if (value) { if (value) {
w.Key(k, sizeof(T) - 1); w.Key(k, sizeof(T) - 1);
w.String(value); w.String(value);
@ -45,7 +47,11 @@ void JsonWriteCommandEnd(JsonWriter& writer)
writer.EndObject(); // top level writer.EndObject(); // top level
} }
size_t JsonWriteRichPresenceObj(char* dest, size_t maxLen, int nonce, int pid, const DiscordRichPresence* presence) size_t JsonWriteRichPresenceObj(char* dest,
size_t maxLen,
int nonce,
int pid,
const DiscordRichPresence* presence)
{ {
DirectStringBuffer sb(dest, maxLen); DirectStringBuffer sb(dest, maxLen);
StackAllocator wa; StackAllocator wa;
@ -79,7 +85,8 @@ size_t JsonWriteRichPresenceObj(char* dest, size_t maxLen, int nonce, int pid, c
writer.EndObject(); writer.EndObject();
} }
if (presence->largeImageKey || presence->largeImageText || presence->smallImageKey || presence->smallImageText) { if (presence->largeImageKey || presence->largeImageText || presence->smallImageKey ||
presence->smallImageText) {
WriteKey(writer, "assets"); WriteKey(writer, "assets");
writer.StartObject(); writer.StartObject();
@ -156,13 +163,13 @@ size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const cha
writer.StartObject(); writer.StartObject();
JsonWriteNonce(writer, nonce); JsonWriteNonce(writer, nonce);
WriteKey(writer, "cmd"); WriteKey(writer, "cmd");
writer.String("SUBSCRIBE"); writer.String("SUBSCRIBE");
WriteKey(writer, "evt"); WriteKey(writer, "evt");
writer.String(evtName); writer.String(evtName);
writer.EndObject(); writer.EndObject();
return sb.GetSize(); return sb.GetSize();

View file

@ -8,8 +8,9 @@
#include "rapidjson/internal/itoa.h" #include "rapidjson/internal/itoa.h"
// if only there was a standard library function for this // if only there was a standard library function for this
template<size_t Len> template <size_t Len>
inline size_t StringCopy(char (&dest)[Len], const char* src) { inline size_t StringCopy(char (&dest)[Len], const char* src)
{
if (!dest || !src || !Len) { if (!dest || !src || !Len) {
return 0; return 0;
} }
@ -26,20 +27,30 @@ size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char*
// Commands // Commands
struct DiscordRichPresence; struct DiscordRichPresence;
size_t JsonWriteRichPresenceObj(char* dest, size_t maxLen, int nonce, int pid, const DiscordRichPresence* presence); size_t JsonWriteRichPresenceObj(char* dest,
size_t maxLen,
int nonce,
int pid,
const DiscordRichPresence* presence);
size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName); size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName);
// I want to use as few allocations as I can get away with, and to do that with RapidJson, you need to supply some of // I want to use as few allocations as I can get away with, and to do that with RapidJson, you need
// to supply some of
// your own allocators for stuff rather than use the defaults // your own allocators for stuff rather than use the defaults
class LinearAllocator { class LinearAllocator {
public: public:
char* buffer_; char* buffer_;
char* end_; char* end_;
LinearAllocator() { LinearAllocator()
{
assert(0); // needed for some default case in rapidjson, should not use assert(0); // needed for some default case in rapidjson, should not use
} }
LinearAllocator(char* buffer, size_t size) : buffer_(buffer), end_(buffer + size) {} LinearAllocator(char* buffer, size_t size)
: buffer_(buffer)
, end_(buffer + size)
{
}
static const bool kNeedFree = false; static const bool kNeedFree = false;
void* Malloc(size_t size) void* Malloc(size_t size)
{ {
@ -60,14 +71,17 @@ public:
assert(!originalPtr && !originalSize); assert(!originalPtr && !originalSize);
return Malloc(newSize); return Malloc(newSize);
} }
static void Free(void* ptr) { /* shrug */ } static void Free(void* ptr) { /* shrug */}
}; };
template<size_t Size> template <size_t Size>
class FixedLinearAllocator : public LinearAllocator { class FixedLinearAllocator : public LinearAllocator {
public: public:
char fixedBuffer_[Size]; char fixedBuffer_[Size];
FixedLinearAllocator() : LinearAllocator(fixedBuffer_, Size) {} FixedLinearAllocator()
: LinearAllocator(fixedBuffer_, Size)
{
}
static const bool kNeedFree = false; static const bool kNeedFree = false;
}; };
@ -80,10 +94,11 @@ public:
char* current_; char* current_;
DirectStringBuffer(char* buffer, size_t maxLen) DirectStringBuffer(char* buffer, size_t maxLen)
: buffer_(buffer) : buffer_(buffer)
, end_(buffer + maxLen) , end_(buffer + maxLen)
, current_(buffer) , current_(buffer)
{} {
}
void Put(char c) void Put(char c)
{ {
@ -92,10 +107,7 @@ public:
} }
} }
void Flush() {} void Flush() {}
size_t GetSize() const size_t GetSize() const { return current_ - buffer_; }
{
return current_ - buffer_;
}
}; };
using MallocAllocator = rapidjson::CrtAllocator; using MallocAllocator = rapidjson::CrtAllocator;
@ -104,19 +116,25 @@ using UTF8 = rapidjson::UTF8<char>;
// Writer appears to need about 16 bytes per nested object level (with 64bit size_t) // Writer appears to need about 16 bytes per nested object level (with 64bit size_t)
using StackAllocator = FixedLinearAllocator<2048>; using StackAllocator = FixedLinearAllocator<2048>;
constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t)); constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t));
using JsonWriter = rapidjson::Writer<DirectStringBuffer, UTF8, UTF8, StackAllocator, rapidjson::kWriteNoFlags>; using JsonWriter =
rapidjson::Writer<DirectStringBuffer, UTF8, UTF8, StackAllocator, rapidjson::kWriteNoFlags>;
using JsonDocumentBase = rapidjson::GenericDocument<UTF8, PoolAllocator, StackAllocator>; using JsonDocumentBase = rapidjson::GenericDocument<UTF8, PoolAllocator, StackAllocator>;
class JsonDocument : public JsonDocumentBase class JsonDocument : public JsonDocumentBase {
{
public: public:
static const int kDefaultChunkCapacity = 32 * 1024; static const int kDefaultChunkCapacity = 32 * 1024;
// json parser will use this buffer first, then allocate more if needed; I seriously doubt we send any messages that would use all of this, though. // json parser will use this buffer first, then allocate more if needed; I seriously doubt we
// send any messages that would use all of this, though.
char parseBuffer_[32 * 1024]; char parseBuffer_[32 * 1024];
MallocAllocator mallocAllocator_; MallocAllocator mallocAllocator_;
PoolAllocator poolAllocator_; PoolAllocator poolAllocator_;
StackAllocator stackAllocator_; StackAllocator stackAllocator_;
JsonDocument() : JsonDocumentBase(rapidjson::kObjectType, &poolAllocator_, sizeof(stackAllocator_.fixedBuffer_), &stackAllocator_) JsonDocument()
, poolAllocator_(parseBuffer_, sizeof(parseBuffer_), kDefaultChunkCapacity, &mallocAllocator_) : JsonDocumentBase(rapidjson::kObjectType,
, stackAllocator_() &poolAllocator_,
{} sizeof(stackAllocator_.fixedBuffer_),
&stackAllocator_)
, poolAllocator_(parseBuffer_, sizeof(parseBuffer_), kDefaultChunkCapacity, &mallocAllocator_)
, stackAllocator_()
{
}
}; };