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,112 +1,110 @@
{ {
"config" : { "config": {
"appID": "1335730393948749898", "appID": "1335730393948749898",
"doLanguageIcons": true, "doLanguageIcons": true,
"iconBindings": { "iconBindings": {
".htaccess": "https://github.com/vyfor/icons/raw/master/icons/onyx/gear.png", ".htaccess": "https://github.com/vyfor/icons/raw/master/icons/onyx/gear.png",
".ignore file": "https://github.com/vyfor/icons/raw/master/icons/onyx/git.png", ".ignore file": "https://github.com/vyfor/icons/raw/master/icons/onyx/git.png",
"[x]it!": "https://github.com/vyfor/icons/raw/master/icons/onyx/notes.png", "[x]it!": "https://github.com/vyfor/icons/raw/master/icons/onyx/notes.png",
"ada": "https://github.com/vyfor/icons/raw/master/icons/pastel/ada.png", "ada": "https://github.com/vyfor/icons/raw/master/icons/pastel/ada.png",
"adept": "https://raw.github.com/AdeptLanguage/Adept/master/.github/README_logo.png", "adept": "https://raw.github.com/AdeptLanguage/Adept/master/.github/README_logo.png",
"angelscript": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png", "angelscript": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png",
"awk script": "https://github.com/vyfor/icons/raw/master/icons/pastel/awk.png", "awk script": "https://github.com/vyfor/icons/raw/master/icons/pastel/awk.png",
"bat": "https://github.com/vyfor/icons/raw/master/icons/onyx/shell.png", "bat": "https://github.com/vyfor/icons/raw/master/icons/onyx/shell.png",
"bazel": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Bazel_logo.svg/1024px-Bazel_logo.svg.png", "bazel": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Bazel_logo.svg/1024px-Bazel_logo.svg.png",
"bend": "https://avatars.githubusercontent.com/u/92327702", "bend": "https://avatars.githubusercontent.com/u/92327702",
"blueprint": "https://github.com/vyfor/icons/raw/master/icons/onyx/controller.png", "blueprint": "https://github.com/vyfor/icons/raw/master/icons/onyx/controller.png",
"brainfuck": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png", "brainfuck": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png",
"buzz": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png", "buzz": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png",
"c": "https://github.com/vyfor/icons/raw/master/icons/onyx/c.png", "c": "https://github.com/vyfor/icons/raw/master/icons/onyx/c.png",
"carbon": "https://upload.wikimedia.org/wikipedia/commons/e/e1/Carbon_logo.png", "carbon": "https://upload.wikimedia.org/wikipedia/commons/e/e1/Carbon_logo.png",
"clojure": "https://github.com/vyfor/icons/raw/master/icons/onyx/clojure.png", "clojure": "https://github.com/vyfor/icons/raw/master/icons/onyx/clojure.png",
"cmake": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/CMake_logo.svg/1024px-CMake_logo.svg.png", "cmake": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/CMake_logo.svg/1024px-CMake_logo.svg.png",
"cpp": "https://github.com/vyfor/icons/raw/master/icons/onyx/cpp.png", "cpp": "https://github.com/vyfor/icons/raw/master/icons/onyx/cpp.png",
"crystal": "https://github.com/vyfor/icons/raw/master/icons/onyx/crystal.png", "crystal": "https://github.com/vyfor/icons/raw/master/icons/onyx/crystal.png",
"csharp": "https://github.com/vyfor/icons/raw/master/icons/onyx/csharp.png", "csharp": "https://github.com/vyfor/icons/raw/master/icons/onyx/csharp.png",
"css": "https://github.com/vyfor/icons/raw/master/icons/onyx/css.png", "css": "https://github.com/vyfor/icons/raw/master/icons/onyx/css.png",
"d": "https://github.com/vyfor/icons/raw/master/icons/onyx/d.png", "d": "https://github.com/vyfor/icons/raw/master/icons/onyx/d.png",
"dart": "https://github.com/vyfor/icons/raw/master/icons/onyx/dart.png", "dart": "https://github.com/vyfor/icons/raw/master/icons/onyx/dart.png",
"diff": "https://github.com/vyfor/icons/raw/master/icons/onyx/diagnostics.png", "diff": "https://github.com/vyfor/icons/raw/master/icons/onyx/diagnostics.png",
"dockerfile": "https://github.com/vyfor/icons/raw/master/icons/onyx/docker.png", "dockerfile": "https://github.com/vyfor/icons/raw/master/icons/onyx/docker.png",
"elixir": "https://github.com/vyfor/icons/raw/master/icons/onyx/elixir.png", "elixir": "https://github.com/vyfor/icons/raw/master/icons/onyx/elixir.png",
"elm": "https://github.com/vyfor/icons/raw/master/icons/onyx/elm.png", "elm": "https://github.com/vyfor/icons/raw/master/icons/onyx/elm.png",
"environment file": "https://github.com/vyfor/icons/raw/master/icons/onyx/gear.png", "environment file": "https://github.com/vyfor/icons/raw/master/icons/onyx/gear.png",
"fantom": "https://avatars.githubusercontent.com/u/54911692", "fantom": "https://avatars.githubusercontent.com/u/54911692",
"fortran": "https://github.com/vyfor/icons/raw/master/icons/onyx/fortran.png", "fortran": "https://github.com/vyfor/icons/raw/master/icons/onyx/fortran.png",
"fstab": "https://github.com/vyfor/icons/raw/master/icons/onyx/gear.png", "fstab": "https://github.com/vyfor/icons/raw/master/icons/onyx/gear.png",
"gdscript": "https://github.com/vyfor/icons/raw/master/icons/onyx/godot.png", "gdscript": "https://github.com/vyfor/icons/raw/master/icons/onyx/godot.png",
"glsl": "https://github.com/vyfor/icons/raw/master/icons/onyx/opengl.png", "glsl": "https://github.com/vyfor/icons/raw/master/icons/onyx/opengl.png",
"go": "https://github.com/vyfor/icons/raw/master/icons/onyx/go.png", "go": "https://github.com/vyfor/icons/raw/master/icons/onyx/go.png",
"graphql": "https://github.com/vyfor/icons/raw/master/icons/onyx/graphql.png", "graphql": "https://github.com/vyfor/icons/raw/master/icons/onyx/graphql.png",
"groovy": "https://github.com/vyfor/icons/raw/master/icons/onyx/groovy.png", "groovy": "https://github.com/vyfor/icons/raw/master/icons/onyx/groovy.png",
"hare": "https://harelang.org/mascot.png", "hare": "https://harelang.org/mascot.png",
"haskell": "https://github.com/vyfor/icons/raw/master/icons/onyx/haskell.png", "haskell": "https://github.com/vyfor/icons/raw/master/icons/onyx/haskell.png",
"haxe": "https://github.com/vyfor/icons/raw/master/icons/pastel/haxe.png", "haxe": "https://github.com/vyfor/icons/raw/master/icons/pastel/haxe.png",
"haxe compiler arguments": "https://github.com/vyfor/icons/raw/master/icons/onyx/haxe.png", "haxe compiler arguments": "https://github.com/vyfor/icons/raw/master/icons/onyx/haxe.png",
"hlsl": "https://github.com/vyfor/icons/raw/master/icons/onyx/diagnostics.png", "hlsl": "https://github.com/vyfor/icons/raw/master/icons/onyx/diagnostics.png",
"html": "https://github.com/vyfor/icons/raw/master/icons/onyx/html.png", "html": "https://github.com/vyfor/icons/raw/master/icons/onyx/html.png",
"ini": "https://github.com/vyfor/icons/raw/master/icons/onyx/gear.png", "ini": "https://github.com/vyfor/icons/raw/master/icons/onyx/gear.png",
"jai": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png", "jai": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png",
"java": "https://github.com/vyfor/icons/raw/master/icons/onyx/java.png", "java": "https://github.com/vyfor/icons/raw/master/icons/onyx/java.png",
"javascript": "https://github.com/vyfor/icons/raw/master/icons/onyx/javascript.png", "javascript": "https://github.com/vyfor/icons/raw/master/icons/onyx/javascript.png",
"javascriptreact": "https://github.com/vyfor/icons/raw/master/icons/onyx/react.png", "javascriptreact": "https://github.com/vyfor/icons/raw/master/icons/onyx/react.png",
"json": "https://github.com/vyfor/icons/raw/master/icons/onyx/json.png", "json": "https://github.com/vyfor/icons/raw/master/icons/onyx/json.png",
"julia": "https://github.com/vyfor/icons/raw/master/icons/onyx/julia.png", "julia": "https://github.com/vyfor/icons/raw/master/icons/onyx/julia.png",
"kotlin": "https://github.com/vyfor/icons/raw/master/icons/onyx/kotlin.png", "kotlin": "https://github.com/vyfor/icons/raw/master/icons/onyx/kotlin.png",
"latex": "https://github.com/vyfor/icons/raw/master/icons/onyx/latex.png", "latex": "https://github.com/vyfor/icons/raw/master/icons/onyx/latex.png",
"lobster": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png", "lobster": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png",
"lua": "https://github.com/vyfor/icons/raw/master/icons/onyx/latex.png", "lua": "https://github.com/vyfor/icons/raw/master/icons/onyx/latex.png",
"makefile": "https://github.com/vyfor/icons/raw/master/icons/onyx/diagnostics.png", "makefile": "https://github.com/vyfor/icons/raw/master/icons/onyx/diagnostics.png",
"markdown": "https://github.com/vyfor/icons/raw/master/icons/onyx/markdown.png", "markdown": "https://github.com/vyfor/icons/raw/master/icons/onyx/markdown.png",
"meson": "https://github.com/vyfor/icons/raw/master/icons/onyx/diagnostics.png", "meson": "https://github.com/vyfor/icons/raw/master/icons/onyx/diagnostics.png",
"moonscript": "https://github.com/vyfor/icons/raw/master/icons/onyx/lua.png", "moonscript": "https://github.com/vyfor/icons/raw/master/icons/onyx/lua.png",
"nelua": "https://nelua.io/assets/img/nelua-logo-64px.png", "nelua": "https://nelua.io/assets/img/nelua-logo-64px.png",
"nim": "https://github.com/vyfor/icons/raw/master/icons/onyx/nim.png", "nim": "https://github.com/vyfor/icons/raw/master/icons/onyx/nim.png",
"objeck": "https://github.com/vyfor/icons/raw/master/icons/onyx/gear.png", "objeck": "https://github.com/vyfor/icons/raw/master/icons/onyx/gear.png",
"objective-c": "https://github.com/vyfor/icons/raw/master/icons/onyx/c.png", "objective-c": "https://github.com/vyfor/icons/raw/master/icons/onyx/c.png",
"ocaml": "https://github.com/vyfor/icons/raw/master/icons/onyx/ocaml.png", "ocaml": "https://github.com/vyfor/icons/raw/master/icons/onyx/ocaml.png",
"odin": "https://github.com/vyfor/icons/raw/master/icons/onyx/odin.png", "odin": "https://github.com/vyfor/icons/raw/master/icons/onyx/odin.png",
"openscad": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/eb/Openscad.svg/1024px-Openscad.svg.png", "openscad": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/eb/Openscad.svg/1024px-Openscad.svg.png",
"pascal": "https://github.com/vyfor/icons/raw/master/icons/onyx/pascal.png", "pascal": "https://github.com/vyfor/icons/raw/master/icons/onyx/pascal.png",
"perl": "https://github.com/vyfor/icons/raw/master/icons/onyx/perl.png", "perl": "https://github.com/vyfor/icons/raw/master/icons/onyx/perl.png",
"php": "https://github.com/vyfor/icons/raw/master/icons/onyx/php.png", "php": "https://github.com/vyfor/icons/raw/master/icons/onyx/php.png",
"pico-8": "https://www.lexaloffle.com/gfx/p8b_pico8.png", "pico-8": "https://www.lexaloffle.com/gfx/p8b_pico8.png",
"plaintext": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png", "plaintext": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png",
"po": "https://github.com/vyfor/icons/raw/master/icons/onyx/gnu.png", "po": "https://github.com/vyfor/icons/raw/master/icons/onyx/gnu.png",
"pony": "https://avatars.githubusercontent.com/u/12997238", "pony": "https://avatars.githubusercontent.com/u/12997238",
"postgresql": "https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Postgresql_elephant.svg/1024px-Postgresql_elephant.svg.png", "postgresql": "https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Postgresql_elephant.svg/1024px-Postgresql_elephant.svg.png",
"powershell": "https://github.com/vyfor/icons/raw/master/icons/onyx/powershell.png", "powershell": "https://github.com/vyfor/icons/raw/master/icons/onyx/powershell.png",
"python": "https://github.com/vyfor/icons/raw/master/icons/onyx/python.png", "python": "https://github.com/vyfor/icons/raw/master/icons/onyx/python.png",
"r": "https://github.com/vyfor/icons/raw/master/icons/onyx/r.png", "r": "https://github.com/vyfor/icons/raw/master/icons/onyx/r.png",
"ring": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png", "ring": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png",
"ruby": "https://github.com/vyfor/icons/raw/master/icons/onyx/ruby.png", "ruby": "https://github.com/vyfor/icons/raw/master/icons/onyx/ruby.png",
"rust": "https://github.com/vyfor/icons/raw/master/icons/onyx/rust.png", "rust": "https://github.com/vyfor/icons/raw/master/icons/onyx/rust.png",
"sass": "https://github.com/vyfor/icons/raw/master/icons/onyx/scss.png", "sass": "https://github.com/vyfor/icons/raw/master/icons/onyx/scss.png",
"scala": "https://github.com/vyfor/icons/raw/master/icons/onyx/scala.png", "scala": "https://github.com/vyfor/icons/raw/master/icons/onyx/scala.png",
"shellscript": "https://github.com/vyfor/icons/raw/master/icons/onyx/shell.png", "shellscript": "https://github.com/vyfor/icons/raw/master/icons/onyx/shell.png",
"smallbasic": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png", "smallbasic": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png",
"solidity": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png", "solidity": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png",
"sql": "https://github.com/vyfor/icons/raw/master/icons/onyx/sql.png", "sql": "https://github.com/vyfor/icons/raw/master/icons/onyx/sql.png",
"swift": "https://github.com/vyfor/icons/raw/master/icons/onyx/swift.png", "swift": "https://github.com/vyfor/icons/raw/master/icons/onyx/swift.png",
"tcl": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png", "tcl": "https://github.com/vyfor/icons/raw/master/icons/onyx/text.png",
"teal": "https://avatars.githubusercontent.com/u/62526430", "teal": "https://avatars.githubusercontent.com/u/62526430",
"toml": "https://github.com/vyfor/icons/raw/master/icons/onyx/toml.png", "toml": "https://github.com/vyfor/icons/raw/master/icons/onyx/toml.png",
"typescript": "https://github.com/vyfor/icons/raw/master/icons/onyx/typescript.png", "typescript": "https://github.com/vyfor/icons/raw/master/icons/onyx/typescript.png",
"typescriptreact": "https://github.com/vyfor/icons/raw/master/icons/onyx/react.png", "typescriptreact": "https://github.com/vyfor/icons/raw/master/icons/onyx/react.png",
"v": "https://github.com/vyfor/icons/raw/master/icons/onyx/v.png", "v": "https://github.com/vyfor/icons/raw/master/icons/onyx/v.png",
"vala": "https://github.com/vyfor/icons/raw/master/icons/onyx/vala.png", "vala": "https://github.com/vyfor/icons/raw/master/icons/onyx/vala.png",
"verilog": "https://github.com/vyfor/icons/raw/master/icons/onyx/assembly.png", "verilog": "https://github.com/vyfor/icons/raw/master/icons/onyx/assembly.png",
"visual basic": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/40/VB.NET_Logo.svg/1024px-VB.NET_Logo.svg.png", "visual basic": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/40/VB.NET_Logo.svg/1024px-VB.NET_Logo.svg.png",
"vue": "https://github.com/vyfor/icons/raw/master/icons/onyx/vue.png", "vue": "https://github.com/vyfor/icons/raw/master/icons/onyx/vue.png",
"wren": "https://avatars.githubusercontent.com/u/45213573", "wren": "https://avatars.githubusercontent.com/u/45213573",
"x86 assembly": "https://github.com/vyfor/icons/raw/master/icons/onyx/assembly.png", "x86 assembly": "https://github.com/vyfor/icons/raw/master/icons/onyx/assembly.png",
"xml": "https://github.com/vyfor/icons/raw/master/icons/onyx/xml.png", "xml": "https://github.com/vyfor/icons/raw/master/icons/onyx/xml.png",
"xtend": "https://github.com/vyfor/icons/raw/master/icons/onyx/java.png", "xtend": "https://github.com/vyfor/icons/raw/master/icons/onyx/java.png",
"yaml": "https://github.com/vyfor/icons/raw/master/icons/onyx/yaml.png", "yaml": "https://github.com/vyfor/icons/raw/master/icons/onyx/yaml.png",
"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,28 +33,27 @@ 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;
AtomicBoolScopedOp loading( mLoading, true ); AtomicBoolScopedOp loading( mLoading, true );
pluginManager->subscribeMessages( this, pluginManager->subscribeMessages( this,
[this]( const auto& notification ) -> PluginRequestHandle { [this]( const auto& notification ) -> PluginRequestHandle {
return processMessage( notification ); return processMessage( notification );
} ); } );
std::vector<std::string> paths; std::vector<std::string> paths;
std::string path( pluginManager->getResourcesPath() + "plugins/discordRPC.json" ); std::string path( pluginManager->getResourcesPath() + "plugins/discordRPC.json" );
if ( FileSystem::fileExists( path ) ) if ( FileSystem::fileExists( path ) )
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 );
} }
std::string data; std::string data;
if ( !FileSystem::fileGet( path, data ) ) if ( !FileSystem::fileGet( path, data ) )
return; return;
mConfigHash = String::hash( data ); mConfigHash = String::hash( data );
@@ -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 ) {
@@ -91,13 +95,13 @@ void DiscordRPCplugin::load( PluginManager* pluginManager ) {
mConfigHash = String::hash( newData ); mConfigHash = String::hash( newData );
} }
} }
mIPC.tryConnect(); mIPC.tryConnect();
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();
setReady( clock.getElapsedTime() ); setReady( clock.getElapsedTime() );
@@ -109,38 +113,45 @@ 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();
} }
} }
default: default:
break; break;
} }
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 ) {
listeners.push_back( editor->on( Event::OnFocus, [this, editor]( const Event* ) { listeners.push_back( editor->on( Event::OnFocus, [this, editor]( const Event* ) {
// `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();
if ( filename != mLastFile ) { if ( filename != mLastFile ) {
this->mLastFile = filename; this->mLastFile = filename;
@@ -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,52 +18,53 @@ 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, { 0, 0, 0 },
{ 0, 0, 0 }, DiscordRPCplugin::NewSync };
DiscordRPCplugin::NewSync }; }
}
static Plugin* New( PluginManager* pluginManager );
static Plugin* NewSync( PluginManager* pluginManager );
virtual ~DiscordRPCplugin() override;
std::string getId() override { return Definition().id; }
std::string getTitle() override { return Definition().name; } static Plugin* New( PluginManager* pluginManager );
std::string getDescription() override { return Definition().description; } static Plugin* NewSync( PluginManager* pluginManager );
protected: virtual ~DiscordRPCplugin() override;
DiscordIPC mIPC;
std::string mLastFile; std::string getId() override { return Definition().id; }
std::string mProjectName;
nlohmann::json mcLangBindings; std::string getTitle() override { return Definition().name; }
void load ( PluginManager* pluginManager ); std::string getDescription() override { return Definition().description; }
PluginRequestHandle processMessage( const PluginMessage& msg ); protected:
DiscordIPC mIPC;
virtual void onRegisterListeners(UICodeEditor* editor, std::vector<Uint32>& listeners ) override; std::string mLastFile;
virtual void onRegisterDocument( TextDocument* doc ) override; std::string mProjectName;
nlohmann::json mcLangBindings;
bool mcDoLangIcon;
DiscordRPCplugin( PluginManager* pluginManager, bool sync );
void load( PluginManager* pluginManager );
PluginRequestHandle processMessage( const PluginMessage& msg );
virtual void onRegisterListeners( UICodeEditor* editor,
std::vector<Uint32>& listeners ) override;
virtual void onRegisterEditor( UICodeEditor* editor ) override;
virtual void onUnregisterEditor( UICodeEditor* editor ) override;
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,303 +27,320 @@ 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;
} }
}
reconnect();
return false;
#elif defined( EE_PLATFORM_POSIX )
// Socket path can be in any of the following directories:
// * `XDG_RUNTIME_DIR`
// * `TMPDIR`
// * `TMP`
// * `TEMP`
// * `/tmp`
//
// Possibly Followed by:
// * `/app/com.discordapp.Discord` - for flatpak
// * `/.flatpak/dev.vencord.Vesktop/xdg-run` - Vesktop flatpak
// * `/snap.discord` - for snap
//
// Followed by:
// * `/discord-ipc-{i}` - where `i` is a number from 0 to 9
const std::string env[] = { "XDG_RUNTIME_DIR", "TMPDIR", "TMP", "TEMP" };
const std::vector<std::string> additionalPaths = {
"/app/com.discordapp.Discord",
"/.flatpak/dev.vencord.Vesktop/xdg-run",
"/snap.discord",
};
std::vector<std::string> validPaths;
for ( const auto& eVar : env ) {
const char* value = std::getenv( eVar.c_str() );
if ( !value ) {
continue;
}
if ( !std::filesystem::exists( value ) ) {
continue;
}
validPaths.push_back( value );
}
validPaths.push_back( "/tmp" ); // Hard coded fallback
std::vector<std::string> checkPaths;
for ( const auto& basePath : validPaths ) {
for ( const auto& additionalPath : additionalPaths ) {
std::string fullPath = basePath + additionalPath;
if ( std::filesystem::exists( fullPath ) ) {
checkPaths.push_back( fullPath );
}
}
}
checkPaths.insert( checkPaths.end(), validPaths.begin(), validPaths.end() );
for ( const auto& basePath : checkPaths ) {
if ( !std::filesystem::exists( basePath ) ) {
continue;
}
for ( int i = 0; i < 10; ++i ) {
std::string ipcPath = basePath + "/discord-ipc-" + std::to_string( i );
if ( std::filesystem::exists( ipcPath ) ) {
Log::debug( "dcIPC: IPC path found! - %s", ipcPath );
mIpcPath = ipcPath;
mSocket = socket( AF_UNIX, SOCK_STREAM, 0 );
if ( mSocket == -1 ) {
Log::error( "dcIPC: Discord IPC socket cold not be opened: %s", mIpcPath );
mIpcPath = "";
continue;
}
sockaddr_un serverAddr;
memset( &serverAddr, 0, sizeof( serverAddr ) );
serverAddr.sun_family = AF_UNIX;
mIpcPath.copy( serverAddr.sun_path, sizeof( serverAddr.sun_path ) - 1 );
serverAddr.sun_path[sizeof( serverAddr.sun_path ) - 1] =
'\0'; // Ensure null termination
if ( connect( mSocket, reinterpret_cast<struct sockaddr*>( &serverAddr ),
sizeof( serverAddr ) ) == -1 ) {
close( mSocket );
return false;
}
doHandshake();
return true;
}
} }
reconnect(); reconnect();
return false; return false;
}
#elif defined(EE_PLATFORM_POSIX) #endif
// Socket path can be in any of the following directories:
// * `XDG_RUNTIME_DIR`
// * `TMPDIR`
// * `TMP`
// * `TEMP`
// * `/tmp`
//
// Possibly Followed by:
// * `/app/com.discordapp.Discord` - for flatpak
// * `/.flatpak/dev.vencord.Vesktop/xdg-run` - Vesktop flatpak
// * `/snap.discord` - for snap
//
// Followed by:
// * `/discord-ipc-{i}` - where `i` is a number from 0 to 9
const std::string env[] = {"XDG_RUNTIME_DIR", "TMPDIR", "TMP", "TEMP"};
const std::vector<std::string> additionalPaths = {
"/app/com.discordapp.Discord",
"/.flatpak/dev.vencord.Vesktop/xdg-run",
"/snap.discord",
};
std::vector<std::string> validPaths;
for ( const auto& eVar : env ){
const char* value = std::getenv(eVar.c_str());
if (!value) { continue; }
if (!std::filesystem::exists(value)) { continue; }
validPaths.push_back(value);
}
validPaths.push_back("/tmp"); // Hard coded fallback
std::vector<std::string> checkPaths;
for ( const auto& basePath : validPaths ) {
for (const auto& additionalPath : additionalPaths) {
std::string fullPath = basePath + additionalPath;
if (std::filesystem::exists(fullPath)) {
checkPaths.push_back(fullPath);
}
}
}
checkPaths.insert(checkPaths.end(), validPaths.begin(), validPaths.end());
for (const auto& basePath : checkPaths) {
if (!std::filesystem::exists(basePath)) { continue; }
for (int i = 0; i < 10; ++i) {
std::string ipcPath = basePath + "/discord-ipc-" + std::to_string(i);
if (std::filesystem::exists(ipcPath)) {
Log::debug("dcIPC: IPC path found! - %s", ipcPath);
mIpcPath = ipcPath;
mSocket = socket(AF_UNIX, SOCK_STREAM, 0);
if (mSocket == -1) {
Log::error("dcIPC: Discord IPC socket cold not be opened: %s", mIpcPath);
mIpcPath = "";
continue;
}
sockaddr_un serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sun_family = AF_UNIX;
mIpcPath.copy(serverAddr.sun_path, sizeof(serverAddr.sun_path) - 1);
serverAddr.sun_path[sizeof(serverAddr.sun_path) - 1] = '\0'; // Ensure null termination
if (connect(mSocket, reinterpret_cast<struct sockaddr*>(&serverAddr), sizeof(serverAddr)) == -1) {
close(mSocket);
return false;
}
doHandshake();
return true;
}
}
reconnect();
return false;
}
#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} };
}}, sendPacket( DiscordIPCOpcodes::Frame, j );
{"nonce", "-"} // TODO: Null nonce for dev purposes, change to UUIDV4 in finished product
};
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())
aj["state"] = a.state;
if (!a.details.empty())
aj["details"] = a.details;
json as; if ( !a.state.empty() )
if (!a.largeImage.empty()) { aj["state"] = a.state;
as["large_image"] = a.largeImage; if ( !a.details.empty() )
} aj["details"] = a.details;
if (!a.largeText.empty()) {
as["large_text"] = a.largeText; json as;
} if ( !a.largeImage.empty() ) {
if (!a.smallImage.empty()) { as["large_image"] = a.largeImage;
as["small_image"] = a.smallImage; }
} if ( !a.largeText.empty() ) {
if (!a.smallText.empty()) { as["large_text"] = a.largeText;
as["small_text"] = a.smallText; }
} if ( !a.smallImage.empty() ) {
if (!as.empty()) { as["small_image"] = a.smallImage;
aj["assets"] = as; }
} if ( !a.smallText.empty() ) {
as["small_text"] = a.smallText;
}
if ( !as.empty() ) {
aj["assets"] = as;
}
json t;
if ( a.start != 0 ) {
t["start"] = a.start;
}
if ( a.end != 0 ) {
t["end"] = a.end;
}
if ( !t.empty() ) {
aj["timestamps"] = t;
}
json t;
if (a.start != 0) {
t["start"] = a.start;
}
if (a.end != 0) {
t["end"] = a.end;
}
if (!t.empty()) {
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();
const std::string packet = j.dump(); return;
std::vector<uint8_t> data; }
const std::string packet = j.dump();
std::vector<uint8_t> data;
// Add correct ammount of padding for the protocol // Add correct ammount of padding for the protocol
union { union {
uint32_t value; uint32_t value;
uint8_t bytes[4]; uint8_t bytes[4];
} 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());
// std::stringstream ss;
// for (uint8_t byte : data) {
// ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byte) << " ";
// }
// Log::debug(ss.str()); // Log::debug("Packet is: %s (%u)", j.dump(4), data.size());
#if defined( EE_PLATFORM_POSIX )
ssize_t bytesSent = send(mSocket, data.data(), data.size(), 0);
if (bytesSent != data.size()) {
Log::error("dcIPC: Failed to send all data to Unix socket: %zu bytes sent, %zu bytes expected", bytesSent, data.size());
reconnect();
return;
}
// std::stringstream ss;
struct timeval tv; // for (uint8_t byte : data) {
tv.tv_sec = 0; // ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byte) << " ";
tv.tv_usec = 500000; // 0.5 seconds in microseconds // }
setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
char buffer[1024];
ssize_t bytesRead = recv(mSocket, buffer, sizeof(buffer), 0);
// Log::debug("dcIPC: RECV: %s", buffer);
// TODO: Implement nonce checking? (does it even really matter?)
//return bytesRead;
#elif EE_PLATFORM == EE_PLATFORM_WIN
DWORD bytesSent;
if ( !WriteFile(mSocket, data.data(), data.size(), &bytesSent, nullptr) ) {
Log::error("dcIPC: Error writing to pipe!!");
reconnect();
return;
} else if (bytesSent != data.size()) {
Log::error("dcIPC: Incorrect ammount of data written: %zu bytes sent, %zu bytes expected",
bytesSent, data.size());
reconnect();
return;
}
DWORD bytesRead;
char buffer[1024];
if ( !ReadFile(mSocket, buffer, 1024, &bytesRead, nullptr ) ) {
Log::error("dcIPC: Error reading pipe!!");
reconnect();
return;
}
// Log::debug("dcIPC: RECV: %s", buffer);
#endif // Log::debug(ss.str());
#if defined( EE_PLATFORM_POSIX )
ssize_t bytesSent = send( mSocket, data.data(), data.size(), 0 );
if ( bytesSent != data.size() ) {
Log::error(
"dcIPC: Failed to send all data to Unix socket: %zu bytes sent, %zu bytes expected",
bytesSent, data.size() );
reconnect();
return;
}
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 500000; // 0.5 seconds in microseconds
setsockopt( mSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof( tv ) );
char buffer[1024];
ssize_t bytesRead = recv( mSocket, buffer, sizeof( buffer ), 0 );
// Log::debug("dcIPC: RECV: %s", buffer);
// TODO: Implement nonce checking? (does it even really matter?)
// return bytesRead;
#elif EE_PLATFORM == EE_PLATFORM_WIN
DWORD bytesSent;
if ( !WriteFile( mSocket, data.data(), data.size(), &bytesSent, nullptr ) ) {
Log::error( "dcIPC: Error writing to pipe!!" );
reconnect();
return;
} else if ( bytesSent != data.size() ) {
Log::error( "dcIPC: Incorrect ammount of data written: %zu bytes sent, %zu bytes expected",
bytesSent, data.size() );
reconnect();
return;
}
DWORD bytesRead;
char buffer[1024];
if ( !ReadFile( mSocket, buffer, 1024, &bytesRead, nullptr ) ) {
Log::error( "dcIPC: Error reading pipe!!" );
reconnect();
return;
}
// Log::debug("dcIPC: RECV: %s", buffer);
#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

