Giter Club home page Giter Club logo

discord-presence's Introduction

Hi, I'm Juliette! ๐Ÿ‘‹

๐Ÿ”— Links

Kinetic Hosting

KoFi twitter twitch

๐Ÿš€ About Me

I'm a full time student, and hobby developer

๐Ÿ‘ฉโ€๐Ÿ’ป I'm currently working on silly little apps to make my life easier

๐Ÿง  I'm currently learning C, C++ & Rust

๐Ÿ˜„ She/Her

๐Ÿ› ๏ธ Skills

Rust C Typescript HTML5 CSS3 React NextJS SASS NodeJS Firebase

Metrics Snek

discord-presence's People

Contributors

bigfarts avatar bond-009 avatar doinkythederp avatar jewlexx avatar lennyphoenix avatar renovate[bot] avatar tenrys avatar valeth avatar vernoxvernax avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

discord-presence's Issues

[FEATURE] Check ready status without event listener

Is your feature request related to a problem? Please describe.
There is no consise and easy way to get the ready status of the RPC without using an event listener.

Describe the solution you'd like. Also mention of you would be able to get involved in implementing the solution
the READY AtomicBool to be un-privated.

Describe alternatives you've considered
Using a event listener, but I couldn't move refs around properly and it didn't seem to work that well. This seems like a built-in thing which would be easier to use.

`set_activity` runs before `start` despite being written after

Pretty sure I'm just doing something wrong here, but I can't figure out why set_activity runs before start in my program.

use discord_presence::Client;

fn main() {
    let mut client = Client::new(1066249445282422784);

    client.on_ready(|_| println!("Ready"));

    client.on_error(|ctx| eprintln!("{}", ctx.event));

    let thread = client.start();

    if let Err(err) = client.set_activity(|act| act.state("State Text")) {
        eprintln!("{}", err);
    }

    thread.join().unwrap()
}

This outputs the following:

Connection has not been started
Ready

If someone could please explain to me what I'm doing wrong, I would greatly appreciate it!

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

cargo
Cargo.toml
  • byteorder 1.5
  • bytes 1.6
  • cfg-if 1.0
  • crossbeam-channel 0.5
  • num-derive 0.4
  • num-traits 0.2
  • parking_lot 0.12
  • paste 1.0
  • quork 0.6
  • serde_json 1.0
  • thiserror 1.0
  • tracing 0.1
  • serde 1.0
  • uuid 1.8
  • anyhow 1.0
  • ctrlc 3.4
  • rusty-hook 0.11
  • tracing-subscriber 0.3
  • version-sync 0.9
  • named_pipe 0.4
github-actions
.github/workflows/publish.yml
  • actions/checkout v4
.github/workflows/rust.yml
  • actions/checkout v4
  • Swatinem/rust-cache v2

  • Check this box to trigger a request for Renovate to run again on this repository

[FEATURE] Removing event handlers

Is your feature request related to a problem? Please describe.
Right now it doesn't look like it's possible to remove event handlers. This is unfortunate, because it means registering an event handler is always a memory leak.

Describe the solution you'd like. Also mention of you would be able to get involved in implementing the solution
Ideally the on_event method would return a value that de-registers the event callback when it is dropped. The old behavior could be restored by using std::mem::forget on the returned value.

Describe alternatives you've considered
Another option would be to have some sort of delete_handler or remove_event_handler method on the Client. This has the downside of allowing you to try and deregister a listener multiple times or deregister one that doesn't exist, making some kind of runtime error.

[BUG] "missing field `buttons`", line: 1, column: 107

Describe the bug
When running the following code, set_activity panics. The activity is visible for a few seconds in Discord.

use discord_presence::{Client, Event};
use std::{env, thread, time};

