Update testbot example
Packet handling is now extracted into a separate function and the bot uses euphoxide's joined.since for its !uptime command.
This commit is contained in:
parent
7357435ee1
commit
705ef90e98
1 changed files with 117 additions and 104 deletions
|
|
@ -1,8 +1,13 @@
|
||||||
use std::error::Error;
|
//! A small bot that doesn't use the `bot` submodule. Meant to show how the main
|
||||||
use std::time::{Duration, Instant};
|
//! parts of the API fit together.
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use euphoxide::api::packet::ParsedPacket;
|
||||||
use euphoxide::api::{Data, Nick, Send};
|
use euphoxide::api::{Data, Nick, Send};
|
||||||
use euphoxide::conn::Conn;
|
use euphoxide::conn::{Conn, ConnTx, State};
|
||||||
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
const TIMEOUT: Duration = Duration::from_secs(10);
|
const TIMEOUT: Duration = Duration::from_secs(10);
|
||||||
const DOMAIN: &str = "euphoria.io";
|
const DOMAIN: &str = "euphoria.io";
|
||||||
|
|
@ -10,12 +15,12 @@ const ROOM: &str = "test";
|
||||||
const NICK: &str = "TestBot";
|
const NICK: &str = "TestBot";
|
||||||
const HELP: &str = "I'm an example bot for https://github.com/Garmelon/euphoxide";
|
const HELP: &str = "I'm an example bot for https://github.com/Garmelon/euphoxide";
|
||||||
|
|
||||||
fn format_delta(delta: Duration) -> String {
|
fn format_delta(delta: time::Duration) -> String {
|
||||||
const MINUTE: u64 = 60;
|
const MINUTE: u64 = 60;
|
||||||
const HOUR: u64 = MINUTE * 60;
|
const HOUR: u64 = MINUTE * 60;
|
||||||
const DAY: u64 = HOUR * 24;
|
const DAY: u64 = HOUR * 24;
|
||||||
|
|
||||||
let mut seconds = delta.as_secs();
|
let mut seconds: u64 = delta.whole_seconds().try_into().unwrap();
|
||||||
let mut parts = vec![];
|
let mut parts = vec![];
|
||||||
|
|
||||||
let days = seconds / DAY;
|
let days = seconds / DAY;
|
||||||
|
|
@ -43,20 +48,15 @@ fn format_delta(delta: Duration) -> String {
|
||||||
parts.join(" ")
|
parts.join(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
async fn on_packet(packet: ParsedPacket, conn_tx: &ConnTx, state: &State) -> Result<(), ()> {
|
||||||
async fn main() -> Result<(), Box<dyn Error>> {
|
|
||||||
let start = Instant::now();
|
|
||||||
|
|
||||||
let (mut conn, _) = Conn::connect(DOMAIN, ROOM, false, None, TIMEOUT).await?;
|
|
||||||
|
|
||||||
while let Ok(packet) = conn.recv().await {
|
|
||||||
let data = match packet.content {
|
let data = match packet.content {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Error for {}: {err}", packet.r#type);
|
println!("Error for {}: {err}", packet.r#type);
|
||||||
continue;
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match data {
|
match data {
|
||||||
Data::HelloEvent(event) => println!("Connected with id {}", event.session.id),
|
Data::HelloEvent(event) => println!("Connected with id {}", event.session.id),
|
||||||
Data::SnapshotEvent(event) => {
|
Data::SnapshotEvent(event) => {
|
||||||
|
|
@ -71,11 +71,11 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// We only need to do this because we want to log the result of
|
// We only need to do this because we want to log the result of
|
||||||
// the nick command. Otherwise, we could've just called
|
// the nick command. Otherwise, we could've just called
|
||||||
// tx.send() synchronously and ignored the returned Future.
|
// tx.send() synchronously and ignored the returned Future.
|
||||||
let tx = conn.tx().clone();
|
let conn_tx_clone = conn_tx.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
// Awaiting the future returned by the send command lets you
|
// Awaiting the future returned by the send command lets you
|
||||||
// (type-safely) access the server's reply.
|
// (type-safely) access the server's reply.
|
||||||
let reply = tx
|
let reply = conn_tx_clone
|
||||||
.send(Nick {
|
.send(Nick {
|
||||||
name: NICK.to_string(),
|
name: NICK.to_string(),
|
||||||
})
|
})
|
||||||
|
|
@ -88,11 +88,11 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
}
|
}
|
||||||
Data::BounceEvent(_) => {
|
Data::BounceEvent(_) => {
|
||||||
println!("Received bounce event, stopping");
|
println!("Received bounce event, stopping");
|
||||||
break;
|
return Err(());
|
||||||
}
|
}
|
||||||
Data::DisconnectEvent(_) => {
|
Data::DisconnectEvent(_) => {
|
||||||
println!("Received disconnect event, stopping");
|
println!("Received disconnect event, stopping");
|
||||||
break;
|
return Err(());
|
||||||
}
|
}
|
||||||
Data::JoinEvent(event) => println!("{:?} ({}) joined", event.0.name, event.0.id),
|
Data::JoinEvent(event) => println!("{:?} ({}) joined", event.0.name, event.0.id),
|
||||||
Data::PartEvent(event) => println!("{:?} ({}) left", event.0.name, event.0.id),
|
Data::PartEvent(event) => println!("{:?} ({}) left", event.0.name, event.0.id),
|
||||||
|
|
@ -111,8 +111,10 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
} else if content == format!("!help @{NICK}") {
|
} else if content == format!("!help @{NICK}") {
|
||||||
reply = Some(HELP.to_string());
|
reply = Some(HELP.to_string());
|
||||||
} else if content == format!("!uptime @{NICK}") {
|
} else if content == format!("!uptime @{NICK}") {
|
||||||
let delta = Instant::now().duration_since(start);
|
if let Some(joined) = state.joined() {
|
||||||
|
let delta = OffsetDateTime::now_utc() - joined.since;
|
||||||
reply = Some(format!("/me has been up for {}", format_delta(delta)));
|
reply = Some(format!("/me has been up for {}", format_delta(delta)));
|
||||||
|
}
|
||||||
} else if content == "!test" {
|
} else if content == "!test" {
|
||||||
reply = Some("Test successful!".to_string());
|
reply = Some("Test successful!".to_string());
|
||||||
} else if content == format!("!kill @{NICK}") {
|
} else if content == format!("!kill @{NICK}") {
|
||||||
|
|
@ -125,21 +127,20 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// would be a race between sending the message and closing
|
// would be a race between sending the message and closing
|
||||||
// the connection as the send function can return before the
|
// the connection as the send function can return before the
|
||||||
// message has actually been sent.
|
// message has actually been sent.
|
||||||
let _ = conn
|
let _ = conn_tx
|
||||||
.tx()
|
|
||||||
.send(Send {
|
.send(Send {
|
||||||
content: "/me dies".to_string(),
|
content: "/me dies".to_string(),
|
||||||
parent: Some(event.0.id),
|
parent: Some(event.0.id),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
break;
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(reply) = reply {
|
if let Some(reply) = reply {
|
||||||
// If you are not interested in the result, you can just
|
// If you are not interested in the result, you can just
|
||||||
// throw away the future returned by the send function.
|
// throw away the future returned by the send function.
|
||||||
println!("Sending reply...");
|
println!("Sending reply...");
|
||||||
let _ = conn.tx().send(Send {
|
let _ = conn_tx.send(Send {
|
||||||
content: reply,
|
content: reply,
|
||||||
parent: Some(event.0.id),
|
parent: Some(event.0.id),
|
||||||
});
|
});
|
||||||
|
|
@ -148,6 +149,18 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let (mut conn, _) = Conn::connect(DOMAIN, ROOM, false, None, TIMEOUT).await?;
|
||||||
|
|
||||||
|
while let Ok(packet) = conn.recv().await {
|
||||||
|
if on_packet(packet, conn.tx(), conn.state()).await.is_err() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue