denoland / fastwebsockets

A fast RFC6455 WebSocket implementation
https://docs.rs/fastwebsockets/
Apache License 2.0
845 stars 61 forks source link

Splitting connection cannot handle ping #76

Closed gabrielfonte closed 4 months ago

gabrielfonte commented 5 months ago

I have been following the example 'echo_server_split' from the examples section, but I am facing an issue when the client connection tries to ping.

The relevant part of code:

    let ws = fut.await?;
    let (rx, mut tx) = ws.split(tokio::io::split);
    let mut rx = FragmentCollectorRead::new(rx);

    loop {
        let frame = match rx
            .read_frame::<_, WebSocketError>(&mut move |_| async {
                unreachable!();
            }).await {
            Ok(frame) => frame,
            Err(e) => {
                println!("Frame Error {:?}", e);
                break;
            }
        };
    }

The code is getting to this unreachable part right after pinging from client. I don't know if there is a different way handling pings after splitting the connection.

I have already tested the connection without the splitting and the ping works.

In my application, I need the split because I use an Arc with RwLock to store only the tx part of the connections.

Backtrace: thread 'main' panicked at src/main.rs:282:17: internal error: entered unreachable code stack backtrace: 0: rust_begin_unwind at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5 1: core::panicking::panic_fmt at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14 2: core::panicking::panic at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:144:5 3: websocket_server::handle_client::{{closure}}::{{closure}}::{{closure}} at ./src/main.rs:282:17 4: fastwebsockets::fragment::FragmentCollectorRead::read_frame::{{closure}} at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/fastwebsockets-0.7.1/src/fragment.rs:178:34 5: websocket_server::handle_client::{{closure}} at ./src/main.rs:283:16 6: websocket_server::server_upgrade::{{closure}}::{{closure}} at ./src/main.rs:370:86 7: tokio::runtime::task::core::Core<T,S>::poll::{{closure}} at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/task/core.rs:328:17 8: tokio::loom::std::unsafe_cell::UnsafeCell::with_mut at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/loom/std/unsafe_cell.rs:16:9 9: tokio::runtime::task::core::Core<T,S>::poll at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/task/core.rs:317:13 10: tokio::runtime::task::harness::poll_future::{{closure}} at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/task/harness.rs:485:19 11: <core::panic::unwind_safe::AssertUnwindSafe as core::ops::function::FnOnce<()>>::call_once at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panic/unwind_safe.rs:272:9 12: std::panicking::try::do_call at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:552:40 13: __rust_try 14: std::panicking::try at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:516:19 15: std::panic::catch_unwind at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panic.rs:142:14 16: tokio::runtime::task::harness::poll_future at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/task/harness.rs:473:18 17: tokio::runtime::task::harness::Harness<T,S>::poll_inner at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/task/harness.rs:208:27 18: tokio::runtime::task::harness::Harness<T,S>::poll at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/task/harness.rs:153:15 19: tokio::runtime::task::raw::poll at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/task/raw.rs:271:5 20: tokio::runtime::task::raw::RawTask::poll at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/task/raw.rs:201:18 21: tokio::runtime::task::LocalNotified::run at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/task/mod.rs:416:9 22: tokio::runtime::scheduler::current_thread::CoreGuard::block_on::{{closure}}::{{closure}} at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/scheduler/current_thread/mod.rs:700:25 23: tokio::runtime::coop::with_budget at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/coop.rs:107:5 24: tokio::runtime::coop::budget at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/coop.rs:73:5 25: tokio::runtime::scheduler::current_thread::Context::run_task::{{closure}} at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/scheduler/current_thread/mod.rs:343:43 26: tokio::runtime::scheduler::current_thread::Context::enter at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/scheduler/current_thread/mod.rs:404:19 27: tokio::runtime::scheduler::current_thread::Context::run_task at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/scheduler/current_thread/mod.rs:343:23 28: tokio::runtime::scheduler::current_thread::CoreGuard::block_on::{{closure}} at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/scheduler/current_thread/mod.rs:699:35 29: tokio::runtime::scheduler::current_thread::CoreGuard::enter::{{closure}} at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/scheduler/current_thread/mod.rs:737:68 30: tokio::runtime::context::scoped::Scoped::set at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/context/scoped.rs:40:9 31: tokio::runtime::context::set_scheduler::{{closure}} at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/context.rs:176:26 32: std::thread::local::LocalKey::try_with at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/thread/local.rs:270:16 33: std::thread::local::LocalKey::with at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/thread/local.rs:246:9 34: tokio::runtime::context::set_scheduler at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/context.rs:176:9 35: tokio::runtime::scheduler::current_thread::CoreGuard::enter at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/scheduler/current_thread/mod.rs:737:27 36: tokio::runtime::scheduler::current_thread::CoreGuard::block_on at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/scheduler/current_thread/mod.rs:646:19 37: tokio::runtime::scheduler::current_thread::CurrentThread::block_on::{{closure}} at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/scheduler/current_thread/mod.rs:175:28 38: tokio::runtime::context::runtime::enter_runtime at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/context/runtime.rs:65:16 39: tokio::runtime::scheduler::current_thread::CurrentThread::block_on at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/scheduler/current_thread/mod.rs:167:9 40: tokio::runtime::runtime::Runtime::block_on at /home/gabrielfonte/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/runtime/runtime.rs:348:47 41: websocket_server::main at ./src/main.rs:388:5 42: core::ops::function::FnOnce::call_once at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5 note: Some details are omitted, run with RUST_BACKTRACE=full for a verbose backtrace.

gabrielfonte commented 5 months ago

I already found the solution:

You have to handle pings and pongs manually in the handler like this:

    let ws = fut.await?;
    ws.set_writev(false);
    ws.set_auto_pong(false);
    ws.set_auto_close(false);
    let (rx, mut tx) = ws.split(tokio::io::split);
    let mut rx = FragmentCollectorRead::new(rx);

    loop {
        let frame = match rx
            .read_frame::<_, WebSocketError>(&mut move |_| async {
                unreachable!();
            }).await {
            Ok(frame) => frame,
            Err(e) => {
                println!("Frame Error {:?}", e);
                break;
            }
        };

    match frame.opcode {
        OpCode::Close => {
            println!("Op code close");
            //Handle close
                break;
        },
        OpCode::Ping => {
            println!("Op code ping");
            //Handle ping
        },
            OpCode::Text | OpCode::Binary => {
                println!("Op Code Text or Binary");
                //Handle application commands
        }
        _ => {
            println!("Other Op Code");
            //Just ignore
        }
    }
    }