map of server

This commit is contained in:
Oliver Atkinson 2024-07-23 11:13:07 -06:00
parent e0a9f957a5
commit 67ee89bad9
5 changed files with 916 additions and 504 deletions

1153
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
[package]
name = "REPO-NAME"
name = "discord_egress"
authors = ["Oliver", "Oliver"]
description = "egress a discord server"
repository = "https://git.oliveratkinson.net/Oliver/discord-egress.git"
@ -11,9 +11,6 @@ edition = "2021"
[dependencies]
tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] }
# songbird = { version = "0.3.2", features = ["yt-dlp"] }
poise = { version = "0.5.7", features = ["cache"] }
poise = { version = "0.6", features = ["cache"] }
dotenv = "0.15.0"
anyhow = "1.0.75"
url = "2.4.1"
async-recursion = "1.0.5"

View File

@ -3,15 +3,13 @@ FROM rustlang/rust:nightly as builder
ENV RUSTFLAGS=""
WORKDIR /bot
# RUN apt-get update && apt-get upgrade -y
COPY . .
RUN cargo build --release
# Now make the runtime container
FROM debian:bookworm-slim
RUN apt-get update && apt-get upgrade -y && apt-get clean
COPY --from=builder /bot/target/release/REPO-NAME /usr/local/bin/REPO-NAME
COPY --from=builder /bot/target/release/discord_egress /usr/local/bin/discord_egress
COPY Cargo.lock /
CMD ["/usr/local/bin/REPO-NAME"]
CMD ["/usr/local/bin/discord_egress"]

View File

@ -1,17 +1,171 @@
use std::hint::black_box;
use anyhow::Error;
use crate::Context;
use std::fmt::Display;
// NOTE!!! Make sure these names in quotes are lowercase!
#[poise::command(slash_command, rename = "cmd_name", guild_only)]
pub async fn example(
ctx: Context<'_>,
#[description = "cmd_desc"]
input: String
) -> Result<(), Error> {
// Do something...
black_box(ctx);
black_box(input);
Ok(())
use crate::Context;
use anyhow::Error;
use poise::serenity_prelude::{ChannelId, ChannelType, GuildChannel};
struct Server {
channels: Vec<Channel>,
orphanage: Vec<GuildChannel>,
needs_clean: bool,
}
struct Channel {
this: GuildChannel,
children: Vec<Channel>
}
impl Display for Server {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn print(f: &mut std::fmt::Formatter<'_>, tab: usize, channel: &Vec<Channel>) {
for i in channel {
for _ in 0..tab { let _ = write!(f, "\t"); }
let _ = writeln!(f, "{} {}", prefix(i.this.kind),i.this.name);
print(f, tab+1, &i.children);
}
}
fn prefix(kind: ChannelType) -> &'static str {
match kind {
poise::serenity_prelude::ChannelType::Text => "💬",
poise::serenity_prelude::ChannelType::Private => "🕵️",
poise::serenity_prelude::ChannelType::Voice => "🔊",
poise::serenity_prelude::ChannelType::GroupDm => "👨‍👦‍👦",
poise::serenity_prelude::ChannelType::Category => "📁",
poise::serenity_prelude::ChannelType::News => "📢",
poise::serenity_prelude::ChannelType::NewsThread => "📢🧵",
poise::serenity_prelude::ChannelType::PublicThread => "🧵",
poise::serenity_prelude::ChannelType::PrivateThread => "🕵️🧵",
poise::serenity_prelude::ChannelType::Stage => "🎙️",
poise::serenity_prelude::ChannelType::Directory => "📒",
poise::serenity_prelude::ChannelType::Forum => "🗣️",
_ => "?",
}
}
print(f, 0, &self.channels);
if self.needs_clean {
let _ = writeln!(f, "Orphans: (please clean() before displaying...)");
for i in &self.orphanage {
let _ = write!(f, "{} {},", prefix(i.kind),i.name);
}
}
write!(f, "")
}
}
impl Server {
fn new() -> Self {
Self {
channels: Vec::new(),
orphanage: Vec::new(),
needs_clean: false
}
}
// TODO this might be broken
fn search<'a>(target: &'a mut Vec<Channel>, find: &ChannelId) -> Option<&'a mut Channel> {
for child in target {
if child.this.id == *find {
return Some(child);
}
match Self::search(&mut child.children, find) {
Some(x) => return Some(x),
None => {},
}
}
None
}
fn add(&mut self, insert: GuildChannel) {
// make sure the new item wants a parent
if let Some(parent_id) = &insert.parent_id {
// find the parent (needs to go thru all nodes)
match Self::search(&mut self.channels, &parent_id) {
Some(parent_node) => {
parent_node.children.push(Channel { this: insert, children: Vec::new() });
},
None => {
// couldn't find parent, store somewhere else until it's parent is added...
self.orphanage.push(insert);
self.needs_clean = true;
},
}
} else {
self.channels.push(Channel { this: insert, children: Vec::new() })
}
}
fn clean(&mut self) {
if !self.needs_clean {return;}
// Look thru the orphanage and try to find parents
for orphan in &self.orphanage {
if let Some(parent_id) = orphan.parent_id {
if let Some(found) = Self::search(&mut self.channels, &parent_id) {
found.children.push(Channel { this: orphan.clone(), children: Vec::new() });
} else {
panic!("⚠️ Couldn't find parent for orphan!");
}
} else {
panic!("⚠️ All orphans should want a parent node!");
}
}
self.orphanage.clear();
self.needs_clean = false;
}
}
// NOTE!!! Make sure these names in quotes are lowercase!
#[poise::command(slash_command, rename = "index", guild_only)]
pub async fn index(ctx: Context<'_>) -> Result<(), Error> {
let guild = ctx.guild_id().unwrap().to_partial_guild(ctx.serenity_context()).await.unwrap();
match guild.channels(ctx.http()).await {
Ok(ok) => {
let mut server = Server::new();
// iterate thru all channels
ok.into_iter().for_each(|(_id, current)| {
match current.kind {
poise::serenity_prelude::ChannelType::Text => {
server.add(current);
// current.position,
},
poise::serenity_prelude::ChannelType::Private => todo!(),
poise::serenity_prelude::ChannelType::Voice => {
server.add(current);
// current.user_limit,
// current.parent_id,
},
poise::serenity_prelude::ChannelType::GroupDm => todo!(),
poise::serenity_prelude::ChannelType::Category => {
server.add(current);
},
poise::serenity_prelude::ChannelType::News => todo!(),
poise::serenity_prelude::ChannelType::NewsThread => todo!(),
poise::serenity_prelude::ChannelType::PublicThread => todo!(),
poise::serenity_prelude::ChannelType::PrivateThread => todo!(),
poise::serenity_prelude::ChannelType::Stage => todo!(),
poise::serenity_prelude::ChannelType::Directory => todo!(),
poise::serenity_prelude::ChannelType::Forum => todo!(),
poise::serenity_prelude::ChannelType::Unknown(_) => todo!(),
_ => todo!(),
}
});
server.clean();
println!("{}", server);
},
Err(_) => todo!(),
}
Ok(())
}

