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

@@ -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

@@ -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;
@@ -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 ) {
@@ -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();
@@ -156,20 +167,18 @@ void DiscordRPCplugin::onRegisterListeners( UICodeEditor* editor, std::vector<Ui
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,8 +3,8 @@
#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 )
@@ -39,8 +39,8 @@ bool DiscordIPC::tryConnect() {
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;
@@ -74,8 +74,12 @@ bool DiscordIPC::tryConnect() {
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;
}
if ( !std::filesystem::exists( value ) ) {
continue;
}
validPaths.push_back( value ); validPaths.push_back( value );
} }
@@ -94,7 +98,9 @@ bool DiscordIPC::tryConnect() {
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 ) ) {
continue;
}
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 );
@@ -113,9 +119,11 @@ bool DiscordIPC::tryConnect() {
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 ),
sizeof( serverAddr ) ) == -1 ) {
close( mSocket ); close( mSocket );
return false; return false;
} }
@@ -132,10 +140,7 @@ bool DiscordIPC::tryConnect() {
} }
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 );
} }
@@ -143,10 +148,7 @@ void DiscordIPC::doHandshake() {
void DiscordIPC::clearActivity() { void DiscordIPC::clearActivity() {
json j = { json j = {
{ "cmd", "SET_ACTIVITY" }, { "cmd", "SET_ACTIVITY" },
{"args", { { "args", { { "pid", 0 }, { "activity", nullptr } } },
{"pid", 0},
{"activity", nullptr}
}},
{ "nonce", "-" } // TODO: Null nonce for dev purposes, change to UUIDV4 in finished product { "nonce", "-" } // TODO: Null nonce for dev purposes, change to UUIDV4 in finished product
}; };
sendPacket( DiscordIPCOpcodes::Frame, j ); sendPacket( DiscordIPCOpcodes::Frame, j );
@@ -204,21 +206,23 @@ void DiscordIPC::setActivity( DiscordIPCActivity a ) {
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;
@@ -256,12 +260,13 @@ void DiscordIPC::sendPacket(DiscordIPCOpcodes opcode, json j) {
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
@@ -302,22 +307,34 @@ void DiscordIPC::sendPacket(DiscordIPCOpcodes opcode, json j) {
} }
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;
}
if ( !mUIReady ) {
Log::debug( "dcIPC: Scheduled a reconnect" );
mIsReconnectScheduled = true;
return;
}
if ( mBackoffIndex < DISCORDIPC_BACKOFF_MAX ) {
mBackoffIndex++;
}
int delay = 5 + pow( 2, 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() {

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();
@@ -57,20 +52,22 @@ class DiscordIPC {
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