mirror of
https://codeberg.org/JasterV/gofish_bot.git
synced 2026-04-26 18:10:09 +00:00
first commit
This commit is contained in:
commit
deeed9be09
13 changed files with 1902 additions and 0 deletions
2
.env.example
Normal file
2
.env.example
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
TELOXIDE_TOKEN=""
|
||||
REDIS_URL=""
|
||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
.env
|
||||
1697
Cargo.lock
generated
Normal file
1697
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
16
Cargo.toml
Normal file
16
Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "gofish"
|
||||
version = "0.1.0"
|
||||
authors = ["JasterV <jaster.victor@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
teloxide = { version="0.5.1", features = ["macros", "auto-send"] }
|
||||
dotenv = "0.15.0"
|
||||
log = "0.4.8"
|
||||
thiserror = "1.0.x"
|
||||
anyhow = "1.0.x"
|
||||
pretty_env_logger = "0.4.0"
|
||||
tokio = { version = "1.3.0", features = ["rt-multi-thread", "macros"] }
|
||||
mobc-redis = "0.7.0"
|
||||
mobc = "0.7.3"
|
||||
6
commandslist.txt
Normal file
6
commandslist.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
start - start a game
|
||||
stop - stop the game
|
||||
ask - ask someone for cards
|
||||
status - ask the bot to show the game general status
|
||||
mystatus - ask the bot to send you your status
|
||||
help - display commands info
|
||||
12
src/actions/help.rs
Normal file
12
src/actions/help.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use crate::alias::Cx;
|
||||
use crate::command::Command;
|
||||
use anyhow::Result;
|
||||
use teloxide::{prelude::*, utils::command::BotCommand};
|
||||
|
||||
pub async fn help(cx: &Cx) -> Result<()> {
|
||||
cx.answer(Command::descriptions())
|
||||
.send()
|
||||
.await
|
||||
.map(|_| ())?;
|
||||
Ok(())
|
||||
}
|
||||
5
src/actions/mod.rs
Normal file
5
src/actions/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod help;
|
||||
mod say_hi;
|
||||
|
||||
pub use help::help;
|
||||
pub use say_hi::say_hi;
|
||||
21
src/actions/say_hi.rs
Normal file
21
src/actions/say_hi.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
use crate::alias::Cx;
|
||||
use anyhow::Result;
|
||||
use teloxide::prelude::*;
|
||||
|
||||
pub async fn say_hi(cx: &Cx) -> Result<()> {
|
||||
let bot = cx.requester.clone();
|
||||
let message = cx.update.clone();
|
||||
let sender = message.from().expect("User data not found");
|
||||
// let sender_chat = message.sender_chat().expect("Sender chat not found");
|
||||
let info = format!(
|
||||
"Your data: \n \t fullname: {} \n \t username: {} \n \t id: {}",
|
||||
sender.full_name(),
|
||||
sender.username.clone().unwrap_or("unknown".into()),
|
||||
sender.id
|
||||
);
|
||||
bot.send_message(cx.update.chat_id(), info.clone())
|
||||
.send()
|
||||
.await?;
|
||||
bot.send_message(sender.id, info).send().await?;
|
||||
Ok(())
|
||||
}
|
||||
7
src/alias.rs
Normal file
7
src/alias.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
use mobc::{Connection, Pool};
|
||||
use mobc_redis::RedisConnectionManager;
|
||||
use teloxide::{adaptors::AutoSend, prelude::*, Bot};
|
||||
|
||||
pub type Cx = UpdateWithCx<AutoSend<Bot>, Message>;
|
||||
pub type MobcPool = Pool<RedisConnectionManager>;
|
||||
pub type MobcCon = Connection<RedisConnectionManager>;
|
||||
31
src/command.rs
Normal file
31
src/command.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
use teloxide::utils::command::BotCommand;
|
||||
|
||||
// Derive BotCommand to parse text with a command into this enumeration.
|
||||
//
|
||||
// 1. rename = "lowercase" turns all the commands into lowercase letters.
|
||||
// 2. `description = "..."` specifies a text before all the commands.
|
||||
//
|
||||
// That is, you can just call Command::descriptions() to get a description of
|
||||
// your commands in this format:
|
||||
// %GENERAL-DESCRIPTION%
|
||||
// %PREFIX%%COMMAND% - %DESCRIPTION%
|
||||
#[derive(BotCommand)]
|
||||
#[command(
|
||||
rename = "lowercase",
|
||||
description = "Use commands in format /command <arg1> <arg2> ... <argN> ",
|
||||
parse_with = "split"
|
||||
)]
|
||||
pub enum Command {
|
||||
#[command(description = "start a game")]
|
||||
Start,
|
||||
#[command(description = "stop the game")]
|
||||
Stop,
|
||||
#[command(description = "ask someone for cards")]
|
||||
Ask,
|
||||
#[command(description = "ask the bot to show the game general status")]
|
||||
Status,
|
||||
#[command(description = "ask the bot to send you your status")]
|
||||
MyStatus,
|
||||
#[command(description = "Show bot commands")]
|
||||
Help,
|
||||
}
|
||||
51
src/db/mod.rs
Normal file
51
src/db/mod.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
use crate::alias::{MobcCon, MobcPool};
|
||||
use crate::errors::MobcError::*;
|
||||
use anyhow::Result;
|
||||
use mobc::Pool;
|
||||
use mobc_redis::redis::{AsyncCommands, FromRedisValue, ToRedisArgs};
|
||||
use mobc_redis::{redis, RedisConnectionManager};
|
||||
use std::time::Duration;
|
||||
|
||||
pub const CACHE_POOL_MAX_OPEN: u64 = 16;
|
||||
pub const CACHE_POOL_MAX_IDLE: u64 = 8;
|
||||
pub const CACHE_POOL_TIMEOUT_SECONDS: u64 = 1;
|
||||
pub const CACHE_POOL_EXPIRE_SECONDS: u64 = 60;
|
||||
|
||||
pub async fn connect(url: &str) -> Result<MobcPool> {
|
||||
let client = redis::Client::open(url).map_err(RedisClientError)?;
|
||||
let manager = RedisConnectionManager::new(client);
|
||||
Ok(Pool::builder()
|
||||
.get_timeout(Some(Duration::from_secs(CACHE_POOL_TIMEOUT_SECONDS)))
|
||||
.max_open(CACHE_POOL_MAX_OPEN)
|
||||
.max_idle(CACHE_POOL_MAX_IDLE)
|
||||
.max_lifetime(Some(Duration::from_secs(CACHE_POOL_EXPIRE_SECONDS)))
|
||||
.build(manager))
|
||||
}
|
||||
|
||||
async fn get_con(pool: &MobcPool) -> Result<MobcCon> {
|
||||
pool.get().await.map_err(|e| {
|
||||
eprintln!("error connecting to redis: {}", e);
|
||||
RedisPoolError(e).into()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn set_data<T>(pool: &MobcPool, key: &str, value: T, ttl_seconds: usize) -> Result<()>
|
||||
where
|
||||
T: ToRedisArgs + Send + Sync,
|
||||
{
|
||||
let mut con = get_con(&pool).await?;
|
||||
con.set(key, value).await.map_err(RedisCMDError)?;
|
||||
if ttl_seconds > 0 {
|
||||
con.expire(key, ttl_seconds).await.map_err(RedisCMDError)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_data<T>(pool: &MobcPool, key: &str) -> Result<T>
|
||||
where
|
||||
T: mobc_redis::redis::FromRedisValue,
|
||||
{
|
||||
let mut con = get_con(&pool).await?;
|
||||
let value = con.get(key).await.map_err(RedisCMDError)?;
|
||||
FromRedisValue::from_redis_value(&value).map_err(|e| RedisTypeError(e).into())
|
||||
}
|
||||
13
src/errors.rs
Normal file
13
src/errors.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum MobcError {
|
||||
#[error("could not get redis connection from pool : {0}")]
|
||||
RedisPoolError(mobc::Error<mobc_redis::redis::RedisError>),
|
||||
#[error("error parsing string from redis result: {0}")]
|
||||
RedisTypeError(mobc_redis::redis::RedisError),
|
||||
#[error("error executing redis command: {0}")]
|
||||
RedisCMDError(mobc_redis::redis::RedisError),
|
||||
#[error("error creating Redis client: {0}")]
|
||||
RedisClientError(mobc_redis::redis::RedisError),
|
||||
}
|
||||
39
src/main.rs
Normal file
39
src/main.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
mod actions;
|
||||
mod alias;
|
||||
mod command;
|
||||
mod db;
|
||||
mod errors;
|
||||
|
||||
use alias::Cx;
|
||||
use anyhow::Result;
|
||||
use command::Command;
|
||||
use dotenv;
|
||||
use teloxide::{prelude::*, types::Me};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
dotenv::dotenv().ok();
|
||||
teloxide::enable_logging!();
|
||||
run().await;
|
||||
}
|
||||
|
||||
async fn run() {
|
||||
log::info!("Starting bot...");
|
||||
let redis_url = std::env::var("REDIS_URL").expect("REDIS_URL not found");
|
||||
|
||||
let bot = Bot::from_env().auto_send();
|
||||
let Me { user: bot_user, .. } = bot.get_me().await.unwrap();
|
||||
let bot_name = bot_user.username.expect("Bots must have usernames");
|
||||
|
||||
log::info!("listening...");
|
||||
|
||||
teloxide::commands_repl(bot, bot_name, execute).await;
|
||||
}
|
||||
|
||||
async fn execute(cx: Cx, command: Command) -> Result<()> {
|
||||
match command {
|
||||
Command::Help => actions::help(&cx).await?,
|
||||
_ => actions::say_hi(&cx).await?,
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Reference in a new issue