View File

@ -10,81 +10,39 @@ async fn main() {
// Generate sick text like this:
// http://www.patorjk.com/software/taag/#p=testall&f=Graffiti&t=hello%20world
println!(r#"
/$$$$$$$$ /$$ /$$ /$$$$$$$ /$$
|__ $$__/ | $$ | $$ | $$__ $$ | $$
| $$ /$$$$$$ /$$$$$$/$$$$ /$$$$$$ | $$ /$$$$$$ /$$$$$$ /$$$$$$ | $$ \ $$ /$$$$$$ /$$$$$$
| $$ /$$__ $$| $$_ $$_ $$ /$$__ $$| $$ |____ $$|_ $$_/ /$$__ $$ | $$$$$$$ /$$__ $$|_ $$_/
| $$| $$$$$$$$| $$ \ $$ \ $$| $$ \ $$| $$ /$$$$$$$ | $$ | $$$$$$$$ | $$__ $$| $$ \ $$ | $$
| $$| $$_____/| $$ | $$ | $$| $$ | $$| $$ /$$__ $$ | $$ /$$| $$_____/ | $$ \ $$| $$ | $$ | $$ /$$
| $$| $$$$$$$| $$ | $$ | $$| $$$$$$$/| $$| $$$$$$$ | $$$$/| $$$$$$$ | $$$$$$$/| $$$$$$/ | $$$$/
|__/ \_______/|__/ |__/ |__/| $$____/ |__/ \_______/ \___/ \_______/ |_______/ \______/ \___/
| $$
| $$
|__/
Template Bot.
Invite this bot with:
"#);
println!("https://discord.com/api/oauth2/authorize?client_id={}&permissions={}&scope=bot",
env.id,
env.intents.bits(),
);
print!("\n");
// Setup framework
let framework = poise::Framework::builder()
.options(poise::FrameworkOptions {
commands: vec![
command::example(),
command::index(),
],
..Default::default()
})
// un-comment songbird from Cargo.toml first.
//.client_settings(songbird::register)
.token(env.token)
.intents(env.intents)
.setup(|ctx, _ready, framework| {
Box::pin(async move {
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
poise::builtins::register_globally(
ctx,
&framework.options().commands
).await?;
Ok(Data {})
})
});
// Start the Bot.
// Collect all the errors into one variable, that way we can match it
// all at once.
let err: Result<(), serenity::Error> = match framework.build().await {
Ok(ok) => {
match ok.start().await {
Ok(_start) => Ok(()),
Err(err) => Err(err),
}
},
Err(err) => Err(err),
};
})
.build();
if let Err(error) = err {
match error {
serenity::Error::Gateway(e)=>{
match e {
serenity::GatewayError::InvalidAuthentication => println!("ERROR: Authentication Invalid, check your bot token."),
err_no_var=>println!("ERROR: {}",err_no_var.to_string()),
}
},
serenity::Error::Decode(_, _) => println!("ERROR: Decode"),
serenity::Error::Format(_) => println!("ERROR: Format"),
serenity::Error::Io(_) => println!("ERROR: IO"),
serenity::Error::Json(_) => println!("ERROR: Json"),
serenity::Error::Model(_) => println!("ERROR: Model"),
serenity::Error::ExceededLimit(_, _) => println!("ERROR: ExceededLimit"),
serenity::Error::NotInRange(_, _, _, _) => println!("ERROR: NotInRange"),
serenity::Error::Other(_) => println!("ERROR: Other"),
serenity::Error::Url(_) => println!("ERROR: Url"),
serenity::Error::Client(_) => println!("ERROR: Client"),
serenity::Error::Collector(_) => println!("ERROR: Collector"),
serenity::Error::Http(_) => println!("ERROR: Http"),
serenity::Error::Tungstenite(_) => println!("ERROR: Tungstenite"),
_ => todo!(),
}
}
// Start the Bot.
let client = serenity::ClientBuilder::new(env.token, env.intents)
.framework(framework)
.await;
client.unwrap().start().await.unwrap();
}
struct BotEnv {