@@ -9,11 +9,12 @@ use rust_socketio::asynchronous::{Client, ClientBuilder};
99use rust_socketio:: { Payload , TransportType } ;
1010use serde_json:: { Value , json} ;
1111use simple_logger:: SimpleLogger ;
12+ use std:: sync:: Arc ;
1213use tokio:: fs:: File ;
1314use tokio:: io:: { AsyncWriteExt , BufWriter } ;
1415use tokio:: select;
1516use tokio:: signal;
16- use tokio:: time:: Duration ;
17+ use tokio:: time:: { Duration , sleep } ;
1718use tokio_util:: sync:: CancellationToken ;
1819
1920const WRITE_BUFFER_SIZE : usize = 8 * 1024 ; // 8 KiB
@@ -54,6 +55,11 @@ enum Event {
5455 Terminate ,
5556}
5657
58+ enum LoginError {
59+ Throttled ( u64 ) ,
60+ Unknown ( Option < String > ) ,
61+ }
62+
5763enum SocketAddressError {
5864 NotFound ,
5965 Parse ( serde_json:: Error ) ,
@@ -73,7 +79,7 @@ async fn create_chat_log_file(channel: &str) -> File {
7379 file
7480}
7581
76- fn handle_login_event ( values : Vec < Value > ) {
82+ fn handle_login_event ( values : Vec < Value > ) -> Result < ( ) , LoginError > {
7783 for value in values {
7884 let login: data:: Login = match serde_json:: from_value ( value) {
7985 Ok ( v) => v,
@@ -86,15 +92,21 @@ fn handle_login_event(values: Vec<Value>) {
8692 if login. success {
8793 log:: info!(
8894 "Logged in as guest {}" ,
89- login. name. unwrap_or( "Unknown " . into( ) )
95+ login. name. unwrap_or( "<UNKNOWN> " . into( ) )
9096 ) ;
97+ return Ok ( ( ) ) ;
9198 } else {
92- log:: warn!(
93- "Login failed: {}" ,
94- login. error. unwrap_or( "Unknown error" . into( ) )
95- ) ;
99+ if let Some ( error_message) = login. error {
100+ if let Some ( duration) = utils:: check_throttling_error ( & error_message) {
101+ return Err ( LoginError :: Throttled ( duration) ) ;
102+ } else {
103+ return Err ( LoginError :: Unknown ( Some ( error_message) ) ) ;
104+ }
105+ }
106+ return Err ( LoginError :: Unknown ( None ) ) ;
96107 }
97108 }
109+ Err ( LoginError :: Unknown ( None ) )
98110}
99111
100112/// Join a channel on the Cytube server.
@@ -211,16 +223,18 @@ async fn main() {
211223 } ;
212224
213225 let channel_name = args. channel . clone ( ) ;
226+ let guest_login = Arc :: new ( args. guest_login ) ;
227+ let connect_guest_login = guest_login. clone ( ) ;
214228 let socket = ClientBuilder :: new ( socket_address)
215229 . transport_type ( TransportType :: Any )
216230 . on ( rust_socketio:: Event :: Connect , move |_, client| {
217231 let channel_name = channel_name. clone ( ) ;
218- let guest_login = args . guest_login . clone ( ) ;
232+ let username = connect_guest_login . clone ( ) ;
219233 async move {
220234 log:: info!( "Connected to server" ) ;
221235 join_channel ( & client, & channel_name) . await ;
222- if let Some ( username) = guest_login {
223- login_as_guest ( & client, & username) . await ;
236+ if let Some ( username) = & * username {
237+ login_as_guest ( & client, username) . await ;
224238 }
225239 }
226240 . boxed ( )
@@ -286,6 +300,7 @@ async fn main() {
286300 . expect ( "Connection failed" ) ;
287301
288302 let channel_name = args. channel . clone ( ) ;
303+ let manager_socket = socket. clone ( ) ;
289304 let manager = tokio:: spawn ( async move {
290305 let mut last_timestamp: u64 = 0 ;
291306 while let Some ( event) = channel:: read_event ( & mut rx) . await {
@@ -327,7 +342,24 @@ async fn main() {
327342 Event :: Disconnect => {
328343 log:: warn!( "Client disconnected from server" ) ;
329344 }
330- Event :: Login ( values) => handle_login_event ( values) ,
345+ Event :: Login ( values) => match handle_login_event ( values) {
346+ Ok ( _) => { }
347+ Err ( LoginError :: Throttled ( seconds) ) => {
348+ log:: warn!( "Guest login throttled; retrying in {} seconds" , seconds) ;
349+ let username = guest_login. clone ( ) ;
350+ let socket = manager_socket. clone ( ) ;
351+ let _ = tokio:: spawn ( async move {
352+ sleep ( Duration :: from_secs ( seconds) ) . await ;
353+ if let Some ( username) = & * username {
354+ login_as_guest ( & socket, username) . await ;
355+ }
356+ } ) ;
357+ }
358+ Err ( LoginError :: Unknown ( Some ( message) ) ) => {
359+ log:: warn!( "Login failed: {}" , message)
360+ }
361+ Err ( LoginError :: Unknown ( None ) ) => log:: warn!( "Login failed" ) ,
362+ } ,
331363 Event :: RotateLog => {
332364 log:: info!( "Rotating log file..." ) ;
333365 match file_buffer. flush ( ) . await {
0 commit comments