update how configuring works

This commit is contained in:
Gabriel Fontes
2023-06-11 15:41:55 -03:00
parent c808e5f480
commit e147916d27
10 changed files with 338 additions and 149 deletions

View File

@@ -1,83 +0,0 @@
use anyhow::{Context as ErrContext, Result};
use serenity::{
client::Client as DiscordClient,
framework::standard::StandardFramework,
prelude::{GatewayIntents, TypeMapKey},
};
use songbird::SerenityInit;
use sunk::Client as SubsonicClient;
use std::{env, fs, io};
use crate::discord::{after_hook, Handler, GENERAL_GROUP};
pub struct Client {
ss_url: String,
ss_user: String,
ss_password: String,
discord_token: String,
}
impl Client {
pub async fn from_env() -> Result<Self> {
// Convert to std::io::Error, allowing usage of and_then
let convert_err = |e| io::Error::new(io::ErrorKind::Other, e);
let ss_url = env::var("SUBSONIC_URL")?;
let ss_user = env::var("SUBSONIC_USER")?;
let ss_password = env::var("SUBSONIC_PASSWORD").or_else(|_| {
env::var("SUBSONIC_PASSWORD_FILE")
.map_err(convert_err)
.and_then(fs::read_to_string)
.map(|s| s.trim().to_owned())
})?;
let discord_token = env::var("DISCORD_TOKEN").or_else(|_| {
env::var("DISCORD_TOKEN_FILE")
.map_err(convert_err)
.and_then(fs::read_to_string)
.map(|s| s.trim().to_owned())
})?;
Ok(Self {
ss_url,
ss_user,
ss_password,
discord_token,
})
}
pub async fn discord(&self, ss: SubsonicClient) -> Result<DiscordClient> {
let intents = GatewayIntents::non_privileged() | GatewayIntents::MESSAGE_CONTENT;
let framework = StandardFramework::new()
.group(&GENERAL_GROUP)
.after(after_hook);
framework.configure(|c| c.prefix("~"));
let client = DiscordClient::builder(&self.discord_token, intents)
.event_handler(Handler)
.framework(framework)
.type_map_insert::<MusicClient>(ss)
.register_songbird()
.await?;
Ok(client)
}
pub async fn subsonic(&self) -> Result<SubsonicClient> {
let client = SubsonicClient::new(&self.ss_url, &self.ss_user, &self.ss_password)?;
log::info!("Created subsonic client: {client:?}");
// Check that connection works
client
.ping()
.await
.with_context(|| "Could not connect to subsonic server.")?;
Ok(client)
}
}
pub struct MusicClient;
impl TypeMapKey for MusicClient {
type Value = SubsonicClient;
}

67
src/config.rs Normal file
View File

@@ -0,0 +1,67 @@
use crate::handles::SubsonicClientHandle;
use anyhow::{Context as ErrContext, Result};
use clap::Parser;
use log::LevelFilter;
use serenity::{
client::Client as DiscordClient, framework::standard::StandardFramework,
prelude::GatewayIntents,
};
use simple_logger::SimpleLogger;
use songbird::SerenityInit;
use sunk::Client as SubsonicClient;
use crate::discord::{after_hook, Handler, GENERAL_GROUP};
#[derive(Parser, Clone)]
pub struct Config {
#[clap(long, env = "DISCONIC_SUBSONIC_URL")]
subsonic_url: String,
#[clap(long, env = "DISCONIC_SUBSONIC_USER")]
subsonic_user: String,
#[clap(long, env = "DISCONIC_SUBSONIC_PASSWORD")]
subsonic_password: String,
#[clap(long, env = "DISCONIC_DISCORD_TOKEN")]
discord_token: String,
#[clap(long, env = "DISCONIC_LOG_LEVEL", default_value = "warn")]
log_level: LevelFilter,
}
impl Config {
pub async fn discord(&self, ss: SubsonicClient) -> Result<DiscordClient> {
let intents = GatewayIntents::non_privileged() | GatewayIntents::MESSAGE_CONTENT;
let framework = StandardFramework::new()
.group(&GENERAL_GROUP)
.after(after_hook);
framework.configure(|c| c.prefix("~"));
let client = DiscordClient::builder(&self.discord_token, intents)
.event_handler(Handler)
.framework(framework)
.type_map_insert::<SubsonicClientHandle>(ss)
.register_songbird()
.await?;
Ok(client)
}
pub async fn subsonic(&self) -> Result<SubsonicClient> {
let client = SubsonicClient::new(
&self.subsonic_url,
&self.subsonic_user,
&self.subsonic_password,
)?;
log::info!("Created subsonic client: {client:?}");
// Check that connection works
client
.ping()
.await
.with_context(|| "Could not connect to subsonic server.")?;
Ok(client)
}
pub fn logger(&self) -> SimpleLogger {
SimpleLogger::new().with_level(self.log_level)
}
}