fn main() {
    // Get our main status message
    let state_message = env::args().nth(1).expect("Requires at least one argument");

    // Create the client
    let mut drpc = Client::new(/* ... */);

    // Register event handlers with the corresponding methods
    drpc.on_ready(|_ctx| {
        println!("ready?");
    })
    .persist();

    // Start up the client connection, so that we can actually send and receive stuff
    drpc.start();
    drpc.block_until_event(Event::Ready).unwrap();

    // Set the activity
    drpc.set_activity(|act| act.state(state_message))
        .expect("Failed to set activity");

    // Wait 10 seconds before exiting
    thread::sleep(time::Duration::from_secs(5));
}
ready?
thread 'main' panicked at src/main.rs:23:10:
Failed to set activity: JsonError(Error("missing field `buttons`", line: 1, column: 107))
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

To Reproduce
Steps to reproduce the behavior:

  1. Run the code specified above.
  2. After the client is ready, the activity will be visible in Discord, but set_activity will panic.

Expected behavior
The code should run as intended; the activity should be visible for 5 seconds, after which the program terminates.

Desktop (please complete the following information):

  • OS: macOS
  • Version: 12.7.3
  • Rustc: stable 1.77.1
  • crate version: 1.1.1

Additional context
Adding a button to the activity makes the program hang forever.

drpc.set_activity(|act| {
        act.state(state_message)
            .append_buttons(|btn| btn.label("Testing"))
}).expect("Failed to set activity");

[BUG] Client::shutdown Err(NotStarted)

Describe the bug
When I call Client.shutdown() it returns an Err(NotStarted)
I believe it's succeeding but still returning an Err, because if I use block_on instead, it doesn't error.

To Reproduce

lazy_static::lazy_static! {
    pub static ref USER: Option<PartialUser> = {
        let user_event = Arc::new(RwLock::new(None));
        let user_clone = user_event.clone();
        let mut client = Client::new(CLIENT_ID);

        client.on_ready(move |ctx| {
            if let EventData::Ready(event) = ctx.event {
                *user_event.write() = event.user;
            };
        }).persist();

        client.start();

        // block_until_event will never timeout
        std::thread::sleep(Duration::from_secs(5));

        client.shutdown().expect("Failed to stop RPC thread");

        let user = user_clone.read();

        user.clone()
    };
}

Expected behavior
Client.shutdown() to return Ok if it successfully shut down the thread.

Screenshots
image

Desktop:

  • OS: Windows 11 23H2
  • Version 1.1.0

[BUG] PartialUser isn't public

I need to specify an Option<PartialUser> response, but PartialUser isn't public.

lazy_static::lazy_static! {
    pub static ref USER: Option<PartialUser> = {
        let user = Arc::new(RwLock::new(None));
        let user_clone = user.clone();

        let mut client = Client::new(CLIENT_ID);
        client.on_ready(move |ctx| {
            let EventData::Ready(event) = ctx.event else {
                return;
            };

            *user.write() = event.user;
        });

        client.start();
        std::thread::sleep(Duration::from_secs(5));
        client.shutdown().expect("Failed to stop RPC thread");

        let user = user_clone.read();

        user.clone()
    };
}

rpc not working with tauri app

when i put tauri func to top rpc not working but when i put tauri func after rpc Discrod RpC working but tauri app not starting

Screenshot 2022-09-30 142205

[FEATURE] Close/Exit/Quit

I need a way to close/exit/quit the thread, I just need the first ready event to get the user's discord id

impl Default for Ravenwood {
    fn default() -> Self {
        println!("[Ravenwood] Attempting to get your Discord ID using RPC");

        let client = Client::new();
        let mut discord_id = USER_ID;
        let mut discord_rpc = DiscordRPC::new(CLIENT_ID);
        discord_rpc.on_ready(|ctx| {
            let a = ctx.event;
            let b = a.as_object();
        });
        let handle = discord_rpc.start();
        // std::thread::sleep(Duration::from_secs(15));
        discord_rpc.block_until_event(Event::Ready).unwrap();

        if discord_id == USER_ID {
            println!("[Ravenwood] Couldn't get your Discord ID, please make sure Discord is open");
            println!("[Ravenwood] Defaulting to the ID of the developer of this program, ShayBox");
        }

        Self { client, discord_id }
    }
}

