Clang-format; Correctly add command discordrpc-reconnect; Check for doLanguageIcons config option

This commit is contained in:
Bytequill
2025-02-11 22:20:43 +01:00
parent fadb3b9879
commit 08e92db506
6 changed files with 551 additions and 527 deletions

View File

@@ -160,6 +160,8 @@ File path is: </string>
<string name="cut">Cut</string> <string name="cut">Cut</string>
<string name="dark">Dark</string> <string name="dark">Dark</string>
<string name="date">Date</string> <string name="date">Date</string>
<string name="dc_editing">Editing %s, a %s file</string>
<string name="dc_workspace">Working on %s</string>
<string name="debug_draw_boxes">Draw Boxes</string> <string name="debug_draw_boxes">Draw Boxes</string>
<string name="debug_draw_boxes_toggle">Debug Draw Boxes Toggle</string> <string name="debug_draw_boxes_toggle">Debug Draw Boxes Toggle</string>
<string name="debug_draw_debug_data">Debug Draw Debug Data</string> <string name="debug_draw_debug_data">Debug Draw Debug Data</string>

View File

@@ -1,5 +1,5 @@
{ {
"config" : { "config": {
"appID": "1335730393948749898", "appID": "1335730393948749898",
"doLanguageIcons": true, "doLanguageIcons": true,
"iconBindings": { "iconBindings": {
@@ -106,7 +106,5 @@
"zig": "https://github.com/vyfor/icons/raw/master/icons/onyx/zig.png" "zig": "https://github.com/vyfor/icons/raw/master/icons/onyx/zig.png"
} }
}, },
"keybindings" : { "keybindings": {}
}
} }

View File