View File

@@ -8,7 +8,6 @@ use serenity::{
Args, CommandResult,
},
model::{channel::Message, gateway::Ready},
prelude::TypeMapKey,
utils::MessageBuilder,
};
use songbird::{
@@ -25,7 +24,7 @@ use tokio::sync::Mutex;
use std::sync::Arc;
use crate::MusicClient;
use crate::handles::{SubsonicClientHandle, SubsonicSongHandle};
#[group]
#[commands(
@@ -38,7 +37,7 @@ pub struct Handler;
#[async_trait]
impl EventHandler for Handler {
async fn ready(&self, _: Context, ready: Ready) {
println!("{} is connected!", ready.user.name);
log::info!("{} is connected!", ready.user.name);
}
}
@@ -76,7 +75,7 @@ async fn join(ctx: &Context, msg: &Message) -> CommandResult {
async fn song(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let data = ctx.data.read().await;
let music_client = data
.get::<MusicClient>()
.get::<SubsonicClientHandle>()
.expect("Couldn't retrieve music client");
let search_size = SearchPage::new().with_size(1);
@@ -114,7 +113,7 @@ async fn song(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
async fn album(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let data = ctx.data.read().await;
let music_client = data
.get::<MusicClient>()
.get::<SubsonicClientHandle>()
.expect("Couldn't retrieve music client");
let search_size = SearchPage::new().with_size(1);
@@ -153,7 +152,7 @@ async fn album(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
async fn random(ctx: &Context, msg: &Message) -> CommandResult {
let data = ctx.data.read().await;
let music_client = data
.get::<MusicClient>()
.get::<SubsonicClientHandle>()
.expect("Couldn't retrieve music client");
let result = Song::random(music_client, 1).await?;
@@ -334,11 +333,6 @@ async fn remove(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
// ==========================
// ==========================
struct SongHandler;
impl TypeMapKey for SongHandler {
type Value = Song;
}
async fn queue_song(
ctx: &Context,
msg: &Message,
@@ -351,7 +345,7 @@ async fn queue_song(
let track = load_song(song, client).await?;
let track_handle = handler.enqueue(track).await;
let mut type_map = track_handle.typemap().write().await;
type_map.insert::<SongHandler>(song.clone());
type_map.insert::<SubsonicSongHandle>(song.clone());
Ok(())
}
@@ -394,7 +388,7 @@ async fn get_song(track: &TrackHandle) -> Result<Song> {
.typemap()
.read()
.await
.get::<SongHandler>()
.get::<SubsonicSongHandle>()
.map(ToOwned::to_owned)
.ok_or_else(|| anyhow!("Sound information not found"))?;
Ok(song)

12
src/handles.rs Normal file
View File

@@ -0,0 +1,12 @@
use serenity::prelude::TypeMapKey;
use sunk::{song::Song as SubsonicSong, Client as SubsonicClient};
pub struct SubsonicClientHandle;
impl TypeMapKey for SubsonicClientHandle {
type Value = SubsonicClient;
}
pub struct SubsonicSongHandle;
impl TypeMapKey for SubsonicSongHandle {
type Value = SubsonicSong;
}

View File

@@ -1,4 +1,3 @@
pub mod client;
pub use client::{Client, MusicClient};
pub mod config;
pub mod discord;
pub mod handles;

View File

@@ -1,16 +1,18 @@
use anyhow::Result;
use clap::Parser;
use disconic::Client;
use disconic::config::Config;
#[tokio::main]
async fn main() -> Result<()> {
dotenv::dotenv().ok();
env_logger::init();
let client = Client::from_env().await?;
let subsonic = client.subsonic().await?;
let mut discord = client.discord(subsonic).await?;
let config = Config::parse();
let logger = config.logger();
let subsonic = config.subsonic().await?;
let mut discord = config.discord(subsonic).await?;
logger.init()?;
discord.start().await?;
Ok(())