Letting the variables drop out of scope just causes the thread to crash when it receives an event
Also, A model struct for the ready event would be nice

Maybe this can be done using Abortable
https://docs.rs/futures/latest/futures/future/struct.Abortable.html

[FEATURE] Allow for generic IPC usage

๐Ÿ‘‹ Hi @jewlexx & community

What I'm going to propose could very well be "out of scope" for this project and might be possible to abstract the IPC logic into a standalone project which this could consume.

Proposal

Allow for more generic usage of the IPC that is documented as RPC private beta and probably never going public any time soon ๐Ÿ˜….

Why?

There are many things you can do when interacting with the discord client via RPC. I use a bunch of the RPC API in hacksore/overlayed but I want to try out Tauri and currently there is not a rust impl of a discord IPC client.

Crude example

Keep in mind I'm just the local JS dev so my knowledge of rust is basically non-existent.

use discord_presence::{Client as DiscordRPC, DiscordCommand, DiscordEvent};

fn main() {
  let mut drpc = DiscordRPC::new(905987126099836938);

  // client is ready so we can login
  drpc.on_ready(|_ctx| {
    println!("client connected!");

    // login with a valid app access token that has "rpc" scope as well as "trusted testers"
    drpc.login("42069420");

    // assuming login was succesful we can try to sub to moar events
    drpc.subscribe(DiscordCommand::GetSelectedVoiceChannel);
    drpc.subscribe(DiscordCommand::VoiceChannelSelect);
  });

  // generic message handler to capture anything from the IPC
  drpc.on_message(|ctx| {
    println!("Command: {:?}", ctx.command);
    println!("Event: {:?}", ctx.event);
    println!("Data: {:?}", ctx.data);

    // sent when the client joins a voice channel
    if (ctx.event == DiscordEvent::VoiceChannelSelect) {
      // TODO: do something with this
    }
  });

  drpc.start();
}

Initially, I started trying to hack something together hacksore/discord-ipc-rust but then I stumbled across this repo.

In any case thanks for all the work that went into this project and no hard feelings if my request can't be done.

Presence updates hang my game

Hey, thanks a bunch for this plugin!

I'm noticing that changing my presence seems to hang my game. I have the following system:

fn update_presence(
    app_state: Res<State<AppState>>,
    mut last_state: Local<Option<AppState>>,
    mut activity_state: ResMut<ActivityState>,
    level: Query<&Level, Changed<Level>>,
) {
    let mut changed = false;
    for _ in level.iter() {
        println!("New level");
        changed = true;
    }
    if changed || *last_state != Some(*app_state.current()) {
        println!(
            "App state changed: {:?} != {:?}",
            *last_state,
            Some(*app_state.current())
        );
        match app_state.current() {
            AppState::Loading | AppState::Paused => {}
            AppState::InGame
            | AppState::Exploration
            | AppState::BetweenLives
            | AppState::LevelUp => {
                for level in level.iter() {
                    // activity_state.details = Some(format!("Level {}", **level));
                }
            }
            _ => {
                // activity_state.details = None;
            }
        }
    }
    *last_state = Some(*app_state.current());
}

I've confirmed that these conditionals run when they should, and not excessively. As shown, this system doesn't seem to hang the game. However, if I uncomment the line that changes the state details, the game hangs. Likewise, if I uncomment more of the matches so I can set state updates more liberally, the game hangs at each point where an update is sent.

I'm guessing the client isn't async? Wondering if it'd make sense to run the updates in a separate task?

Thanks again.

Failed to connect: IoError(Os { code: 2, kind: NotFound, message: "No such file or directory" })

The rpc application is normally created on https://discord.com/developers/applications/

fn main() {
	App::new()
		.add_plugins(DefaultPlugins)
		.add_plugin(RPCPlugin(RPCConfig{
			app_id: token(),
			show_time: true,
		}))
                .add_system(update_presence)
		.run();
}