@@ -1,7 +1,7 @@
#include "discordRPCplugin.hpp" #include "discordRPCplugin.hpp"
using json = nlohmann::json; using json = nlohmann::json;
#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined ( __EMSCRIPTEN_PTHREADS__ ) #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined( __EMSCRIPTEN_PTHREADS__ )
#define dcRPC_THREADED 1 #define dcRPC_THREADED 1
#else #else
#define dcRPC_THREADED 0 #define dcRPC_THREADED 0
@@ -9,11 +9,11 @@ using json = nlohmann::json;
namespace ecode { namespace ecode {
Plugin* DiscordRPCplugin::New( PluginManager* pluginManager) { Plugin* DiscordRPCplugin::New( PluginManager* pluginManager ) {
return eeNew( DiscordRPCplugin, ( pluginManager, false ) ); return eeNew( DiscordRPCplugin, ( pluginManager, false ) );
} }
Plugin* DiscordRPCplugin::NewSync( PluginManager* pluginManager) { Plugin* DiscordRPCplugin::NewSync( PluginManager* pluginManager ) {
return eeNew( DiscordRPCplugin, ( pluginManager, true ) ); return eeNew( DiscordRPCplugin, ( pluginManager, true ) );
} }
@@ -33,7 +33,6 @@ DiscordRPCplugin::DiscordRPCplugin( PluginManager* pluginManager, bool sync ) :
DiscordRPCplugin::~DiscordRPCplugin() { DiscordRPCplugin::~DiscordRPCplugin() {
waitUntilLoaded(); waitUntilLoaded();
mShuttingDown = true; mShuttingDown = true;
} }
void DiscordRPCplugin::load( PluginManager* pluginManager ) { void DiscordRPCplugin::load( PluginManager* pluginManager ) {
Clock clock; Clock clock;
@@ -50,7 +49,7 @@ void DiscordRPCplugin::load( PluginManager* pluginManager ) {
paths.emplace_back( path ); paths.emplace_back( path );
path = pluginManager->getPluginsPath() + "discordRPC.json"; path = pluginManager->getPluginsPath() + "discordRPC.json";
if ( FileSystem::fileExists( path ) || if ( FileSystem::fileExists( path ) ||
FileSystem::fileWrite(path, "{\n \"config\":{},\n \"keybindings\":{}\n}\n") ) { FileSystem::fileWrite( path, "{\n \"config\":{},\n \"keybindings\":{}\n}\n" ) ) {
mConfigPath = path; mConfigPath = path;
paths.emplace_back( path ); paths.emplace_back( path );
} }
@@ -81,7 +80,12 @@ void DiscordRPCplugin::load( PluginManager* pluginManager ) {
mIPC.mcClientID = "1335730393948749898"; mIPC.mcClientID = "1335730393948749898";
updateConfigFile = true; updateConfigFile = true;
} }
if ( config.contains( "doLanguageIcons" ) ) {
mcDoLangIcon = config.value( "doLanguageIcons", true );
} else {
mIPC.mcClientID = true;
updateConfigFile = true;
}
} }
if ( updateConfigFile ) { if ( updateConfigFile ) {
@@ -96,7 +100,7 @@ void DiscordRPCplugin::load( PluginManager* pluginManager ) {
DiscordIPCActivity* a = mIPC.getActivity(); DiscordIPCActivity* a = mIPC.getActivity();
a->largeImage = DISCORDRPC_DEFAULT_ICON; a->largeImage = DISCORDRPC_DEFAULT_ICON;
mIPC.setActivity(*a); mIPC.setActivity( *a );
mReady = true; mReady = true;
fireReadyCbs(); fireReadyCbs();
@@ -109,13 +113,13 @@ PluginRequestHandle DiscordRPCplugin::processMessage( const PluginMessage& msg )
std::string rpath = FileSystem::getRealPath( msg.asJSON()["folder"] ); std::string rpath = FileSystem::getRealPath( msg.asJSON()["folder"] );
FileSystem::dirAddSlashAtEnd( rpath ); FileSystem::dirAddSlashAtEnd( rpath );
mProjectName = FileSystem::fileNameFromPath( rpath ); mProjectName = FileSystem::fileNameFromPath( rpath );
Log::debug("Loaded new workspace: %s ; %s", rpath, mProjectName); Log::debug( "Loaded new workspace: %s ; %s", rpath, mProjectName );
} }
case PluginMessageType::UIReady: { case PluginMessageType::UIReady: {
mIPC.mUIReady = true; mIPC.mUIReady = true;
// Log::debug("dcPlugin: UI is ready!"); // Log::debug("dcPlugin: UI is ready!");
if (mIPC.mIsReconnectScheduled) { if ( mIPC.mIsReconnectScheduled ) {
Log::debug("Running scheduled reconnect"); Log::debug( "Running scheduled reconnect" );
mIPC.tryConnect(); mIPC.tryConnect();
} }
} }
@@ -126,10 +130,15 @@ PluginRequestHandle DiscordRPCplugin::processMessage( const PluginMessage& msg )
return PluginRequestHandle::empty(); return PluginRequestHandle::empty();
} }
void DiscordRPCplugin::onRegisterDocument( TextDocument* doc ){ void DiscordRPCplugin::onRegisterEditor( UICodeEditor* editor ) {
doc->setCommand( "discordrpc-reconnect", [this] { editor->addUnlockedCommands( { "discordrpc-reconnect" } );
mIPC.reconnect(); editor->getDocument().setCommand( "discordrpc-reconnect", [this] { mIPC.reconnect(); } );
} );
PluginBase::onRegisterEditor( editor );
}
void DiscordRPCplugin::onUnregisterEditor( UICodeEditor* editor ) {
editor->removeUnlockedCommands( { "discordrpc-reconnect" } );
} }
void DiscordRPCplugin::onRegisterListeners( UICodeEditor* editor, std::vector<Uint32>& listeners ) { void DiscordRPCplugin::onRegisterListeners( UICodeEditor* editor, std::vector<Uint32>& listeners ) {
@@ -137,7 +146,9 @@ void DiscordRPCplugin::onRegisterListeners( UICodeEditor* editor, std::vector<Ui
// `this` in the scope of the lambda is the parent `DiscordRPCplugin` // `this` in the scope of the lambda is the parent `DiscordRPCplugin`
auto& doc = editor->getDocument(); auto& doc = editor->getDocument();
if (!doc.hasFilepath()) { return; } if ( !doc.hasFilepath() ) {
return;
}
auto filename = doc.getFilename(); auto filename = doc.getFilename();
@@ -149,27 +160,25 @@ void DiscordRPCplugin::onRegisterListeners( UICodeEditor* editor, std::vector<Ui
DiscordIPCActivity* a = this->mIPC.getActivity(); DiscordIPCActivity* a = this->mIPC.getActivity();
if (!mProjectName.empty()) if ( !mProjectName.empty() )
a->details = String::format(i18n( "dc_workspace", "Working on %s" ).toUtf8(), a->details = String::format( i18n( "dc_workspace", "Working on %s" ).toUtf8(),
mProjectName); mProjectName );
a->state = String::format(i18n( "dc_editing", "Editing %s, a %s file" ).toUtf8(), a->state = String::format( i18n( "dc_editing", "Editing %s, a %s file" ).toUtf8(),
filename, doc.getSyntaxDefinition().getLanguageName() ); filename, doc.getSyntaxDefinition().getLanguageName() );
a->start = time( nullptr ); // Time spent in this specific file a->start = time( nullptr ); // Time spent in this specific file
// TODO: Implement github/gitlab remote button (integrate with git plugin)
// a->buttons[0].label = "Repository";
// a->buttons[0].url = "https://github.com/name/repo";
std::string name = doc.getSyntaxDefinition().getLSPName(); std::string name = doc.getSyntaxDefinition().getLSPName();
if (!name.empty()) { if ( !name.empty() && mcDoLangIcon ) {
a->largeImage = mcLangBindings.value(name, DISCORDRPC_DEFAULT_ICON); a->largeImage = mcLangBindings.value( name, DISCORDRPC_DEFAULT_ICON );
} }
this->mIPC.setActivity( *a ); this->mIPC.setActivity( *a );
} }
} ) ); } ) );
} }
} // namespace ecode } // namespace ecode

