Files
vinezombie/examples/reconnect.rs
TheDaemoness b2f40896bf Update reg handler to use client state
The handler now, instead of returning Registration,
sets the Client's internal ClientState.
This means useful state info is more readily-available to handlers.

Updated examples to match.
2024-04-28 09:41:23 -07:00

86 lines
3.4 KiB
Rust

use std::io::BufReader;
use vinezombie::{
client::{
self,
auth::Clear,
channel::SyncChannels,
conn::{ServerAddr, Stream},
handlers::{AutoPong, YieldParsed},
register::{register_as_bot, Options},
state::ClientSource,
tls::TlsConfig,
Client,
},
ctcp_version_handler,
names::cmd::PRIVMSG,
string::Line,
};
// Any reliable IRC software needs a way to automatically reconnect.
//
// For this example, we're going to use sync I/O, since we need to do stuff in the loop that
// drives the client anyway, so we might as well explore how to use a system we've been ignoring
// this whole time in a context where it's not completely irrelevant.
//
// WARNING: This example does NOT implement progressively less-frequent reconnections.
// This is strongly recommended to do robust usecase.
fn make_sock(
tls_config: &mut Option<TlsConfig>,
address: &ServerAddr<'static>,
) -> std::io::Result<BufReader<Stream>> {
address.connect(|| {
if let Some(v) = tls_config.as_ref() {
return Ok(v.clone());
};
let config = client::tls::TlsConfigOptions::default().build()?;
*tls_config = Some(config.clone());
Ok(config)
})
}
fn main() -> std::io::Result<()> {
tracing_subscriber::fmt().with_max_level(tracing::Level::INFO).compact().init();
// Standard vinezombie boilerplate.
let mut options: Options<Clear> = Options::new();
options.realname = Some(Line::from_str("Vinezombie Example: reconnect"));
let address = ServerAddr::from_host_str("irc.libera.chat");
let mut tls_config: Option<TlsConfig> = None;
let mut client = Client::new(make_sock(&mut tls_config, &address)?, SyncChannels);
loop {
let (_, reg_result) = client.add(&register_as_bot(), &options).unwrap();
client.run()?;
reg_result.0.recv_now().unwrap()?;
let _ = client.add((), AutoPong);
// As we can interact with this bot, let's add a handler to auto-reply to
// CTCP VERSION and CTCP SOURCE.
let _ = client.add((), ctcp_version_handler!());
// For the purposes of this example, let's quit and reconnect
// if literally anyone sends us a message containing the letter "q".
// In previous examples, we've been ignoring that the client's `run` methods
// actually disclose which handlers produced values and/or finished.
// This time we're actually going to use that information,
// starting by saving the id of the message handler.
let (id, msgs) = client.add((), YieldParsed::just(PRIVMSG)).unwrap();
tracing::info!("bot {} ready for 'q'~", client.state().get::<ClientSource>().unwrap().nick);
loop {
let Ok(result) = client.run() else {
tracing::info!("connection broke, making new connection");
break;
};
// Check if the list of handlers that yielded something contains our id.
if !result.unwrap().0.contains(&id) {
continue;
}
let msg = msgs.try_recv().unwrap();
if !msg.value.contains(&b'q') {
tracing::info!("received \"{}\"", msg.value);
continue;
}
tracing::info!("got 'q', making new connection");
break;
}
client.reset_with_conn(make_sock(&mut tls_config, &address)?);
}
}