5个版本 (稳定)
2.0.2 | 2023年11月19日 |
---|---|
1.0.0 | 2023年11月10日 |
0.3.0 | 2023年10月29日 |
945 在 HTTP服务器
每月46次下载
27KB
386 行
██████╗ ████████╗███╗ ██╗██╗███████╗██╗ ██╗ ██╔══██╗╚══██╔══╝████╗ ██║██║██╔════╝╚██╗ ██╔╝ ██████╔╝ ██║ ██╔██╗ ██║██║█████╗ ╚████╔╝ ██╔══██╗ ██║ ██║╚██╗██║██║██╔══╝ ╚██╔╝ ██████╔╝ ██║ ██║ ╚████║██║██║ ██║ ╚═════╝ ╚═╝ ╚═╝ ╚═══╝╚═╝╚═╝ ╚═╝
rust library to simplify allowing user input over the web
托管带按钮的网站,让您可以专注于重要的事情!
Btnify是一个小型库,可以让您托管一个带有按钮的网站,这些按钮在点击时会调用函数或闭包。在底层,Btnify使用Axum。这个库很简单,但是它确实工作,并且它是开源的!请提交任何改进的拉取请求:我会非常感激的。
安装
运行 cargo add btnify
或者
将 btnify = "2.0.2"
添加到您的 Cargo.toml
如何使用
示例
Hello World
use btnify::button::{Button, ButtonResponse};
fn greet_handler() -> ButtonResponse {
ButtonResponse::from("hello world!")
}
// this button doesn't use any state so we will mark the state generic as unit
let greet_button: Button<()> = Button::create_basic_button("Greet!", Box::new(greet_handler));
Hello World 2.0
use btnify::button::{Button, ButtonResponse};
fn better_greet_handler(responses: Vec<Option<String>>) -> ButtonResponse {
// responses is guaranteed to be the same length as the number of extra prompts
// specified when creating a button
let name = &responses[0];
match name {
Some(name) => format!("Hello, {name}").into(),
None => format!("You didn't provide a name! :(").into()
}
}
let better_greet_button: Button<()> = Button::create_button_with_prompts(
"Greet 2.0",
Box::new(better_greet_handler),
vec!["What's your name?".to_string()]
);
计数器应用程序
use std::sync::Mutex;
use tokio::sync::oneshot;
use btnify::bind_server;
use btnify::ShutdownConfig;
use btnify::button::{Button, ButtonResponse};
struct Counter {
// must use Mutex for interior mutability and thread-safety
count: Mutex<i32>,
end_server_tx: Mutex<Option<oneshot::Sender<()>>>,
}
impl Counter {
fn new(tx: oneshot::Sender<()>) -> Counter {
Counter {
count: Mutex::new(0),
end_server_tx: Mutex::new(Some(tx)),
}
}
fn end_server(&self) {
// Acquire the Mutex to modify
let mut tx = self.end_server_tx.lock().unwrap();
// Take the sender
let tx = tx.take().unwrap();
// Send the signal to end the server
tx.send(()).unwrap();
}
}
fn count_handler(state: &Counter) -> ButtonResponse {
let count = state.count.lock().unwrap();
format!("The count is: {count}").into()
}
fn plus_handler(state: &Counter, responses: Vec<Option<String>>) -> ButtonResponse {
match &responses[0] {
Some(response_str) => {
if let Ok(amount) = response_str.parse::<i32>() {
let mut count = state.count.lock().unwrap();
*count += amount;
format!("The count now is: {}", *count).into()
} else {
"You did not provide a number.".into()
}
}
None => "You didn't provide any input.".into(),
}
}
fn end_button_handler(state: &Counter) -> ButtonResponse {
state.end_server();
"Server is ending. Goodbye!".into()
}
fn server_end(state: &Counter) {
println!("goodbye world. ;(");
}
let count_button = Button::create_button_with_state("Counter", Box::new(count_handler));
let plus_button = Button::create_button_with_state_and_prompts(
"add to counter",
Box::new(plus_handler),
vec!["How much do you want to add?".to_string()]
);
let end_button = Button::create_button_with_state("End Server", Box::new(end_button_handler));
let buttons = vec![count_button, plus_button, end_button];
let (tx, rx) = oneshot::channel();
let shutdown_config = ShutdownConfig::new(Some(rx), Some(Box::new(server_end)));
bind_server(&"0.0.0.0:3000".parse().unwrap(), buttons, Counter::new(tx), None);
// uncomment to actually run the server:
// .await
// .unwrap();
依赖关系
~6–16MB
~194K SLoC