Browse Source

Communicate with Discord IPC to update activity status.

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
cb15bbeb1a
5 changed files with 214 additions and 0 deletions
  1. +3
    -0
      adapters/standalone.cpp
  2. +13
    -0
      include/discord.hpp
  3. +1
    -0
      include/settings.hpp
  4. +189
    -0
      src/discord.cpp
  5. +8
    -0
      src/settings.cpp

+ 3
- 0
adapters/standalone.cpp View File

@@ -21,6 +21,7 @@
#include <string.hpp>
#include <library.hpp>
#include <network.hpp>
#include <discord.hpp>

#include <osdialog.h>
#include <thread>
@@ -175,6 +176,7 @@ int main(int argc, char* argv[]) {
gamepad::init();
plugin::init();
library::init();
discord::init();
if (!settings::headless) {
ui::init();
windowInit();
@@ -251,6 +253,7 @@ int main(int argc, char* argv[]) {
windowDestroy();
ui::destroy();
}
discord::destroy();
library::destroy();
midi::destroy();
audio::destroy();


+ 13
- 0
include/discord.hpp View File

@@ -0,0 +1,13 @@
#pragma once
#include <common.hpp>

namespace rack {
namespace discord {


void init();
void destroy();


} // namespace discord
} // namespace rack

+ 1
- 0
include/settings.hpp View File

@@ -78,6 +78,7 @@ extern std::vector<NVGcolor> cableColors;
extern bool autoCheckUpdates;
extern bool showTipsOnLaunch;
extern int tipIndex;
extern bool discordUpdateActivity;
enum ModuleBrowserSort {
MODULE_BROWSER_SORT_UPDATED,
MODULE_BROWSER_SORT_LAST_USED,


+ 189
- 0
src/discord.cpp View File

@@ -0,0 +1,189 @@
#include <discord.hpp>
#include <system.hpp>
#include <random.hpp>
#include <settings.hpp>

#include <thread>
#include <mutex>
#include <condition_variable>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <jansson.h>


namespace rack {
namespace discord {


static const char* CLIENT_ID = "878351961274060861";

static bool running = false;
static std::thread thread;
static std::mutex mutex;
static std::condition_variable cv;


static int sendJson(int fd, int32_t opcode, json_t* j) {
// Encode payload
char* json = json_dumps(j, 0);
if (!json)
return 1;
DEFER({free(json);});
size_t len = strlen(json);

// Send header
int32_t header[2] = {opcode, int32_t(len)};
if (write(fd, header, sizeof(header)) != sizeof(header))
return 1;

// Send payload
if (write(fd, json, len) != ssize_t(len))
return 1;

return 0;
}


static json_t* receiveJson(int fd) {
// Receive header
int32_t header[2];
if (read(fd, header, sizeof(header)) != sizeof(header))
return NULL;

// Receive payload
size_t len = header[1];
char json[len];
if (read(fd, json, len) != ssize_t(len))
return NULL;
// DEBUG("Payload: %.*s", int(len), json);

// Parse payload
json_t* j = json_loadb(json, len, 0, NULL);
return j;
}


static void run() {
system::setThreadName("Discord IPC");
random::init();

// Open socket
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
assert(fd);
if (fd < 0) {
WARN("Could not open Discord socket");
return;
}
DEFER({close(fd);});

// Get socket path
const char* env = getenv("XDG_RUNTIME_DIR");
if (!env)
env = getenv("TMPDIR");
if (!env)
env = getenv("TMP");
if (!env)
env = getenv("TEMP");
if (!env)
env = "/tmp";
std::string path = std::string() + env + "/discord-ipc-0";

// Connect to socket
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path.c_str());
if (connect(fd, (struct sockaddr*) &addr, sizeof(addr))) {
// Fail silently since this just means Discord isn't open.
// WARN("Could not bind Discord socket");
return;
}

// Send handshake
json_t* handshakeJ = json_object();
json_object_set(handshakeJ, "v", json_integer(1));
json_object_set(handshakeJ, "client_id", json_string(CLIENT_ID));
DEFER({json_decref(handshakeJ);});
if (sendJson(fd, 0, handshakeJ)) {
WARN("Could not request Discord handshake");
return;
}

// Receive handshake response
json_t* handshakeResJ = receiveJson(fd);
if (!handshakeResJ) {
WARN("Could not receive Discord handshake response");
return;
}
DEFER({json_decref(handshakeResJ);});

// Send activity
json_t* payloadJ = json_object();
json_object_set(payloadJ, "cmd", json_string("SET_ACTIVITY"));
json_object_set(payloadJ, "nonce", json_string(std::to_string(random::u64()).c_str()));
{
json_t* argsJ = json_object();
json_object_set(argsJ, "pid", json_integer(getpid()));
{
json_t* activityJ = json_object();
{
json_t* timestampsJ = json_object();
json_object_set(timestampsJ, "start", json_integer(system::getUnixTime()));
json_object_set(activityJ, "timestamps", timestampsJ);
}
json_object_set(argsJ, "activity", activityJ);
}
json_object_set(payloadJ, "args", argsJ);
}
DEFER({json_decref(payloadJ);});
if (sendJson(fd, 1, payloadJ)) {
WARN("Could not set activity on Discord");
return;
}

// Receive activity response
json_t* payloadResJ = receiveJson(fd);
if (!payloadResJ) {
WARN("Could not receive Discord activity response");
return;
}
DEFER({json_decref(payloadResJ);});

// Wait for destroy()
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, []() {return !running;});

// Ask Discord to disconnect
// json_t* disconnectJ = json_object();
// DEFER({json_decref(disconnectJ);});
// if (sendJson(fd, 2, disconnectJ)) {
// WARN("Could not disconnect from Discord");
// return;
// }
}


void init() {
if (!settings::discordUpdateActivity)
return;
running = true;
thread = std::thread(run);
}


void destroy() {
{
std::lock_guard<std::mutex> lock(mutex);
running = false;
cv.notify_all();
}
if (thread.joinable())
thread.join();
}


} // namespace discord
} // namespace rack

+ 8
- 0
src/settings.cpp View File

@@ -61,6 +61,7 @@ std::vector<NVGcolor> cableColors = {
bool autoCheckUpdates = true;
bool showTipsOnLaunch = true;
int tipIndex = -1;
bool discordUpdateActivity = true;
ModuleBrowserSort moduleBrowserSort = MODULE_BROWSER_SORT_UPDATED;
float moduleBrowserZoom = -1.f;
std::map<std::string, std::set<std::string>> moduleWhitelist = {};
@@ -161,6 +162,9 @@ json_t* toJson() {

json_object_set_new(rootJ, "tipIndex", json_integer(tipIndex));

if (!discordUpdateActivity)
json_object_set_new(rootJ, "discordUpdateActivity", json_boolean(discordUpdateActivity));

json_object_set_new(rootJ, "moduleBrowserSort", json_integer((int) moduleBrowserSort));

json_object_set_new(rootJ, "moduleBrowserZoom", json_real(moduleBrowserZoom));
@@ -333,6 +337,10 @@ void fromJson(json_t* rootJ) {
if (tipIndexJ)
tipIndex = json_integer_value(tipIndexJ);

json_t* discordUpdateActivityJ = json_object_get(rootJ, "discordUpdateActivity");
if (discordUpdateActivityJ)
discordUpdateActivity = json_boolean_value(discordUpdateActivityJ);

json_t* moduleBrowserSortJ = json_object_get(rootJ, "moduleBrowserSort");
if (moduleBrowserSortJ)
moduleBrowserSort = (ModuleBrowserSort) json_integer_value(moduleBrowserSortJ);


Loading…
Cancel
Save