@@ -3,81 +3,78 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
// 2^8 = 256s ~4.3min // 2^8 = 256s ~4.3min
#define DISCORDIPC_BACKOFF_MAX 8 #define DISCORDIPC_BACKOFF_MAX 8
enum DiscordIPCActivityTypes { enum DiscordIPCActivityTypes {
Playing = 0, Playing = 0,
Listening = 2, Listening = 2,
Watching = 3, Watching = 3,
Competing = 5, Competing = 5,
}; };
struct DiscordIPCActivityButton { struct DiscordIPCActivityButton {
std::string label; std::string label;
std::string url; std::string url;
}; };
struct DiscordIPCActivity { struct DiscordIPCActivity {
DiscordIPCActivityTypes type = DiscordIPCActivityTypes::Playing; DiscordIPCActivityTypes type = DiscordIPCActivityTypes::Playing;
std::string state; std::string state;
std::string details; std::string details;
time_t start = 0; time_t start = 0;
time_t end = 0; time_t end = 0;
std::string largeImage; std::string largeImage;
std::string largeText; std::string largeText;
std::string smallImage; std::string smallImage;
std::string smallText; std::string smallText;
DiscordIPCActivityButton buttons[2]; // IMPORTANT: For some reason, you do not see the buttons of your own account on the discord
// client (intended discord behavior)
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();
// false - FileNotFound/OSNotSupported // false - FileNotFound/OSNotSupported
// true - Success // true - Success
bool tryConnect(); bool tryConnect();
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
std::string mcClientID; // Configurables
protected: std::string mcClientID;
std::string mIpcPath;
int mPID; protected:
std::string mIpcPath;
int mBackoffIndex; int mPID;
int mReconnectLock = false; // Not quite a mutex because I want to lock any attempts if one is already waiting
int mBackoffIndex;
DiscordIPCActivity mActivity; int mReconnectLock =
false; // Not quite a mutex because I want to lock any attempts if one is already waiting
#if defined( EE_PLATFORM_POSIX ) DiscordIPCActivity mActivity;
int mSocket;
#elif EE_PLATFORM == EE_PLATFORM_WIN #if defined( EE_PLATFORM_POSIX )
void* mSocket; int mSocket;
#endif #elif EE_PLATFORM == EE_PLATFORM_WIN
void* mSocket;
void doHandshake(); #endif
void sendPacket( DiscordIPCOpcodes opcode, nlohmann::json j ); void doHandshake();
void sendPacket( DiscordIPCOpcodes opcode, nlohmann::json j );
}; };