rustfmt, some minor logging additions
This commit is contained in:
parent
a7b9487c38
commit
7490df1c91
|
@ -1,6 +1,9 @@
|
||||||
use arrayvec::{ArrayString, CapacityError};
|
use arrayvec::{ArrayString, CapacityError};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::{error::Error, fmt::{Debug, Display}};
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
fmt::{Debug, Display},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LeekCapacityError(CapacityError);
|
pub struct LeekCapacityError(CapacityError);
|
||||||
|
@ -19,7 +22,6 @@ impl<T> From<CapacityError<T>> for LeekCapacityError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type LeekResult = Result<ArrayString<512>, LeekCapacityError>;
|
type LeekResult = Result<ArrayString<512>, LeekCapacityError>;
|
||||||
|
|
||||||
pub fn mock(input: &str) -> LeekResult {
|
pub fn mock(input: &str) -> LeekResult {
|
||||||
|
@ -99,4 +101,3 @@ pub fn owoify(input: &str) -> LeekResult {
|
||||||
builder.try_push_str("~~")?;
|
builder.try_push_str("~~")?;
|
||||||
Ok(builder)
|
Ok(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use arrayvec::ArrayString;
|
use arrayvec::ArrayString;
|
||||||
use meval::Context;
|
use meval::Context;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LeekCommand {
|
||||||
|
Owo,
|
||||||
|
Leet,
|
||||||
|
Mock,
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_waifu_pic(category: &str) -> anyhow::Result<Option<String>> {
|
pub async fn get_waifu_pic(category: &str) -> anyhow::Result<Option<String>> {
|
||||||
let api_resp = reqwest::get(format!("https://api.waifu.pics/sfw/{}", category))
|
let api_resp = reqwest::get(format!("https://api.waifu.pics/sfw/{}", category))
|
||||||
.await?
|
.await?
|
||||||
|
@ -15,16 +22,47 @@ pub async fn get_waifu_pic(category: &str) -> anyhow::Result<Option<String>> {
|
||||||
Ok(url)
|
Ok(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mathbot(author: String, expr: Option<&str>, last_evals: &mut HashMap<String, f64>) -> anyhow::Result<ArrayString<256>> {
|
pub fn mathbot(
|
||||||
|
author: String,
|
||||||
|
expr: Option<&str>,
|
||||||
|
last_evals: &mut HashMap<String, f64>,
|
||||||
|
) -> anyhow::Result<ArrayString<256>> {
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
let last_eval = last_evals.entry(author).or_insert(0.0);
|
let last_eval = last_evals.entry(author).or_insert(0.0);
|
||||||
let mut meval_ctx = Context::new();
|
let mut meval_ctx = Context::new();
|
||||||
let mut result = ArrayString::new();
|
let mut result = ArrayString::new();
|
||||||
let value = meval::eval_str_with_context(expr, meval_ctx.var("x", *last_eval))?;
|
let value = meval::eval_str_with_context(expr, meval_ctx.var("x", *last_eval))?;
|
||||||
*last_eval = value;
|
*last_eval = value;
|
||||||
|
tracing::debug!("{} = {}", expr, value);
|
||||||
write!(result, "{} = {}", expr, value)?;
|
write!(result, "{} = {}", expr, value)?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
} else {
|
} else {
|
||||||
Ok(ArrayString::from("No expression to evaluate")?)
|
Ok(ArrayString::from("No expression to evaluate")?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn execute_leek(
|
||||||
|
state: &mut crate::AppState,
|
||||||
|
cmd: LeekCommand,
|
||||||
|
channel: &str,
|
||||||
|
nick: &str,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
match state.last_msgs.get(nick) {
|
||||||
|
Some(msg) => {
|
||||||
|
tracing::debug!("Executing {:?} on {:?}", cmd, msg);
|
||||||
|
let output = match cmd {
|
||||||
|
LeekCommand::Owo => super::leek::owoify(msg)?,
|
||||||
|
LeekCommand::Leet => super::leek::leetify(msg)?,
|
||||||
|
LeekCommand::Mock => super::leek::mock(msg)?,
|
||||||
|
};
|
||||||
|
state.client.privmsg(channel, &output).await?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
state
|
||||||
|
.client
|
||||||
|
.privmsg(channel, "No last messages found.")
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
pub mod leek;
|
pub mod leek;
|
||||||
pub mod title;
|
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
pub mod sed;
|
pub mod sed;
|
||||||
|
pub mod title;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{fmt::Display, error::Error};
|
use std::{error::Error, fmt::Display};
|
||||||
|
|
||||||
use arrayvec::{ArrayString, CapacityError};
|
use arrayvec::{ArrayString, CapacityError};
|
||||||
use fancy_regex::Regex;
|
use fancy_regex::Regex;
|
||||||
|
@ -9,7 +9,7 @@ use sedregex::find_and_replace;
|
||||||
pub enum SedError {
|
pub enum SedError {
|
||||||
Capacity(CapacityError),
|
Capacity(CapacityError),
|
||||||
Regex(fancy_regex::Error),
|
Regex(fancy_regex::Error),
|
||||||
SedRegex(sedregex::ErrorKind)
|
SedRegex(sedregex::ErrorKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for SedError {
|
impl Display for SedError {
|
||||||
|
@ -56,8 +56,8 @@ pub fn resolve(prev_msg: &str, cmd: &str) -> SedResult {
|
||||||
Ok(Some(ArrayString::from(&formatted)?))
|
Ok(Some(ArrayString::from(&formatted)?))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,8 @@ async fn resolve_spotify(
|
||||||
// }
|
// }
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
"Resolving Spotify resource '{}' with id '{}'",
|
"Resolving Spotify resource '{}' with id '{}'",
|
||||||
resource_type, resource_id
|
resource_type,
|
||||||
|
resource_id
|
||||||
);
|
);
|
||||||
match resource_type {
|
match resource_type {
|
||||||
"track" => {
|
"track" => {
|
||||||
|
@ -89,6 +90,7 @@ impl Titlebot {
|
||||||
r"(?:https?|spotify):(?://open\.spotify\.com/)?(track|artist|album|playlist)[/:]([a-zA-Z0-9]*)",
|
r"(?:https?|spotify):(?://open\.spotify\.com/)?(track|artist|album|playlist)[/:]([a-zA-Z0-9]*)",
|
||||||
)?;
|
)?;
|
||||||
let mut spotify = ClientCredsSpotify::new(spotify_creds);
|
let mut spotify = ClientCredsSpotify::new(spotify_creds);
|
||||||
|
|
||||||
spotify.request_token().await?;
|
spotify.request_token().await?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
url_regex,
|
url_regex,
|
||||||
|
@ -103,6 +105,7 @@ impl Titlebot {
|
||||||
tracing::debug!("{}", message);
|
tracing::debug!("{}", message);
|
||||||
let tp_group = m.get(1).unwrap();
|
let tp_group = m.get(1).unwrap();
|
||||||
let id_group = m.get(2).unwrap();
|
let id_group = m.get(2).unwrap();
|
||||||
|
|
||||||
return Ok(Some(
|
return Ok(Some(
|
||||||
resolve_spotify(
|
resolve_spotify(
|
||||||
&mut self.spotify,
|
&mut self.spotify,
|
||||||
|
@ -114,6 +117,7 @@ impl Titlebot {
|
||||||
} else if let Some(m) = self.url_regex.find(&message)? {
|
} else if let Some(m) = self.url_regex.find(&message)? {
|
||||||
let url = &message[m.start()..m.end()];
|
let url = &message[m.start()..m.end()];
|
||||||
tracing::debug!("url: {}", url);
|
tracing::debug!("url: {}", url);
|
||||||
|
|
||||||
let response = reqwest::get(url).await?;
|
let response = reqwest::get(url).await?;
|
||||||
if let Some(header) = response.headers().get("Content-Type") {
|
if let Some(header) = response.headers().get("Content-Type") {
|
||||||
tracing::debug!("response header: {}", header.to_str()?);
|
tracing::debug!("response header: {}", header.to_str()?);
|
||||||
|
@ -121,6 +125,7 @@ impl Titlebot {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = response.text().await?;
|
let body = response.text().await?;
|
||||||
if let Some(tm) = self.title_regex.find(&body)? {
|
if let Some(tm) = self.title_regex.find(&body)? {
|
||||||
let title_match = &body[tm.start()..tm.end()];
|
let title_match = &body[tm.start()..tm.end()];
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use rusqlite::{OptionalExtension, params};
|
use rusqlite::{params, OptionalExtension};
|
||||||
use tokio::sync::{mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, oneshot};
|
use tokio::sync::{
|
||||||
|
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
||||||
|
oneshot,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Task {
|
enum Task {
|
||||||
|
@ -17,8 +20,11 @@ impl DbExecutor {
|
||||||
pub fn create(dbpath: &str) -> rusqlite::Result<(Self, ExecutorConnection)> {
|
pub fn create(dbpath: &str) -> rusqlite::Result<(Self, ExecutorConnection)> {
|
||||||
let (tx, rx) = unbounded_channel();
|
let (tx, rx) = unbounded_channel();
|
||||||
let db = rusqlite::Connection::open(dbpath)?;
|
let db = rusqlite::Connection::open(dbpath)?;
|
||||||
db.execute("create table if not exists quotes(id integer primary key,\
|
db.execute(
|
||||||
username text not null, quote text not null)", [])?;
|
"create table if not exists quotes(id integer primary key,\
|
||||||
|
username text not null, quote text not null)",
|
||||||
|
[],
|
||||||
|
)?;
|
||||||
tracing::debug!("Database connected ({})", dbpath);
|
tracing::debug!("Database connected ({})", dbpath);
|
||||||
Ok((Self { rx, db }, ExecutorConnection { tx }))
|
Ok((Self { rx, db }, ExecutorConnection { tx }))
|
||||||
}
|
}
|
||||||
|
@ -28,7 +34,9 @@ impl DbExecutor {
|
||||||
match task {
|
match task {
|
||||||
Task::AddQuote(tx, quote, author) => {
|
Task::AddQuote(tx, quote, author) => {
|
||||||
if let Err(e) = self.db.execute(
|
if let Err(e) = self.db.execute(
|
||||||
"insert into quotes(quote,username) values(?,?)", params![quote,author]) {
|
"insert into quotes(quote,username) values(?,?)",
|
||||||
|
params![quote, author],
|
||||||
|
) {
|
||||||
tracing::error!("A database error has occurred: {}", e);
|
tracing::error!("A database error has occurred: {}", e);
|
||||||
tx.send(false).unwrap();
|
tx.send(false).unwrap();
|
||||||
} else {
|
} else {
|
||||||
|
@ -57,7 +65,9 @@ pub struct ExecutorConnection {
|
||||||
|
|
||||||
impl Clone for ExecutorConnection {
|
impl Clone for ExecutorConnection {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self { tx: self.tx.clone() }
|
Self {
|
||||||
|
tx: self.tx.clone(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
90
src/main.rs
90
src/main.rs
|
@ -1,20 +1,20 @@
|
||||||
mod bots;
|
mod bots;
|
||||||
mod database;
|
mod database;
|
||||||
|
|
||||||
|
use crate::database::{DbExecutor, ExecutorConnection};
|
||||||
use arrayvec::ArrayString;
|
use arrayvec::ArrayString;
|
||||||
use async_circe::{commands::Command, Client, Config};
|
use async_circe::{commands::Command, Client, Config};
|
||||||
use bots::title::Titlebot;
|
use bots::title::Titlebot;
|
||||||
use bots::{leek, misc, sed};
|
use bots::{misc, misc::LeekCommand, sed};
|
||||||
use rspotify::Credentials;
|
use rspotify::Credentials;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::fmt::Write;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::thread;
|
||||||
use std::{collections::HashMap, env};
|
use std::{collections::HashMap, env};
|
||||||
use tokio::select;
|
use tokio::select;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
use std::fmt::Write;
|
|
||||||
use std::thread;
|
|
||||||
use crate::database::{DbExecutor, ExecutorConnection};
|
|
||||||
|
|
||||||
// this will be displayed when the help command is used
|
// this will be displayed when the help command is used
|
||||||
const HELP: &[&str] = &[
|
const HELP: &[&str] = &[
|
||||||
|
@ -45,13 +45,13 @@ async fn terminate_signal() {
|
||||||
let _ = ctrlc.recv().await;
|
let _ = ctrlc.recv().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AppState {
|
pub struct AppState {
|
||||||
prefix: String,
|
prefix: String,
|
||||||
client: Client,
|
client: Client,
|
||||||
last_msgs: HashMap<String, String>,
|
last_msgs: HashMap<String, String>,
|
||||||
last_eval: HashMap<String, f64>,
|
last_eval: HashMap<String, f64>,
|
||||||
titlebot: Titlebot,
|
titlebot: Titlebot,
|
||||||
db: ExecutorConnection
|
db: ExecutorConnection,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -65,7 +65,7 @@ struct ClientConf {
|
||||||
spotify_client_id: String,
|
spotify_client_id: String,
|
||||||
spotify_client_secret: String,
|
spotify_client_secret: String,
|
||||||
prefix: String,
|
prefix: String,
|
||||||
db_path: Option<String>
|
db_path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
|
@ -74,13 +74,15 @@ async fn main() -> anyhow::Result<()> {
|
||||||
.with_env_filter(EnvFilter::from_env("UBERBOT_LOG"))
|
.with_env_filter(EnvFilter::from_env("UBERBOT_LOG"))
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let mut file = File::open(env::var("UBERBOT_CONFIG").unwrap_or_else(|_| "uberbot.toml".to_string()))?;
|
let mut file =
|
||||||
|
File::open(env::var("UBERBOT_CONFIG").unwrap_or_else(|_| "uberbot.toml".to_string()))?;
|
||||||
let mut client_conf = String::new();
|
let mut client_conf = String::new();
|
||||||
file.read_to_string(&mut client_conf)?;
|
file.read_to_string(&mut client_conf)?;
|
||||||
|
|
||||||
let client_config: ClientConf = toml::from_str(&client_conf)?;
|
let client_config: ClientConf = toml::from_str(&client_conf)?;
|
||||||
|
|
||||||
let (db_exec, db_conn) = DbExecutor::create(client_config.db_path.as_deref().unwrap_or("uberbot.db3"))?;
|
let (db_exec, db_conn) =
|
||||||
|
DbExecutor::create(client_config.db_path.as_deref().unwrap_or("uberbot.db3"))?;
|
||||||
let exec_thread = thread::spawn(move || {
|
let exec_thread = thread::spawn(move || {
|
||||||
db_exec.run();
|
db_exec.run();
|
||||||
tracing::info!("Database executor has been shut down");
|
tracing::info!("Database executor has been shut down");
|
||||||
|
@ -99,6 +101,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
client_config.port,
|
client_config.port,
|
||||||
client_config.username,
|
client_config.username,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut client = Client::new(config).await?;
|
let mut client = Client::new(config).await?;
|
||||||
client.identify().await?;
|
client.identify().await?;
|
||||||
|
|
||||||
|
@ -108,14 +111,16 @@ async fn main() -> anyhow::Result<()> {
|
||||||
last_msgs: HashMap::new(),
|
last_msgs: HashMap::new(),
|
||||||
last_eval: HashMap::new(),
|
last_eval: HashMap::new(),
|
||||||
titlebot: Titlebot::create(spotify_creds).await?,
|
titlebot: Titlebot::create(spotify_creds).await?,
|
||||||
db: db_conn
|
db: db_conn,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = executor(state).await {
|
if let Err(e) = executor(state).await {
|
||||||
tracing::error!("Error in message loop: {}", e);
|
tracing::error!("Error in message loop: {}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
exec_thread.join();
|
if let Err(e) = exec_thread.join() {
|
||||||
|
tracing::error!("Error while shutting down the database: {:?}", e);
|
||||||
|
}
|
||||||
tracing::info!("Shutting down");
|
tracing::info!("Shutting down");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -146,28 +151,6 @@ async fn message_loop(state: &mut AppState) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum LeekCommand {
|
|
||||||
Owo, Leet, Mock
|
|
||||||
}
|
|
||||||
async fn execute_leek(state: &mut AppState, cmd: LeekCommand, channel: &str, nick: &str) -> anyhow::Result<()> {
|
|
||||||
match state.last_msgs.get(nick) {
|
|
||||||
Some(msg) => {
|
|
||||||
tracing::debug!("Executing {:?} on {:?}", cmd, msg);
|
|
||||||
let output = match cmd {
|
|
||||||
LeekCommand::Owo => leek::owoify(msg)?,
|
|
||||||
LeekCommand::Leet => leek::leetify(msg)?,
|
|
||||||
LeekCommand::Mock => leek::mock(msg)?
|
|
||||||
};
|
|
||||||
state.client.privmsg(channel, &output).await?;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
state.client.privmsg(channel, "No last messages found.").await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn separate_to_space(str: &str, prefix_len: usize) -> (&str, Option<&str>) {
|
fn separate_to_space(str: &str, prefix_len: usize) -> (&str, Option<&str>) {
|
||||||
if let Some(o) = str.find(' ') {
|
if let Some(o) = str.find(' ') {
|
||||||
(&str[prefix_len..o], Some(&str[o + 1..]))
|
(&str[prefix_len..o], Some(&str[o + 1..]))
|
||||||
|
@ -219,13 +202,26 @@ async fn handle_privmsg(
|
||||||
state.client.privmsg(&channel, response).await?;
|
state.client.privmsg(&channel, response).await?;
|
||||||
}
|
}
|
||||||
"mock" => {
|
"mock" => {
|
||||||
execute_leek(state, LeekCommand::Mock, channel, remainder.unwrap_or(&nick)).await?;
|
misc::execute_leek(
|
||||||
|
state,
|
||||||
|
LeekCommand::Mock,
|
||||||
|
channel,
|
||||||
|
remainder.unwrap_or(&nick),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
"leet" => {
|
"leet" => {
|
||||||
execute_leek(state, LeekCommand::Leet, channel, remainder.unwrap_or(&nick)).await?;
|
misc::execute_leek(
|
||||||
|
state,
|
||||||
|
LeekCommand::Leet,
|
||||||
|
channel,
|
||||||
|
remainder.unwrap_or(&nick),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
"owo" => {
|
"owo" => {
|
||||||
execute_leek(state, LeekCommand::Owo, channel, remainder.unwrap_or(&nick)).await?;
|
misc::execute_leek(state, LeekCommand::Owo, channel, remainder.unwrap_or(&nick))
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
"ev" => {
|
"ev" => {
|
||||||
let result = misc::mathbot(nick, remainder, &mut state.last_eval)?;
|
let result = misc::mathbot(nick, remainder, &mut state.last_eval)?;
|
||||||
|
@ -234,20 +230,32 @@ async fn handle_privmsg(
|
||||||
"grab" => {
|
"grab" => {
|
||||||
if let Some(target) = remainder {
|
if let Some(target) = remainder {
|
||||||
if target == nick {
|
if target == nick {
|
||||||
state.client.privmsg(&channel, "You can't grab yourself").await?;
|
state
|
||||||
return Ok(())
|
.client
|
||||||
|
.privmsg(&channel, "You can't grab yourself")
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
if let Some(prev_msg) = state.last_msgs.get(target) {
|
if let Some(prev_msg) = state.last_msgs.get(target) {
|
||||||
if state.db.add_quote(prev_msg.clone(), target.into()).await {
|
if state.db.add_quote(prev_msg.clone(), target.into()).await {
|
||||||
state.client.privmsg(&channel, "Quote added").await?;
|
state.client.privmsg(&channel, "Quote added").await?;
|
||||||
} else {
|
} else {
|
||||||
state.client.privmsg(&channel, "A database error has occurred").await?;
|
state
|
||||||
|
.client
|
||||||
|
.privmsg(&channel, "A database error has occurred")
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state.client.privmsg(&channel, "No previous messages to grab").await?;
|
state
|
||||||
|
.client
|
||||||
|
.privmsg(&channel, "No previous messages to grab")
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state.client.privmsg(&channel, "No nickname to grab").await?;
|
state
|
||||||
|
.client
|
||||||
|
.privmsg(&channel, "No nickname to grab")
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"quot" => {
|
"quot" => {
|
||||||
|
|
Loading…
Reference in a new issue