diff --git a/.gitignore b/.gitignore index 6525916..7ae5910 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Generated by Cargo # will have compiled files and executables /target +examples/**/target # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html diff --git a/TODO.md b/TODO.md index 51cea0a..917eb12 100644 --- a/TODO.md +++ b/TODO.md @@ -2,8 +2,6 @@ ## Features - include events (pharos) - -- close reason - reconnect? ## Testing diff --git a/src/error.rs b/src/error.rs index 71e7344..e8a1f31 100644 --- a/src/error.rs +++ b/src/error.rs @@ -80,6 +80,20 @@ pub enum WsErrKind #[ fail( display = "The port to which the connection is being attempted is being blocked." ) ] // SecurityError, + + /// An invalid close code was given to a close method. For valid close codes, please see: + /// [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes) + /// + #[ fail( display = "An invalid close code was given to a close method: {}", _0 ) ] + // + InvalidCloseCode(u16), + + /// The reason string given to a close method is to long, please see: + /// [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close) + /// + #[ fail( display = "The reason string given to a close method is to long." ) ] + // + ReasonStringToLong, } diff --git a/src/ws_io.rs b/src/ws_io.rs index eed68d8..3315043 100644 --- a/src/ws_io.rs +++ b/src/ws_io.rs @@ -84,10 +84,6 @@ impl WsIo { trace!( "WsStream: message received!" ); - #[ cfg( debug_assertions )] - // - dbg( &msg_evt ); - q2.borrow_mut().push_back( JsMsgEvent{ msg_evt } ); if let Some( w ) = w2.borrow_mut().take() diff --git a/src/ws_stream.rs b/src/ws_stream.rs index a63eb1c..d101540 100644 --- a/src/ws_stream.rs +++ b/src/ws_stream.rs @@ -80,7 +80,7 @@ impl WsStream /// Close the socket. The future will resolve once the socket's state has become `WsReadyState::CLOSED`. - /// TODO: allow setting reason and code. + /// See: [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close) // pub async fn close( &self ) { @@ -97,6 +97,69 @@ impl WsStream + /// Close the socket. The future will resolve once the socket's state has become `WsReadyState::CLOSED`. + /// See: [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close) + // + pub async fn close_code( &self, code: u16 ) -> Result<(), WsErr> + { + match self.ws.close_with_code( code ) + { + Ok(_) => + { + future_event( |cb| self.ws.set_onclose( cb ) ).await; + + trace!( "WebSocket connection closed!" ); + + Ok(()) + } + + Err( _e ) => + { + // TODO: figure out how to print the original error + // + // error!( "{}", e.as_string().expect( "JsValue to string" ) ); + // + Err( WsErrKind::InvalidCloseCode( code ).into() ) + } + } + } + + + + /// Close the socket. The future will resolve once the socket's state has become `WsReadyState::CLOSED`. + /// See: [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close) + // + pub async fn close_reason( &self, code: u16, reason: impl AsRef ) -> Result<(), WsErr> + { + if reason.as_ref().len() > 123 + { + return Err( WsErrKind::ReasonStringToLong.into() ) + } + + match self.ws.close_with_code_and_reason( code, reason.as_ref() ) + { + Ok(_) => + { + future_event( |cb| self.ws.set_onclose( cb ) ).await; + + trace!( "WebSocket connection closed!" ); + + Ok(()) + } + + Err( _e ) => + { + // TODO: figure out how to print the original error + // + // error!( "{}", e.as_string().expect( "JsValue to string" ) ); + // + Err( WsErrKind::InvalidCloseCode(code).into() ) + } + } + } + + + /// Verify the [WsReadyState] of the connection. /// TODO: verify error handling // diff --git a/tests/futures_codec.rs b/tests/futures_codec.rs index 2e0a37b..ee1f606 100644 --- a/tests/futures_codec.rs +++ b/tests/futures_codec.rs @@ -42,7 +42,7 @@ pub fn data_integrity() -> impl Future01 { let _ = console_log::init_with_level( Level::Trace ); - console_log!( "starting test: data_integrity" ); + info!( "starting test: data_integrity" ); let big_size = 10240; let mut random = vec![ 0; big_size ]; @@ -85,7 +85,7 @@ pub fn data_integrity() -> impl Future01 // async fn echo( name: &str, size: usize, data: Bytes ) { - console_log!( " Enter echo: {}", name ); + info!( " Enter echo: {}", name ); let (_ws , wsio) = connect().await; @@ -132,7 +132,7 @@ pub fn lines_integrity() -> impl Future01 { let _ = console_log::init_with_level( Level::Trace ); - console_log!( "starting test: lines_integrity" ); + info!( "starting test: lines_integrity" ); async move @@ -140,25 +140,25 @@ pub fn lines_integrity() -> impl Future01 let (_ws , wsio ) = connect().await; let mut framed = Framed::new( wsio, LinesCodec {} ); - console_log!( "lines_integrity: start sending" ); + info!( "lines_integrity: start sending" ); framed.send( "A line\n" .to_string() ).await.expect_throw( "Send a line" ); framed.send( "A second line\n".to_string() ).await.expect_throw( "Send a second line" ); framed.send( "A third line\n" .to_string() ).await.expect_throw( "Send a third line" ); - console_log!( "lines_integrity: start receiving" ); + info!( "lines_integrity: start receiving" ); let one = framed.next().await.expect_throw( "Some" ).expect_throw( "Receive a line" ); let two = framed.next().await.expect_throw( "Some" ).expect_throw( "Receive a second line" ); let three = framed.next().await.expect_throw( "Some" ).expect_throw( "Receive a third line" ); - console_log!( "lines_integrity: start asserting" ); + info!( "lines_integrity: start asserting" ); assert_eq!( "A line\n" , &one ); assert_eq!( "A second line\n", &two ); assert_eq!( "A third line\n" , &three ); - console_log!( "lines_integrity: done" ); + info!( "lines_integrity: done" ); let r: Result<(), wasm_bindgen::JsValue> = Ok(()); diff --git a/tests/tokio.rs b/tests/tokio.rs index c7e4f4d..657c5aa 100644 --- a/tests/tokio.rs +++ b/tests/tokio.rs @@ -52,7 +52,7 @@ pub fn data_integrity() -> impl Future01 // let _ = console_log::init_with_level( Level::Trace ); - console_log!( "starting test: data_integrity" ); + info!( "starting test: data_integrity" ); let big_size = 10240; let mut random = vec![ 0u8; big_size ]; @@ -93,7 +93,7 @@ pub fn data_integrity() -> impl Future01 // async fn echo( name: &str, size: usize, data: Bytes ) { - console_log!( " Enter echo: {}", name ); + info!( " Enter echo: {}", name ); let (_ws, wsio) = connect().await; let (tx, rx) = BytesCodec::new().framed( wsio ).split(); @@ -147,7 +147,7 @@ pub fn data_integrity_cbor() -> impl Future01 // let _ = console_log::init_with_level( Level::Trace ); - console_log!( "starting test: data_integrity_cbor" ); + info!( "starting test: data_integrity_cbor" ); let dataset: Vec = vec! [ @@ -177,7 +177,7 @@ pub fn data_integrity_cbor() -> impl Future01 // async fn echo_cbor( data: Data ) { - console_log!( " Enter echo_cbor: {}", &data.hello ); + info!( " Enter echo_cbor: {}", &data.hello ); let (_ws, wsio) = connect().await; diff --git a/tests/ws_stream.rs b/tests/ws_stream.rs index a4c4ff5..387a6d6 100644 --- a/tests/ws_stream.rs +++ b/tests/ws_stream.rs @@ -26,7 +26,7 @@ pub fn state() -> impl Future01 { let _ = console_log::init_with_level( Level::Trace ); - console_log!( "starting test: state" ); + info!( "starting test: state" ); async { @@ -56,7 +56,7 @@ pub fn close_from_wsio() -> impl Future01 { let _ = console_log::init_with_level( Level::Trace ); - console_log!( "starting test: close_from_wsio" ); + info!( "starting test: close_from_wsio" ); async { @@ -87,7 +87,7 @@ pub fn url() -> impl Future01 { let _ = console_log::init_with_level( Level::Trace ); - console_log!( "starting test: url" ); + info!( "starting test: url" ); async { @@ -113,7 +113,7 @@ pub fn no_protocols() -> impl Future01 { let _ = console_log::init_with_level( Level::Trace ); - console_log!( "starting test: no_protocols" ); + info!( "starting test: no_protocols" ); async { @@ -129,6 +129,136 @@ pub fn no_protocols() -> impl Future01 } +// Verify close_code method. +// +#[ wasm_bindgen_test(async) ] +// +pub fn close_code_valid() -> impl Future01 +{ + let _ = console_log::init_with_level( Level::Trace ); + + info!( "starting test: close_code_valid" ); + + async + { + let (ws, _wsio) = WsStream::connect( URL, None ).await.expect_throw( "Could not create websocket" ); + + let res = ws.close_code( 1000 ).await; + + assert!( res.is_ok() ); + + let r: Result<(), wasm_bindgen::JsValue> = Ok(()); + + r + + }.boxed_local().compat() +} + + +// Verify close_code method. +// +#[ wasm_bindgen_test(async) ] +// +pub fn close_code_invalid() -> impl Future01 +{ + let _ = console_log::init_with_level( Level::Trace ); + + info!( "starting test: close_code_invalid" ); + + async + { + let (ws, _wsio) = WsStream::connect( URL, None ).await.expect_throw( "Could not create websocket" ); + + let res = ws.close_code( 500 ).await; + + assert_eq!( &WsErrKind::InvalidCloseCode(500), res.unwrap_err().kind() ); + + let r: Result<(), wasm_bindgen::JsValue> = Ok(()); + + r + + }.boxed_local().compat() +} + + +// Verify close_code method. +// +#[ wasm_bindgen_test(async) ] +// +pub fn close_reason_valid() -> impl Future01 +{ + let _ = console_log::init_with_level( Level::Trace ); + + info!( "starting test: close_reason_valid" ); + + async + { + let (ws, _wsio) = WsStream::connect( URL, None ).await.expect_throw( "Could not create websocket" ); + + let res = ws.close_reason( 1000, "Normal shutdown" ).await; + + assert!( res.is_ok() ); + + let r: Result<(), wasm_bindgen::JsValue> = Ok(()); + + r + + }.boxed_local().compat() +} + + +// Verify close_code method. +// +#[ wasm_bindgen_test(async) ] +// +pub fn close_reason_invalid_code() -> impl Future01 +{ + let _ = console_log::init_with_level( Level::Trace ); + + info!( "starting test: close_reason_invalid_code" ); + + async + { + let (ws, _wsio) = WsStream::connect( URL, None ).await.expect_throw( "Could not create websocket" ); + + let res = ws.close_reason( 500, "Normal Shutdown" ).await; + + assert_eq!( &WsErrKind::InvalidCloseCode(500), res.unwrap_err().kind() ); + + let r: Result<(), wasm_bindgen::JsValue> = Ok(()); + + r + + }.boxed_local().compat() +} + + +// Verify close_code method. +// +#[ wasm_bindgen_test(async) ] +// +pub fn close_reason_invalid() -> impl Future01 +{ + let _ = console_log::init_with_level( Level::Trace ); + + info!( "starting test: close_reason_invalid" ); + + async + { + let (ws, _wsio) = WsStream::connect( URL, None ).await.expect_throw( "Could not create websocket" ); + + let res = ws.close_reason( 1000, vec![ "a"; 124 ].join( "" ) ).await; + + assert_eq!( &WsErrKind::ReasonStringToLong, res.unwrap_err().kind() ); + + let r: Result<(), wasm_bindgen::JsValue> = Ok(()); + + r + + }.boxed_local().compat() +} + + /* // Verify protocols. @@ -140,7 +270,7 @@ pub fn protocols_server_accept_none() -> impl Future01