use std::net::SocketAddr;
use anyhow::Result;
use slog::{info, o, Drain, Level, Logger};
use tokio::net::UdpSocket;
use tsproto::algorithms as algs;
use tsproto::client::Client;
use tsproto_packets::packets::*;
use tsproto_types::crypto::EccKeyPrivP256;
pub fn create_logger() -> Logger {
let decorator = slog_term::TermDecorator::new().build();
let drain = slog_term::CompactFormat::new(decorator).build().fuse();
let drain = slog_async::Async::new(drain).build().fuse();
slog::Logger::root(drain, o!())
}
pub async fn create_client(
local_address: SocketAddr, remote_address: SocketAddr, logger: Logger, verbose: u8,
) -> Result<Client> {
let private_key = EccKeyPrivP256::import_str(
"MG0DAgeAAgEgAiAIXJBlj1hQbaH0Eq0DuLlCmH8bl+veTAO2+\
k9EQjEYSgIgNnImcmKo7ls5mExb6skfK2Tw+u54aeDr0OP1ITsC/50CIA8M5nm\
DBnmDM/gZ//4AAAAAAAAAAAAAAAAAAAAZRzOI").unwrap();
let udp_socket = UdpSocket::bind(local_address).await?;
let mut con = Client::new(logger, remote_address, Box::new(udp_socket), private_key);
if verbose >= 1 {
tsproto::log::add_logger_with_verbosity(con.logger.clone(), verbose, &mut con)
}
Ok(con)
}
pub async fn connect(con: &mut Client) -> Result<InCommandBuf> {
con.connect().await?;
let private_key = EccKeyPrivP256::import_str(
"MG0DAgeAAgEgAiAIXJBlj1hQbaH0Eq0DuLlCmH8bl+veTAO2+\
k9EQjEYSgIgNnImcmKo7ls5mExb6skfK2Tw+u54aeDr0OP1ITsC/50CIA8M5nm\
DBnmDM/gZ//4AAAAAAAAAAAAAAAAAAAAZRzOI").unwrap();
let mut time_reporter = slog_perf::TimeReporter::new_with_level(
"Compute public key hash cash level",
con.logger.clone(),
Level::Info,
);
time_reporter.start("Compute public key hash cash level");
let private_key_as_pub = private_key.to_pub();
let offset = algs::hash_cash(&private_key_as_pub, 8);
let omega = private_key_as_pub.to_ts();
time_reporter.finish();
info!(con.logger, "Computed hash cash level";
"level" => algs::get_hash_cash_level(&omega, offset),
"offset" => offset);
let offset = offset.to_string();
let mut cmd =
OutCommand::new(Direction::C2S, Flags::empty(), PacketType::Command, "clientinit");
cmd.write_arg("client_nickname", &"Bot");
cmd.write_arg("client_version", &"3.?.? [Build: 5680278000]");
cmd.write_arg("client_platform", &"Linux");
cmd.write_arg("client_input_hardware", &"1");
cmd.write_arg("client_output_hardware", &"1");
cmd.write_arg("client_default_channel", &"");
cmd.write_arg("client_default_channel_password", &"");
cmd.write_arg("client_server_password", &"");
cmd.write_arg("client_meta_data", &"");
cmd.write_arg(
"client_version_sign",
&"Hjd+N58Gv3ENhoKmGYy2bNRBsNNgm5kpiaQWxOj5HN2DXttG6REjymSwJtpJ8muC2gSwRuZi0R+8Laan5ts5CQ==",
);
cmd.write_arg("client_nickname_phonetic", &"");
cmd.write_arg("client_key_offset", &offset);
cmd.write_arg("client_default_token", &"");
cmd.write_arg("client_badges", &"Overwolf=0");
cmd.write_arg("hwid", &"923f136fb1e22ae6ce95e60255529c00,d13231b1bc33edfecfb9169cc7a63bcc");
con.send_packet(cmd.into_packet())?;
Ok(con
.filter_commands(|con, cmd| {
Ok(if cmd.data().packet().content().starts_with(b"initserver ") {
Some(cmd)
} else {
con.hand_back_buffer(cmd.into_buffer());
None
})
})
.await?)
}
pub async fn disconnect(con: &mut Client) -> Result<()> {
let mut cmd =
OutCommand::new(Direction::C2S, Flags::empty(), PacketType::Command, "clientdisconnect");
cmd.write_arg("reasonid", &8);
cmd.write_arg("reasonmsg", &"Bye");
con.send_packet(cmd.into_packet())?;
con.wait_disconnect().await?;
Ok(())
}