serenity-rs / poise Goto Github PK
View Code? Open in Web Editor NEWDiscord bot command framework for serenity, with advanced features like edit tracking and flexible argument parsing
License: MIT License
Discord bot command framework for serenity, with advanced features like edit tracking and flexible argument parsing
License: MIT License
It seems like the slash commands I created are only available on users who have the administrator permission. For someone with no special permissions, the command list appears empty when starting to type the slash commands with /
. The prefix based commands work fine though. It is also not a permissioning problem regarding slash commands in general, as another bot's slash commands are still accessible. Context menu commands also seem to work.
Error text:
No method named
embeds
found for mutable reference&mut serenity::builder::CreateInteractionResponseData
in the current scope
As of 8 days from the time of writing, embeds
is no longer a valid function; use set_embeds
instead.
Hey so I just updated my packages and poise updated as well. However, now that I've done that, whenever I try and run the bot the following error comes up and stops it from running...
error: unexpected token: `include_str`
--> /Users/user/.cargo/git/checkouts/poise-2ca7e75d46548da7/435cf20/src/lib.rs:1:10
|
1 | #![doc = include_str!("../README.md")]
| ^^^^^^^^^^^
error: aborting due to previous error
error: could not compile `poise`
Any help would be greatly appreciated. Thanks!
This may be just me being dumb and missing something obvious
i am trying to make a announce command that will send an embed in a channel (channel, message, title are in command arguments)
tho to send it using channel.id().send_message() requires &ctx.http, is there a way to get the http somehow differently?
or is there a different way to send embed in a channel
main.rs
According to the docs, discord allows you to set a default value for modal interaction fields.
It would be nice if these where supported dynamically in some way -- although I'm not sure how that'd look.
I think one way to structure that API would be to make the Modal derive-macro generate a second struct <name>DefaultValues
,
which could contain fields for each field in the original modal that has been annotated with #[has_default]
. Then you could provide an instance of that DefaultValues-struct when executing the modal interaction.
Alternatively, the macro could generate a builder struct that requires the defaults to be provided via functions, I guess
The docs on owners i can find are
https://kangalioo.github.io/poise/master/poise/attr.command.html
owners_only: Restricts command callers to the list of owners specified in framework options
https://kangalioo.github.io/poise/master/poise/struct.FrameworkOptions.html#structfield.owners
User IDs which are allowed to use owners_only commands
I think in both of these places it would probably be good to mention it adds the user that created the bot if it's not in owners already.
It would also be nice to have the option to disable that functionality.
https://kangalioo.github.io/poise/master/src/poise/framework/builder.rs.html#164
Hello, I was scheduled these days and something came to my mind that I believe would be a good addition
A way to have a struct that is initially defined in the before command and goes through all the states, the command check, the command itself and the after command
Something similar to how the bot's global data is set
So something like that would be in place of the current pre command
I believe that there would have to be a change in how the command context is currently defined, to have the definition of the type that would transit between the command states
This issue is a continuation of the discussion in #19.
Poise currently generates multiple command objects per function, corresponding to each command type (prefix, slash, context menu). These command objects are stored completely separate from each other in PrefixFrameworkOptions and ApplicationFrameworkOptions respectively.
This makes it hard to tell which command invocations belong to the same command at runtime, which is needed for many things:
In #19 we discussed several ideas to redesign how commands are stored in order to fix the issues. But after thinking about each of them and starting to implement a couple in feature branches, none of them seemed great.
I'm currently relatively demotivated to work on this issue because to me it feels like no good solution is in sight. This issue functions as a reminder/placeholder for now, or as a place of discussion for ideas for solutions
It appears that subcommands (specifically for slash commands, using the command
macro in my case) are somehow implemented, but the only times I can see them mentioned in the documentation (on the page for the command
macro and the page for the Command
struct, and not how to use them.
I can infer from compiler error messages that when specified in the command
macro, subcommands should be the name of another function, and have worked out that:
Context
parameter and returns the Result
that is expected by the macro. It doesn't appear the parent command ever gets run by running a subcommand, it seems to just be there as a placeholder.slash_command
.Assuming these are accurate (which it's entirely possible that they're not), having these things shown in documentation, or even an example, would be great.
Or, is there a more idiomatic way to do this? Documenting that would also be really nice to have.
Here's my code that seems to work as expected:
#[poise::command(
slash_command,
subcommands("create"),
)]
async fn class(
context: Context<'_>,
) -> Result<(), Error> {
println!("parent command");
Ok(())
}
#[poise::command(slash_command)]
async fn create(
context: Context<'_>,
text: String,
) -> Result<(), Error> {
println!("test");
Ok(())
}
Edit: I just found examples/framework_usage/commands/subcommand.rs
. Still, a link to this example on the command macro doc page would be greatly appreciated, as well as links to the other similar examples by their relevant documentation. (You always seem to figure stuff out right after you ask for help, don't you?)
when serenity-rs/serenity#1921 gets merged, how will this library handle localizations?
I've noticed that poise
uses println!
as well as eprintln!
.
This is bad, because this can't make use of a log backend like env_logger
which formats logs in a nice way. This might lead to cases where a warning is missed, because it is just plain text and can't be distinguished from other (non warning) logs. E.g. I've just had a hard time finding this warning: https://github.com/kangalioo/poise/blob/3ad61d4d1c51334b33a6bc362b129fb0e70ea514/src/framework/mod.rs#L287
I saw the crate is just a placeholder.
What
The current builder for the framework doesn't provide a method to get the framework without running it.
I believe a finish()
(or another name like framework()
) method would be useful.
Why
The example from the README proposes (more or less) this code:
#[tokio::main]
async fn main() {
poise::Framework::build()
.token(std::env::var("DISCORD_BOT_TOKEN").unwrap())
.user_data_setup(move |_ctx, _ready, _framework| {
Box::pin(async move {
Ok(())
})
})
.options(poise::FrameworkOptions {
// configure framework here
prefix_options: PrefixFrameworkOptions {
prefix: Some(":t".into()),
..Default::default()
},
..Default::default()
})
.run()
.await
.unwrap();
}
This works fine but provides no control over the Framework
instance which can't even be accessed within main
. This becomes an issue when you want to have some external control on the state of the framework (running or not). For example if you want to gracefully shutdown the shards when quitting by reacting to an INTERRUPT
signal. For the intent of making this example clearer the following is code I'd like to be able to write:
#[tokio::main]
async fn main() {
let framework = poise::build()
.token(std::env::var("DISCORD_BOT_TOKEN").unwrap())
.user_data_setup(move |_ctx, _ready, _framework| {
Box::pin(async move {
Ok(())
})
})
.options(poise::FrameworkOptions {
// configure framework here
prefix_options: PrefixFrameworkOptions {
prefix: Some(":t".into()),
..Default::default()
},
..Default::default()
})
.finish(); // <-- the method I'd like
tokio::spawn(async move {
tokio::signal::ctrl_c()
.await
.expect("Could not register ctrl+c handler");
framework.shard_manager().lock().await.shutdown_all().await; // uses framework
});
if let Err(why) = framework.start().await { // uses framework
error!("Client error: {:?}", why);
}
}
Hopefully this clarifies the case for such a method. If I missed something and this can already be done please point me to it. Otherwise I can try to whip a PR for this.
Probably should just forbid special characters in keys
the docs link https://kangalioo.github.io/poise/poise/ is broken
If a context menu command is registered, it will not show up in help, even if it's also allowed to run as a slash or prefix command, though, that should probably not matter and show up anyway.
/// Test
#[poise::command(context_menu_command = "Test", slash_command, prefix_command)]
pub async fn test(
ctx: Context<'_>,
#[description = "test"] _user: User,
) -> CommandResult {
Ok(())
}
Commands:
/help Show this menu
Test bottom text
Running /help test
doesn't work either, saying "No such command test
"
I run a fairly extensive set of lints on my projects. Since updating Poise from 2746481 to 6010651, I've found that the lint clippy::str_to_string
warns for commands that have String
arguments.
#![warn(clippy::str_to_string)]
#[command(prefix_command)]
pub async fn some_command(
ctx: PoiseContext<'_>,
#[rest]
#[description = "Some description."]
command: String,
) -> Result<(), Error> {
Ok(())
}
Warns with the following error:
warning: `to_string()` called on a `&str`
--> src\commands\mod.rs:40:1
|
40 | #[command(prefix_command)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using `.to_owned()`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
= note: this warning originates in the macro `$crate::_parse_prefix` (in Nightly builds, run with -Z macro-backtrace for more info)
It seems to only be with prefix_command
, not slash_command
. Not a huge deal at all, but I thought I'd mention it.
Is there a pattern for creating long-standing component interactions that will persist across instances of the bot?
The only example I can find of component interactions is this one. Unless I'm quite mistaken, because it awaits interactions in the command handler, if the bot is subsequently restarted the buttons will stop doing anything.
i have looked at the examples and the docs, but i was unable to find anything about it, i have seen how to add descriptions to arguments, but cant find anything about the slash command itself.
In updating my bot to the latest versions of dependencies, I encountered a build error with Poise:
error[E0433]: failed to resolve: could not find `sync` in `once_cell`
--> C:\Users\Zacc\.cargo\git\checkouts\poise-2ca7e75d46548da7\e94eb68\src\framework\mod.rs:14:27
|
14 | user_data: once_cell::sync::OnceCell<U>,
| ^^^^ could not find `sync` in `once_cell`
error[E0433]: failed to resolve: could not find `sync` in `once_cell`
--> C:\Users\Zacc\.cargo\git\checkouts\poise-2ca7e75d46548da7\e94eb68\src\framework\mod.rs:76:41
|
76 | user_data: once_cell::sync::OnceCell::new(),
| ^^^^^^^^ not found in `once_cell::sync`
|
help: consider importing one of these items
|
6 | use core::lazy::OnceCell;
|
6 | use once_cell::unsync::OnceCell;
|
6 | use std::lazy::OnceCell;
|
6 | use tokio::sync::OnceCell;
|
I'm almost certain it's because of commit 9243918, which removed the default features for dependencies and therefore removed the std
feature in once_cell
.
I've tested this in a blank new project and the sync
module is not available without the std
feature.
Thank you for your work on this framework.
What do you think about introducing a macro like the following:
macro_rules! add_commands {
($framework_builder:ident, $($command:path),*) => {{
$($framework_builder = $framework_builder.command($command(), |f| f);)*
$framework_builder
}};
}
This would allow one to do:
let mut framework_builder = poise::Framework::build();
framework_builder = add_commands!(
framework_builder,
help,
register,
command1,
command2
);
let framework = framework_builder.build().await.unwrap();
This is what I currently do with my bot to cut down on the number of .command(command1, |f| f)
calls. This would fit well alongside the already existing builtins
I think.
Serenity's CreateMessage
struct has the set_embed(embed: CreateEmbed)
API when poise only has embed(embed: &mut CreateEmbed)
. While taking a mutable reference can be useful it also causes some lifetime issues. Consider the following code:
pub type Context<'a> = poise::Context<'a, GlobalData, BotError>;
fn some_func(ctx: Context<'_>) {
//embed is bound to the scope of the function
let mut embed = CreateEmbed::default();
// but we make a ref out of it
ctx.send(|r| r.embed(|e| &mut embed)).await;
//then we want to send it again
ctx.send(|r| r.embed(|e| &mut embed)).await;
As you can see this doesn't work because embed
doesn't live long enough since it's bound to the scope's lifetime (not sure about the wording, I'm still pretty new to lifetimes ^^). Of course I could just move the entire embed creation process within the closure but that can be hard to follow and more importantly it means I can't just clone()
the CreateEmbed
if I want to send it again!
If I'm not just missing something I'd like there to be a set_embed
API that takes an owned CreateEmbed
.
It counts non slash commands too
I get this error when I try to run the Quickstart (I've already setted the env variable)
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Gateway(DisallowedGatewayIntents)', src\main.rs:43:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\learn_rust.exe` (exit code: 101)
This is a pretty useful thing to have for developing a bot. If it exists in this library, I haven't found it. The main crate doc page mentions the differences between local and global commands, but I haven't found a way to register guild-specific commands other than manually going through the register_application_commands_buttons()
dialog.
Please let me know if I'm missing something or misunderstanding this.
Thanks!
Is it possible to access message attachments from within a command (using PoiseContext
)?
I took a look through the available API and didn't see anything, but perhaps I missed something.
Because of the situation I'm working in, a library not having a LICENSE generally stokes concerns over whether or not it's fair game to use (since we're developing in a professional context).
So adding a LICENSE file would probably be helpful.
I'm trying to send a DM to a user provided in a command but user.create_dm_channel();
and user.direct_message();
both require a CacheHttp object. Looking through the docs and the examples I don't see any mention of this.
Could you add some examples on how to use those functions in the docs and in this issue for me too please.
Currently the checks field accepts a string with the name of the function to act as a check. This does not presently allow for multiple checks to be implemented.
I used to use serenity's thread_update
function in the event handler struct for this purpose. I tried using the ChannelUpdate
event for this, but it seems to not be called for threads.
This would allow definition of the permissions the bot user must have for a command to execute, if not met, pass an error to on_error.
In order to reduce 403s in the command body, or repeated code to handle checking permissions and displaying friendly errors, it would allow the user to centralize it in on_error. I personally use discord.py
's @commands.bot_required_permissions
extensively to define basic permissions such as send_messages, embed_links, or similar.
Currently, specifying subcommands requires you to manually insert them into the Command struct, commonly done via
Command {
subcommands: vec![a(), b(), c()],
..foo()
}
which is quite cumbersome, especially if you're splitting up your commands into separate modules.
To improve this, I'd propose adding a subcommands
attribute to the poise::command
macro, which would allow specifying subcommands on the parent command like this:
#[poise::command(
slash_command,
subcommands(a, b, c)
]
pub fn foo(_: Context<'_>) -> Result<(), Error> {
Ok(())
}
Currently, Commands are relatively limited in the amount of metadata you can provide to them.
There's the help-fields and the category, but both of those have specific usecases and are limited in what they can and should store.
It would be useful to be able to store arbitrary additional information together with the command declaration, thus allowing users of poise to implement their own system for keeping track of things such as specific permission requirements, additional help-data (i.e. usage examples, etc) and many other things.
After a short discussion of this in the serenity discord server, we came to the conclusion that it'd make sense to provide a custom_data
field in the poise::command
macro, which could store any user-provided struct together with the command, via a Box<dyn Any>
.
I.e.:
#[poise::command(
slash_command,
custom_data=r#"CmdData { perm_level: PermissionLevel::Helpers, example: "/mute someguy 10m" }"#
)]
pub async fn mute(...) -> Result<()> {
...
}
The serenity repo has a very extensive example for their command framework. The later not only makes use of many of the framework's features but also gives many hints as to what is what and how to use the features.
I know poise
is still far from done but I'm thinking trying to port this example may help drive it forward and improve user adoption. This would also alleviate the sometimes lacking documentation.
First of, the existing API for auto completion is incredible, thank you so much for that ❤️. While implementing a command with a parameter that can be auto-filled either with values based on the current user or filled with values based on a member supplied in an extra parameter, I thought it would be great if I could access this member
parameter in the auto complete function.
As far as I understand the discord documentation, in the auto complete event, everything is sent, not just the current/focused parameter. It would be great if the framework could take advantage of that maybe with an autocomplete function for the whole command instead of functions for each parameter.
Looking through the code, it doesn't seem like support for add_string_choice
has been implemented. Is this correct or have I missed it? I'd like to give users choices when entering slash commands.
Hello good night, could you help me? I'm trying to use the event handler but for some functions for example add role I need the new member to be mutable, but from what I noticed the event cannot be mutable, would you have any solution?
temporary solution:
Event::GuildMemberAddition { new_member } => {
let roles = new_member.guild_id.roles(ctx).await.map_app_err()?;
let role = roles.iter().find(|x| x.1.name == "alguma coisa");
let role = role.unwrap();
let mut member = new_member.clone();
member.add_role(ctx, role.0).await.map_app_err()?;
}
That is about it, the Ready
value in user_data_setup
which I presume could be used for a ready function to report that the bot has logged in, has the guild I am testing in reported as unavailable like this:
guilds: [UnavailableGuild { id: GuildId(<The id for the guild>), unavailable: true }]
With the serenity standard framework this worked fine. Also it is not only slash commands that do not work, I can not use the register
provided by examples or help
.
Running the example seems to fail:
error[E0433]: failed to resolve: could not find `CollectComponentInteraction` in `serenity`
--> examples/framework_usage/commands.rs:113:37
|
113 | while let Some(mci) = serenity::CollectComponentInteraction::new(ctx.discord())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not find `CollectComponentInteraction` in `serenity`
For more information about this error, try `rustc --explain E0433`.
error: could not compile `poise` due to previous error```
Adding the custom event handler itself seems to work fine, but the problem arises when I need to use some of the values in the Data
struct. Namely a connection to a database. I need the connection to the database to be available for both commands and said interactions, and with using serenity's TypeMap for storing it would mean I would need to store it 2 times. Is there any other way to do this?
I'm certain that this problem is because of my lack of understanding rust that's why I'm sry for being so impudent to open an issue.
I wanted to use Songbird alongside poise to handle voice for discord, but Songbird needs to be registered at startup as VoiceGatewayManager which is done with ClientBuilder#voice_manager_arc. The method expects a struct with poise::serenity_prelude::VoiceGatewayManager
implemented but Songbird doesn't use the re-exports and implements serenity::client::bridge::voice::VoiceGatewayManager
. I also had to enable the feature voice
for serenity in poise to be able to use ClientBuilder#voice_manager_arc.
Is there a simple way to tell the compiler that poise::serenity_prelude::VoiceGatewayManager
and serenity::client::bridge::voice::VoiceGatewayManager
are the same?
poise::samples::register_application_commands
will say "Can only be used by bot owner" if the owner of the bot is a team. FrameworkOptions.owners
should be a HashSet of every admin member of the team.
After updating Poise and Serenity to their latest versions (using #60 for now, but I doubt that's the culprit) I've found that the bot doesn't recognise any prefix commands.
The prefix is set using the PrefixFrameworkOptions
, and is set to -
. I'm testing it on Linux x64. If you need any more information please let me know, but I'm hoping this will be easily reproducible.
I'm raising this issue here instead of with Serenity because if I'm not mistaken, Poise is doing the parsing. If I'm wrong or it's my fault in some way, please let me know.
Current behaviour: When the command has defer_response
enabled, chained methods such as .components()
, ephemeral(true)
, etc get ignored when using slash commands but work fine when using prefix commands.
Expected behaviour: Chained methods of CreateReply
such as .components()
and .ephemeral()
should not be ignored and work as they do when defer_response
is disabled.
poise::send_reply(ctx, |message| {
message
.embed(|embed| {
// ... create the embed
embed
})
.components(|components| { // components are not shown with defer_response enabled
debug!("Creating components..."); // this does get executed
// ... create components
})
.ephemeral(true) // this gets ignored when defer_response is enabled
})
.await?;
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.