fn update_presence(
	mut state: ResMut<ActivityState>,
){
        state.instance = Some(true);
        state.details = Some("Hello World".to_string());
        state.state = Some("This is state".to_string());
}

Function token() simply returns my token variable
But I get this error for some reason:
Failed to connect: IoError(Os { code: 2, kind: NotFound, message: "No such file or directory" })

EDIT:
OS: Ubuntu Budgie 20.04
Kernel: 5.13.0
Library Version: 0.2.2 (0.5.2)
Bevy Version: 0.7

[FEATURE] Set activity type? "Listening to ..."

I'm developing a music app, and I would really like the ability to have the discord status say "Listening to <music application>" or "Listening on <music application>". Just like spotify. Right now it says "Playing <discord developer application name>"

Is there any way to change this? Or is this somehow changed through the discord dev api? I've looked through the docs.rs page, and didn't find much...

[BUG] Connection errors are not surfaced

Describe the bug
If Discord is not running, or closes while the connection is open, an error is logged:

ERROR discord_presence::connection::manager: Failed to connect: IoError(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" })

The connection manager then breaks from the send/receive loop, but the error itself is not propagated to the consumer, making it very difficult (or impossible) to actually detect and handle these situations (unless I'm missing something).

To Reproduce
Steps to reproduce the behavior:

  1. Close discord
  2. Run the following code:
let client = DiscordClient::new("id");

client.on_ready(|_| println!("ready"));
client.on_error(|err| println!("error: {err:?}"));

client.start();
  1. Observe the above error printed from the library, but not captured by on_error.

Expected behavior
These connection errors should be propagated to the client's on_error handler, making it possible to capture and handle. It should be possible to capture connection errors when the library first starts, and at any point thereafter.

Desktop (please complete the following information):

  • OS: Linux
  • Version 0.5.16

Failed to set presence: No message sent

Describe the bug
It prints the following instead of showing presence:

Failed to set presence: No message sent

Code

#![cfg_attr(
    all(not(debug_assertions), target_os = "windows"),
    windows_subsystem = "windows"
)]

use discord_presence::Client as DiscordRPC;
use std::env;

fn main() {
    let mut drpc = DiscordRPC::new(1002568032041832578);

    drpc.on_ready(|_ctx| {
        println!("READY!");
    });

    drpc.on_error(|ctx| {
        eprintln!("An error occured, {}", ctx.event);
    });

    drpc.start();

    if let Err(why) = drpc.set_activity(|a| {
        a.state("Running examples").assets(|ass| {
            ass.large_image("1024x1024")
                .large_text("Building a Discord Bot")
                .small_image("512x512")
                .small_text("With Hydrazine")
        })
    }) {
        println!("Failed to set presence: {}", why);
    }

    tauri::Builder::default()
        .run(tauri::generate_context!())
        .expect("Unknown Error Occurred While Running Application!");
}
  • Windows 10

[FEATURE] Internal rate limiter

Is your feature request related to a problem? Please describe.
Internal rate limiter, to prevent devs from hitting Discord rate limits by default.

Describe the solution you'd like. Also mention of you would be able to get involved in implementing the solution
Implement a rate limiter that follows the Discord rate limit and only runs executions when the rate limit is refreshed.

[BUG] Does not work with Ubuntu 22.04 Snap-based installs

Ubuntu 22.04's Snap-based Discord uses a different directory for configuration and IPC, resulting in the library not being able to find the IPC socket. The library will infinitely hang.

It looks like an issue for an older version of Discord was previously filed and closed. Perhaps Ubuntu changed how Snaps work.

A debian package-based Discord works fine.

Versions:

  • Linux 5.15.0-48-generic #54-Ubuntu SMP Fri Aug 26 13:26:29 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
  • Discord (Snap): Stable 152532 (a118a24) Host 0.0.20 Linux 64-Bit (5.15.0-48-Generic)
  • rustc 1.64.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.