Skip to content
This repository has been archived by the owner on Jun 17, 2023. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
EAimTY committed Oct 26, 2021
0 parents commit d682b62
Show file tree
Hide file tree
Showing 7 changed files with 926 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
22 changes: 22 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "bing-dict-telegram-bot"
description = "A Telegram bot translates words from Chinese to English or from English to Chinese using Bing Dict"
version = "0.1.0"
authors = ["EAimTY <ea.imty@gmail.com>"]
edition = "2021"
readme = "README.md"
license = "GPL-3.0-or-later"
repository = "https://github.com/EAimTY/bing-dict-telegram-bot"

[dependencies]
bing-dict = "0.1"
futures-util = "0.3"
getopts = "0.2"
tgbot = "0.14"
thiserror = "1.0"
tokio = { version = "1.11", features = ["rt-multi-thread", "macros"] }

[profile.release]
lto = true
codegen-units = 1
panic = "abort"
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# bing-dict

A Telegram bot translates words from Chinese to English or from English to Chinese using Bing Dict.

## Usage

```
Usage: bing-dict-telegram-bot -t TELEGRAM-TOKEN [options]
Options:
-t, --token TOKEN (required) set Telegram Bot HTTP API token
-p, --proxy PROXY set proxy (supported: http, https, socks5)
-w, --webhook-port WEBHOOK_PORT
set webhook port (1 ~ 65535) and run bot in webhook
mode
-c, --trigger-with-command
trigger translate with command rather than any text
message
-h, --help print this help menu
```

## Build

Rust nighlty is required.

```bash
$ git clone https://github.com/EAimTY/bing-dict-telegram-bot && cd bing-dict-telegram-bot
$ cargo build --release
```

## License

GNU General Public License v3.0
113 changes: 113 additions & 0 deletions src/bot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use crate::config::Config;
use futures_util::future::BoxFuture;
use tgbot::{
longpoll::LongPoll,
methods::SendMessage,
types::{Command, Update, UpdateKind},
webhook::{self, HyperError},
Api, ApiError, Config as ApiConfig, ParseProxyError, UpdateHandler,
};
use thiserror::Error;

pub async fn run(config: &Config) -> Result<(), Error> {
let mut api_config = ApiConfig::new(&config.token);

if let Some(proxy) = &config.proxy {
api_config = api_config.proxy(proxy)?;
}

let api = Api::new(api_config)?;

if config.webhook == 0 {
LongPoll::new(api.clone(), Handler::new(api, config.trigger_with_command))
.run()
.await;
} else {
webhook::run_server(
([0, 0, 0, 0], config.webhook),
"/",
Handler::new(api, config.trigger_with_command),
)
.await?;
}

Ok(())
}

#[derive(Clone)]
struct Handler {
api: Api,
trigger_with_command: bool,
}

impl Handler {
fn new(api: Api, trigger_with_command: bool) -> Self {
Self {
api,
trigger_with_command,
}
}
}

impl UpdateHandler for Handler {
type Future = BoxFuture<'static, ()>;

fn handle(&self, update: Update) -> Self::Future {
let handler = self.clone();
Box::pin(async move {
if let UpdateKind::Message(message) = update.kind {
let chat_id = message.get_chat_id();
let mut input = None;

if handler.trigger_with_command {
if let Ok(command) = Command::try_from(message) {
if command.get_name() == "/dict" {
input = Some(
command
.get_args()
.iter()
.map(|arg| arg.as_str())
.intersperse(" ")
.collect::<String>(),
);
}
}
} else if let Some(text) = message.get_text() {
input = Some(text.data.clone());
}

if let Some(input) = input {
let result = match bing_dict::translate(&input).await {
Ok(result) => result,
Err(err) => {
eprintln!("{}", err);
return;
}
};

let send_message;
if let Some(result) = result {
send_message = SendMessage::new(chat_id, result);
} else {
send_message = SendMessage::new(chat_id, "No paraphrase");
}

match handler.api.execute(send_message).await {
Ok(_) => (),
Err(err) => eprintln!("{}", err),
}
}
}
})
}
}

#[derive(Error, Debug)]
pub enum Error {
#[error(transparent)]
Api(#[from] ApiError),
#[error(transparent)]
Hyper(#[from] HyperError),
#[error(transparent)]
ParseProxy(#[from] ParseProxyError),
}
58 changes: 58 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use getopts::Options;

pub struct Config {
pub token: String,
pub proxy: Option<String>,
pub webhook: u16,
pub trigger_with_command: bool,
}

impl Config {
pub fn parse(args: Vec<String>) -> Result<Self, String> {
let mut opts = Options::new();

opts.optopt(
"t",
"token",
"(required) set Telegram Bot HTTP API token",
"TOKEN",
);
opts.optopt(
"p",
"proxy",
"set proxy (supported: http, https, socks5)",
"PROXY",
);
opts.optopt(
"w",
"webhook-port",
"set webhook port (1 ~ 65535) and run bot in webhook mode",
"WEBHOOK_PORT",
);
opts.optflag(
"c",
"trigger-with-command",
"trigger translate with command rather than any text message",
);
opts.optflag("h", "help", "print this help menu");

let usage = opts.usage(&format!("Usage: {} -t TELEGRAM-TOKEN [options]", args[0]));

let matches = opts.parse(&args[1..]).map_err(|e| e.to_string())?;

if matches.opt_present("h") {
return Err(usage);
}

Ok(Self {
token: matches
.opt_str("t")
.ok_or_else(|| String::from("Telegram Bot HTTP API token not set"))?,
proxy: matches.opt_str("p"),
webhook: matches
.opt_str("w")
.map_or_else(|| 0, |port| port.parse().unwrap_or(0)),
trigger_with_command: matches.opt_present("c"),
})
}
}
25 changes: 25 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#![feature(iter_intersperse)]

use crate::config::Config;
use std::env;

mod bot;
mod config;

#[tokio::main]
async fn main() {
let args: Vec<String> = env::args().collect();

let config = match Config::parse(args) {
Ok(config) => config,
Err(err) => {
eprintln!("{}", err);
return;
}
};

match bot::run(&config).await {
Ok(()) => (),
Err(err) => eprintln!("{}", err),
}
}

0 comments on commit d682b62

Please sign in to comment.