View File

@@ -4,10 +4,10 @@
#include "../plugin.hpp" #include "../plugin.hpp"
#include "../pluginmanager.hpp" #include "../pluginmanager.hpp"
#include <eepp/system/threadpool.hpp>
#include <eepp/system/mutex.hpp>
#include <eepp/system/filesystem.hpp> #include <eepp/system/filesystem.hpp>
#include <eepp/system/mutex.hpp>
#include <eepp/system/scopedop.hpp> #include <eepp/system/scopedop.hpp>
#include <eepp/system/threadpool.hpp>
#include "sdk/ipc.hpp" #include "sdk/ipc.hpp"
@@ -18,15 +18,15 @@ using namespace EE::System;
using namespace EE::UI; using namespace EE::UI;
using namespace EE::UI::Doc; using namespace EE::UI::Doc;
#define DISCORDRPC_DEFAULT_ICON "https://github.com/SpartanJ/eepp/blob/develop/bin/assets/icon/ecode.png?raw=true" #define DISCORDRPC_DEFAULT_ICON \
"https://github.com/SpartanJ/eepp/blob/develop/bin/assets/icon/ecode.png?raw=true"
namespace ecode { namespace ecode {
class DiscordRPCplugin : public PluginBase { class DiscordRPCplugin : public PluginBase {
public: public:
static PluginDefinition Definition() { static PluginDefinition Definition() {
return { return { "discrdrpc",
"discrdrpc",
"Discord Rich Presence", "Discord Rich Presence",
"Show your friends what you are up to through the discord Rich Presence system", "Show your friends what you are up to through the discord Rich Presence system",
DiscordRPCplugin::New, DiscordRPCplugin::New,
@@ -51,19 +51,20 @@ class DiscordRPCplugin : public PluginBase {
std::string mLastFile; std::string mLastFile;
std::string mProjectName; std::string mProjectName;
nlohmann::json mcLangBindings; nlohmann::json mcLangBindings;
bool mcDoLangIcon;
void load ( PluginManager* pluginManager ); void load( PluginManager* pluginManager );
PluginRequestHandle processMessage( const PluginMessage& msg ); PluginRequestHandle processMessage( const PluginMessage& msg );
virtual void onRegisterListeners(UICodeEditor* editor, std::vector<Uint32>& listeners ) override; virtual void onRegisterListeners( UICodeEditor* editor,
virtual void onRegisterDocument( TextDocument* doc ) override; std::vector<Uint32>& listeners ) override;
virtual void onRegisterEditor( UICodeEditor* editor ) override;
virtual void onUnregisterEditor( UICodeEditor* editor ) override;
DiscordRPCplugin( PluginManager* pluginManager, bool sync ); DiscordRPCplugin( PluginManager* pluginManager, bool sync );
}; };
} // namespace ecode } // namespace ecode
#endif // ECODE_DISCORDRPCPLUGIN_HPP #endif // ECODE_DISCORDRPCPLUGIN_HPP

View File

@@ -3,19 +3,19 @@
#include <filesystem> #include <filesystem>
#include <vector> #include <vector>
#include <eepp/system/log.hpp>
#include <eepp/scene/scenemanager.hpp> #include <eepp/scene/scenemanager.hpp>
#include <eepp/system/log.hpp>
#include <eepp/ui/uiscenenode.hpp> #include <eepp/ui/uiscenenode.hpp>
#if defined( EE_PLATFORM_POSIX ) #if defined( EE_PLATFORM_POSIX )
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#elif EE_PLATFORM == EE_PLATFORM_WIN #elif EE_PLATFORM == EE_PLATFORM_WIN
#ifndef WIN32LEAN_AND_MEAN #ifndef WIN32LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
#include <windows.h> #include <windows.h>
#endif #endif
using namespace EE::System; using namespace EE::System;
@@ -27,20 +27,20 @@ DiscordIPC::DiscordIPC() {
} }
bool DiscordIPC::tryConnect() { bool DiscordIPC::tryConnect() {
#if EE_PLATFORM == EE_PLATFORM_WIN #if EE_PLATFORM == EE_PLATFORM_WIN
std::string basePath = "\\\\.\\pipe\\"; std::string basePath = "\\\\.\\pipe\\";
for (int i = 0; i < 10; ++i) { for ( int i = 0; i < 10; ++i ) {
std::string ipcPath = basePath + "discord-ipc-" + std::to_string(i); std::string ipcPath = basePath + "discord-ipc-" + std::to_string( i );
// Check if exists // Check if exists
DWORD attributes = GetFileAttributes(ipcPath.c_str()); DWORD attributes = GetFileAttributes( ipcPath.c_str() );
if (attributes != INVALID_FILE_ATTRIBUTES) { if ( attributes != INVALID_FILE_ATTRIBUTES ) {
Log::debug("dcIPC: IPC path found! - %s", ipcPath); Log::debug( "dcIPC: IPC path found! - %s", ipcPath );
mIpcPath = ipcPath; mIpcPath = ipcPath;
mSocket = CreateFile(mIpcPath.c_str(), GENERIC_READ | GENERIC_WRITE, mSocket = CreateFile( mIpcPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr,
0, nullptr, OPEN_EXISTING, 0, nullptr); OPEN_EXISTING, 0, nullptr );
doHandshake(); doHandshake();
return true; return true;
@@ -50,7 +50,7 @@ bool DiscordIPC::tryConnect() {
reconnect(); reconnect();
return false; return false;
#elif defined(EE_PLATFORM_POSIX) #elif defined( EE_PLATFORM_POSIX )
// Socket path can be in any of the following directories: // Socket path can be in any of the following directories:
// * `XDG_RUNTIME_DIR` // * `XDG_RUNTIME_DIR`
// * `TMPDIR` // * `TMPDIR`
@@ -65,58 +65,66 @@ bool DiscordIPC::tryConnect() {
// //
// Followed by: // Followed by:
// * `/discord-ipc-{i}` - where `i` is a number from 0 to 9 // * `/discord-ipc-{i}` - where `i` is a number from 0 to 9
const std::string env[] = {"XDG_RUNTIME_DIR", "TMPDIR", "TMP", "TEMP"}; const std::string env[] = { "XDG_RUNTIME_DIR", "TMPDIR", "TMP", "TEMP" };
const std::vector<std::string> additionalPaths = { const std::vector<std::string> additionalPaths = {
"/app/com.discordapp.Discord", "/app/com.discordapp.Discord",
"/.flatpak/dev.vencord.Vesktop/xdg-run", "/.flatpak/dev.vencord.Vesktop/xdg-run",
"/snap.discord", "/snap.discord",
}; };
std::vector<std::string> validPaths; std::vector<std::string> validPaths;
for ( const auto& eVar : env ){ for ( const auto& eVar : env ) {
const char* value = std::getenv(eVar.c_str()); const char* value = std::getenv( eVar.c_str() );
if (!value) { continue; } if ( !value ) {
if (!std::filesystem::exists(value)) { continue; } continue;
validPaths.push_back(value); }
if ( !std::filesystem::exists( value ) ) {
continue;
}
validPaths.push_back( value );
} }
validPaths.push_back("/tmp"); // Hard coded fallback validPaths.push_back( "/tmp" ); // Hard coded fallback
std::vector<std::string> checkPaths; std::vector<std::string> checkPaths;
for ( const auto& basePath : validPaths ) { for ( const auto& basePath : validPaths ) {
for (const auto& additionalPath : additionalPaths) { for ( const auto& additionalPath : additionalPaths ) {
std::string fullPath = basePath + additionalPath; std::string fullPath = basePath + additionalPath;
if (std::filesystem::exists(fullPath)) { if ( std::filesystem::exists( fullPath ) ) {
checkPaths.push_back(fullPath); checkPaths.push_back( fullPath );
} }
} }
} }
checkPaths.insert(checkPaths.end(), validPaths.begin(), validPaths.end()); checkPaths.insert( checkPaths.end(), validPaths.begin(), validPaths.end() );
for (const auto& basePath : checkPaths) { for ( const auto& basePath : checkPaths ) {
if (!std::filesystem::exists(basePath)) { continue; } if ( !std::filesystem::exists( basePath ) ) {
for (int i = 0; i < 10; ++i) { continue;
std::string ipcPath = basePath + "/discord-ipc-" + std::to_string(i); }
for ( int i = 0; i < 10; ++i ) {
std::string ipcPath = basePath + "/discord-ipc-" + std::to_string( i );
if (std::filesystem::exists(ipcPath)) { if ( std::filesystem::exists( ipcPath ) ) {
Log::debug("dcIPC: IPC path found! - %s", ipcPath); Log::debug( "dcIPC: IPC path found! - %s", ipcPath );
mIpcPath = ipcPath; mIpcPath = ipcPath;
mSocket = socket(AF_UNIX, SOCK_STREAM, 0); mSocket = socket( AF_UNIX, SOCK_STREAM, 0 );
if (mSocket == -1) { if ( mSocket == -1 ) {
Log::error("dcIPC: Discord IPC socket cold not be opened: %s", mIpcPath); Log::error( "dcIPC: Discord IPC socket cold not be opened: %s", mIpcPath );
mIpcPath = ""; mIpcPath = "";
continue; continue;
} }
sockaddr_un serverAddr; sockaddr_un serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr)); memset( &serverAddr, 0, sizeof( serverAddr ) );
serverAddr.sun_family = AF_UNIX; serverAddr.sun_family = AF_UNIX;
mIpcPath.copy(serverAddr.sun_path, sizeof(serverAddr.sun_path) - 1); mIpcPath.copy( serverAddr.sun_path, sizeof( serverAddr.sun_path ) - 1 );
serverAddr.sun_path[sizeof(serverAddr.sun_path) - 1] = '\0'; // Ensure null termination serverAddr.sun_path[sizeof( serverAddr.sun_path ) - 1] =
'\0'; // Ensure null termination
if (connect(mSocket, reinterpret_cast<struct sockaddr*>(&serverAddr), sizeof(serverAddr)) == -1) { if ( connect( mSocket, reinterpret_cast<struct sockaddr*>( &serverAddr ),
close(mSocket); sizeof( serverAddr ) ) == -1 ) {
close( mSocket );
return false; return false;
} }
@@ -127,98 +135,94 @@ bool DiscordIPC::tryConnect() {
reconnect(); reconnect();
return false; return false;
} }
#endif #endif
return false; // Discord not supported by other OS (if it is, TBA) return false; // Discord not supported by other OS (if it is, TBA)
} }
void DiscordIPC::doHandshake() { void DiscordIPC::doHandshake() {
json j = { json j = { { "v", 1 }, { "client_id", mcClientID } };
{"v", 1},
{"client_id", mcClientID}
};
sendPacket(DiscordIPCOpcodes::Handshake, j); sendPacket( DiscordIPCOpcodes::Handshake, j );
} }
void DiscordIPC::clearActivity() { void DiscordIPC::clearActivity() {
json j = { json j = {
{"cmd", "SET_ACTIVITY"}, { "cmd", "SET_ACTIVITY" },
{"args", { { "args", { { "pid", 0 }, { "activity", nullptr } } },
{"pid", 0}, { "nonce", "-" } // TODO: Null nonce for dev purposes, change to UUIDV4 in finished product
{"activity", nullptr}
}},
{"nonce", "-"} // TODO: Null nonce for dev purposes, change to UUIDV4 in finished product
}; };
sendPacket(DiscordIPCOpcodes::Frame, j); sendPacket( DiscordIPCOpcodes::Frame, j );
} }
void DiscordIPC::setActivity( DiscordIPCActivity a ) { void DiscordIPC::setActivity( DiscordIPCActivity a ) {
json aj = { json aj = {
{"type", static_cast<int>(a.type)}, { "type", static_cast<int>( a.type ) },
{"instance", true}, { "instance", true },
}; };
if (!a.state.empty()) if ( !a.state.empty() )
aj["state"] = a.state; aj["state"] = a.state;
if (!a.details.empty()) if ( !a.details.empty() )
aj["details"] = a.details; aj["details"] = a.details;
json as; json as;
if (!a.largeImage.empty()) { if ( !a.largeImage.empty() ) {
as["large_image"] = a.largeImage; as["large_image"] = a.largeImage;
} }
if (!a.largeText.empty()) { if ( !a.largeText.empty() ) {
as["large_text"] = a.largeText; as["large_text"] = a.largeText;
} }
if (!a.smallImage.empty()) { if ( !a.smallImage.empty() ) {
as["small_image"] = a.smallImage; as["small_image"] = a.smallImage;
} }
if (!a.smallText.empty()) { if ( !a.smallText.empty() ) {
as["small_text"] = a.smallText; as["small_text"] = a.smallText;
} }
if (!as.empty()) { if ( !as.empty() ) {
aj["assets"] = as; aj["assets"] = as;
} }
json t; json t;
if (a.start != 0) { if ( a.start != 0 ) {
t["start"] = a.start; t["start"] = a.start;
} }
if (a.end != 0) { if ( a.end != 0 ) {
t["end"] = a.end; t["end"] = a.end;
} }
if (!t.empty()) { if ( !t.empty() ) {
aj["timestamps"] = t; aj["timestamps"] = t;
} }
json b; json b;
if (!a.buttons[0].url.empty()){ if ( !a.buttons[0].url.empty() ) {
b[0]["label"] = a.buttons[0].label; b[0]["label"] = a.buttons[0].label;
b[0]["url"] = a.buttons[0].url; b[0]["url"] = a.buttons[0].url;
} }
if (!a.buttons[1].url.empty()){ if ( !a.buttons[1].url.empty() ) {
b[1]["label"] = a.buttons[1].label; b[1]["label"] = a.buttons[1].label;
b[1]["url"] = a.buttons[1].url; b[1]["url"] = a.buttons[1].url;
} }
if (!b.empty()) { if ( !b.empty() ) {
aj["buttons"] = b; aj["buttons"] = b;
} }
json j{ json j{ { "cmd", "SET_ACTIVITY" },
{"cmd", "SET_ACTIVITY"}, { "args",
{"args", { {
{"pid", mPID}, { "pid", mPID },
{"activity", aj}, { "activity", aj },
}}, } },
{"nonce", "-"} { "nonce", "-" } };
};
mActivity = a; mActivity = a;
sendPacket(DiscordIPCOpcodes::Frame, j); sendPacket( DiscordIPCOpcodes::Frame, j );
} }
void DiscordIPC::sendPacket(DiscordIPCOpcodes opcode, json j) { void DiscordIPC::sendPacket( DiscordIPCOpcodes opcode, json j ) {
if (!std::filesystem::exists(mIpcPath)) { reconnect(); return; } if ( !std::filesystem::exists( mIpcPath ) ) {
reconnect();
return;
}
const std::string packet = j.dump(); const std::string packet = j.dump();
std::vector<uint8_t> data; std::vector<uint8_t> data;
@@ -230,100 +234,113 @@ void DiscordIPC::sendPacket(DiscordIPCOpcodes opcode, json j) {
} bytes; } bytes;
bytes.value = opcode; bytes.value = opcode;
for (int i = 0; i <= 3; ++i) { for ( int i = 0; i <= 3; ++i ) {
data.push_back(bytes.bytes[i]); data.push_back( bytes.bytes[i] );
} }
bytes.value = packet.length(); bytes.value = packet.length();
for (int i = 0; i <= 3; ++i) { for ( int i = 0; i <= 3; ++i ) {
data.push_back(bytes.bytes[i]); data.push_back( bytes.bytes[i] );
} }
for (char c : packet) { for ( char c : packet ) {
data.push_back(static_cast<uint8_t>(c)); data.push_back( static_cast<uint8_t>( c ) );
} }
// Log::debug("Packet is: %s (%u)", j.dump(4), data.size()); // Log::debug("Packet is: %s (%u)", j.dump(4), data.size());
// std::stringstream ss; // std::stringstream ss;
// for (uint8_t byte : data) { // for (uint8_t byte : data) {
// ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byte) << " "; // ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byte) << " ";
// } // }
// Log::debug(ss.str()); // Log::debug(ss.str());
#if defined( EE_PLATFORM_POSIX ) #if defined( EE_PLATFORM_POSIX )
ssize_t bytesSent = send(mSocket, data.data(), data.size(), 0); ssize_t bytesSent = send( mSocket, data.data(), data.size(), 0 );
if (bytesSent != data.size()) { if ( bytesSent != data.size() ) {
Log::error("dcIPC: Failed to send all data to Unix socket: %zu bytes sent, %zu bytes expected", bytesSent, data.size()); Log::error(
"dcIPC: Failed to send all data to Unix socket: %zu bytes sent, %zu bytes expected",
bytesSent, data.size() );
reconnect(); reconnect();
return; return;
} }
struct timeval tv; struct timeval tv;
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 500000; // 0.5 seconds in microseconds tv.tv_usec = 500000; // 0.5 seconds in microseconds
setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); setsockopt( mSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof( tv ) );
char buffer[1024]; char buffer[1024];
ssize_t bytesRead = recv(mSocket, buffer, sizeof(buffer), 0); ssize_t bytesRead = recv( mSocket, buffer, sizeof( buffer ), 0 );
// Log::debug("dcIPC: RECV: %s", buffer); // Log::debug("dcIPC: RECV: %s", buffer);
// TODO: Implement nonce checking? (does it even really matter?) // TODO: Implement nonce checking? (does it even really matter?)
//return bytesRead; // return bytesRead;
#elif EE_PLATFORM == EE_PLATFORM_WIN #elif EE_PLATFORM == EE_PLATFORM_WIN
DWORD bytesSent; DWORD bytesSent;
if ( !WriteFile(mSocket, data.data(), data.size(), &bytesSent, nullptr) ) { if ( !WriteFile( mSocket, data.data(), data.size(), &bytesSent, nullptr ) ) {
Log::error("dcIPC: Error writing to pipe!!"); Log::error( "dcIPC: Error writing to pipe!!" );
reconnect(); reconnect();
return; return;
} else if (bytesSent != data.size()) { } else if ( bytesSent != data.size() ) {
Log::error("dcIPC: Incorrect ammount of data written: %zu bytes sent, %zu bytes expected", Log::error( "dcIPC: Incorrect ammount of data written: %zu bytes sent, %zu bytes expected",
bytesSent, data.size()); bytesSent, data.size() );
reconnect(); reconnect();
return; return;
} }
DWORD bytesRead; DWORD bytesRead;
char buffer[1024]; char buffer[1024];
if ( !ReadFile(mSocket, buffer, 1024, &bytesRead, nullptr ) ) { if ( !ReadFile( mSocket, buffer, 1024, &bytesRead, nullptr ) ) {
Log::error("dcIPC: Error reading pipe!!"); Log::error( "dcIPC: Error reading pipe!!" );
reconnect(); reconnect();
return; return;
} }
// Log::debug("dcIPC: RECV: %s", buffer); // Log::debug("dcIPC: RECV: %s", buffer);
#endif #endif
} }
void DiscordIPC::reconnect() { void DiscordIPC::reconnect() {
if (mReconnectLock) {Log::warning("dcIPC: Tried to call reconnect while locked"); return;} if ( mReconnectLock ) {
if (!mUIReady) { Log::debug("dcIPC: Scheduled a reconnect"); mIsReconnectScheduled = true; return; } Log::warning( "dcIPC: Tried to call reconnect while locked" );
if (mBackoffIndex < DISCORDIPC_BACKOFF_MAX) { mBackoffIndex++; } return;
int delay = 5 + pow(2, mBackoffIndex); }
if ( !mUIReady ) {
Log::debug( "dcIPC: Scheduled a reconnect" );
mIsReconnectScheduled = true;
return;
}
if ( mBackoffIndex < DISCORDIPC_BACKOFF_MAX ) {
mBackoffIndex++;
}
int delay = 5 + pow( 2, mBackoffIndex );
mReconnectLock = true; mReconnectLock = true;
Log::warning("dcIPC: Waiting for reconnect delay of %us (%u/%u)", delay, mBackoffIndex, DISCORDIPC_BACKOFF_MAX); Log::warning( "dcIPC: Waiting for reconnect delay of %us (%u/%u)", delay, mBackoffIndex,
EE::Scene::SceneManager::instance()->getUISceneNode() DISCORDIPC_BACKOFF_MAX );
->setTimeout( [this] { EE::Scene::SceneManager::instance()->getUISceneNode()->setTimeout(
EE::Scene::SceneManager::instance()->getUISceneNode() [this] {
->getThreadPool()->run( [this]{ EE::Scene::SceneManager::instance()->getUISceneNode()->getThreadPool()->run( [this] {
Log::info("dcIPC: Reconnecting..."); Log::info( "dcIPC: Reconnecting..." );
mReconnectLock = false; mReconnectLock = false;
if(tryConnect()){ mBackoffIndex = 0; } if ( tryConnect() ) {
}); mBackoffIndex = 0;
}, Seconds(delay)); }
} );
},
Seconds( delay ) );
} }
DiscordIPC::~DiscordIPC() { DiscordIPC::~DiscordIPC() {
#if defined( EE_PLATFORM_POSIX ) #if defined( EE_PLATFORM_POSIX )
close(mSocket); close( mSocket );
#elif EE_PLATFORM == EE_PLATFORM_WIN #elif EE_PLATFORM == EE_PLATFORM_WIN
CloseHandle(mSocket); CloseHandle( mSocket );
#endif #endif
} }

View File

@@ -30,20 +30,15 @@ struct DiscordIPCActivity {
std::string smallImage; std::string smallImage;
std::string smallText; std::string smallText;
// IMPORTANT: For some reason, you do not see the buttons of your own account on the discord
// client (intended discord behavior)
DiscordIPCActivityButton buttons[2]; DiscordIPCActivityButton buttons[2];
}; };
enum DiscordIPCOpcodes { enum DiscordIPCOpcodes { Handshake = 0, Frame, Close, Ping, Pong };
Handshake = 0,
Frame,
Close,
Ping,
Pong
};
class DiscordIPC { class DiscordIPC {
public: public:
virtual ~DiscordIPC(); virtual ~DiscordIPC();
DiscordIPC(); DiscordIPC();
@@ -53,29 +48,31 @@ class DiscordIPC {
void reconnect(); void reconnect();
void setActivity( DiscordIPCActivity a ); void setActivity( DiscordIPCActivity a );
DiscordIPCActivity *getActivity() { return &mActivity; } DiscordIPCActivity* getActivity() { return &mActivity; }
void clearActivity(); void clearActivity();
bool mUIReady; bool mUIReady;
bool mIsReconnectScheduled = false; // If we fail to load bofore UI initialises we call reconnect after init bool mIsReconnectScheduled =
false; // If we fail to load bofore UI initialises we call reconnect after init
//Configurables // Configurables
std::string mcClientID; std::string mcClientID;
protected: protected:
std::string mIpcPath; std::string mIpcPath;
int mPID; int mPID;
int mBackoffIndex; int mBackoffIndex;
int mReconnectLock = false; // Not quite a mutex because I want to lock any attempts if one is already waiting int mReconnectLock =
false; // Not quite a mutex because I want to lock any attempts if one is already waiting
DiscordIPCActivity mActivity; DiscordIPCActivity mActivity;
#if defined( EE_PLATFORM_POSIX )
#if defined( EE_PLATFORM_POSIX )
int mSocket; int mSocket;
#elif EE_PLATFORM == EE_PLATFORM_WIN #elif EE_PLATFORM == EE_PLATFORM_WIN
void* mSocket; void* mSocket;
#endif #endif
void doHandshake(); void doHandshake();