Giter Club home page Giter Club logo

ws-rs's Introduction

WS-RS

Lightweight, event-driven WebSockets for Rust.

/// A WebSocket echo server
listen("127.0.0.1:3012", |out| {
    move |msg| {
        out.send(msg)
    }
})

Introduction

Build Status MIT licensed Crate

Homepage

API Documentation

This library provides an implementation of WebSockets, RFC6455 using MIO. It allows for handling multiple connections on a single thread, and even spawning new client connections on the same thread. This makes for very fast and resource efficient WebSockets. The API design abstracts away the menial parts of the WebSocket protocol and allows you to focus on application code without worrying about protocol conformance. However, it is also possible to get low-level access to individual WebSocket frames if you need to write extensions or want to optimize around the WebSocket protocol.

Getting Started

Check out the examples.

Features

WS-RS provides a complete implementation of the WebSocket specification. There is also support for ssl and permessage-deflate.

Contributing

Please report bugs and make feature requests here.

ws-rs's People

Contributors

agalakhov avatar alkis avatar azdavis avatar bluetech avatar drbawb avatar eijebong avatar faern avatar hfiguiere avatar housleyjk avatar jlhwung avatar jonalmeida avatar juniperberry avatar king6cong avatar lilianmoraru avatar little-dude avatar maciejhirsz avatar nox avatar overdrivenpotato avatar peterw-lwl avatar ppkunofficial avatar ralfbiedert avatar rocallahan avatar sfonxs avatar shritesh avatar simonsapin avatar thomas-jeepe avatar tomusdrw avatar ue2020 avatar wiomoc avatar wridgers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ws-rs's Issues

Does ws-rs support "wss" protocol?

I can't connect to websocket server using 'wss' proto, here is my client code:

use extern crate ws;

use ws::{connect, Handler, Sender, Handshake, Message, CloseCode};
use ws::Result as WSResult;
use ws::Error as WSError;


struct WSClient {
    out: Sender,
}

impl Handler for WSClient {
    fn on_open(&mut self, _: Handshake) -> WSResult<()> {
        println!("connection established");
        match self.out.send("text") {
            Ok(_) => println!("success"),
            Err(e) => println!("{}", e),
        };
        return Ok(());
    }

    fn on_message(&mut self, msg: Message) -> WSResult<()> {
        println!("Got message: {}", msg);
        self.out.close(CloseCode::Normal)
    }

    fn on_close(&mut self, _: CloseCode, reason: &str) {
        println!("closed due to {}", reason);
    }

    fn on_error(&mut self, err: WSError) {
        println!("Error {}", err);
    }
}


fn main () {
    connect(url, |out| {WSClient { out: out } }).unwrap();
}

this code works, if I use url like ws://echo.websocket.org, but for wss://echo.websocket.org the program just provides no output.

Set headers, such as authentication and protocol headers

I'm trying to build a client that sends web socket headers to denote the sub protocol to use, but if didn't seem that this is very easy. I wasn't able to find an example or documentation for accessing the HTTP request that's used for making this connection. Things I may be interested in are:

  • protocol header
  • authentication
  • cookies

rust-websocket makes this really easy, but I prefer other aspects of this library better and wish this was also easy. I've looked at the Factory trait and this wasn't obvious, if it's possible.

ws-rs client use wss can not connect

with:
cargo run --features ssl --example cli ws://echo.websocket.org
ws-rs can success connect.

but with:
cargo run --features ssl --example cli wss://echo.websocket.org
display:
Connecting to wss://echo.websocket.org
and nothing else.

p.s
ws-rs server tls is ok, I can connect the server with the websocket bulit in javascript

Ability to access Request methods (like resource()) from Factory methods

Hey! I've been writing a bit of server code in your (excellent) WebSockets library. I have an API suggestion: my code routes a connection based on the specific WebSocket path accessed, so for example connections to ws://server/thing1 and ws://server/thing2 are handled differently. ws' API handles this ok right now if I do my routing in on_open, but it would be ideal if Factory's methods had access to Request objects (or at least a couple of their properties like resource()) so that I could dispatch connections to different Handlers based on handshake data and client metadata. I'm quite surprised Factory objects don't seem to have the ability to access Request data already: they have a handle to a Sender, which implies the connection handshake has already completed and the data should be on hand.

Ability to reply to http connections

I noticed if I hit the server in the browser via http://localhost:3012/ that I get these messages on the command line:

$ cargo run
     Running `target/debug/sockmeup`
Encountered an error: WebSocket Protocol Error: Unable to parse WebSocket key.
Enable a logger to see more information.
Encountered an error: WebSocket Protocol Error: Handshake failed.
Enable a logger to see more information.

In both Firefox and Chrome the connection doesn't seem to finish (the loading indicator keep spinning). Is there a way to terminate these connections? Can we reply to them with content?

Connection problems when client and server are on the same machine

I'm building a server that uses ws-rs and I've found that if the client responds too quickly after the initial handshake, then the server isn't prepared to respond to the message. The message is then lost, and the client hangs waiting for a response message.

I believe the source of the problem is write_handshake in connection.rs. The server sends its response to the client on line 410, but doesn't start listening until line 465. I doubt that it would ever be much of an issue if the client and server weren't on the same machine, but it happens every single time for me. It doesn't happen if I use a client also based on ws-rs, but it does for other websocket libraries. I've created a gist that demonstrates the problem using ws-rs and throwing a short sleep in the on_open() method to simulate the client responding faster than the server can read here https://gist.github.com/dyule/af30554b2257fe2370e39ff739e990b9

It's easy to get around this by adding in a short sleep in the client after connecting, but that's not very ideal. It's also a pretty rare case. But it is something I've encountered. I don't understand mio well enough to fix it myself, but I hope it's not too much of a change.

Is it possible to get the client IP in on_open?

If so, how would I do it? The docs do not really mention this, but theoretically it should be possible to get the IP from the initial request.

On a side note, props for making this library. It is by far the best-designed websocket library I have ever worked with. (No idea why websocket-rs has so many more downloads on crates.io than this, considering ws-rs is also a lot faster)

need a hook into a pong message

In my application I want to send a ping with a date string generated on the client and on receiving the pong monitor the latency of the link. Currently there is no way to do this in the API.

Integration with existing eventloop?

Are there any plans to allow ws-rs to be used within an existing eventloop?

Perhaps the host application/library could query ws-rs for a set of fd's to select/poll on... Or alternately, ws-rs could utilise all eventloop functionality via a trait, thereby making the eventloop pluggable.

can't connect to wss endpoint with openssl 0.7.2

I am using 0.4.2. I noticed that openssl got upgraded to 0.7.2, not sure if that's the problem.

Debug logs look like this:

DEBUG:2015-12-16T23:56:08.530593:ws::handler: Handler is building request from wss://ws-feed.exchange.coinbase.com/.
DEBUG:2015-12-16T23:56:08.530811:ws::handshake: Built request from URL:
GET / HTTP/1.1
Connection: Upgrade
Host: ws-feed.exchange.coinbase.com:443
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: vWO5OTYQQRuk5o5Lq4NyMA==
Upgrade: websocket


ERROR:2015-12-16T23:56:08.530939:ws::io: Unable to establish connection to wss://ws-feed.exchange.coinbase.com/: WS Error <Ssl(StreamError(Error { repr: Os { code: 57, message: "Socket is not connected" } }))>

Handling of HTTP parse errors is a bit too aggressive

If HTTP parse error occurs during handshake, the current implementation just panics. This can be used to blow up the server, by sending random bytes to the server.

This does not happen in release builds, of course, because it uses debug_assert!. So this shouldn't be a problem in production. But I think this handling of HTTP errors is a bit too aggressive, compared to other kinds of errors. Is there a reason? Probably settings.panic_on_parse is needed?

dependencies should not use "*"

It should also not use git repos unless a tag is specified.
This can cause it to break when any dependency releases a breaking change.

How to handle ws::ErrorKind::Queue?

I'm (apparently) sending too many items to the internal queue and getting back:

ERROR:ws::handler: WS Error <Queue(NotifyError::Full(..))>
DEBUG:ws::handler: Connection closing due to (Abnormal)

However I don't see any calls on Sender that would allow me to determine if I'm about to fill up the queue? By the time I get the error back ws-rs is already disconnecting from the client.

Is there some method I can call that'd advise to sleep for a bit and try again?

Real world use case: https://github.com/nickhs/websocket_replay/blob/master/src/main.rs#L80

`on_error` is called even when the error is initiated by the server

I'm not sure whether this is intentional or not, but on_error is called not only when the client does something wrong, but also when the server initiates an error by returning Err in the handler.

This kinda makes sense, in that server-initiated errors may also want to be handled by the same on_error handler, but it is a bit awkward when one tries to capture the moment of disconnection by registering both on_close and on_error, because for server-initiated errors, both on_close and on_error are called (on_error is called first, and then on_close is called). I had to introduce a flag to prevent double finalization.

Is there a better way to handle this situation? Ideally something like on_disconnect would be good to have, but I guess making on_error not called for server-initiated errors is also viable.

For a server, is it possible to send to certain clients only

in on_message callback for impl Handler for Server { ... }:

Sender::send will send the message to the client sending the message only.

Sender::broadcast will send the message to everybody connected to the server.

Is it possible to send to certain clients only, specified by e.g. client tokens?

Mixing ssl with non-ssl connections results in panic in debug builds

I'm using the basic example:

extern crate ws;

use ws::listen;

fn main() {
    listen("127.0.0.1:3012", |out| {
        move |msg| {
            out.send(msg)
        }
    });
}

I'm able to connect mutiple web socket connections via ws://localhost:3012/. But if I try wss://localhost:3012/, my process crashes.

$ RUST_BACKTRACE=1 cargo run
     Running `target/debug/sockmeup`
Encountered an error: WebSocket Protocol Error: Unable to parse WebSocket key.
Enable a logger to see more information.
Encountered an error: WebSocket Protocol Error: Handshake failed.
Enable a logger to see more information.
Encountered an error: WebSocket Protocol Error: Unable to parse WebSocket key.
Enable a logger to see more information.
Encountered an error: WebSocket Protocol Error: Handshake failed.
Enable a logger to see more information.
Encountered an error: Unable to parse HTTP
Enable a logger to see more information.
thread '<main>' panicked at 'Encountered HTTP parse error while not in connecting state!', /home/jedireza/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/ws-0.4.4/src/connection.rs:369
stack backtrace:
   1:     0x55634365cff0 - sys::backtrace::tracing::imp::write::hd6d99fcaca6f3487qru
   2:     0x55634365f60b - panicking::default_handler::_$u7b$$u7b$closure$u7d$$u7d$::closure.43421
   3:     0x55634365f278 - panicking::default_handler::hd56ae5efa8870fb8eZy
   4:     0x55634365357c - sys_common::unwind::begin_unwind_inner::hddffc5a57d251d30fgt
   5:     0x55634359d347 - sys_common::unwind::begin_unwind::h15246923697048288963
                        at ../src/libstd/sys/common/unwind/mod.rs:236
   6:     0x5563435ba25c - connection::Connection<H>::error::h14748544831559286976
                        at /home/jedireza/playground/sockmeup/<std macros>:3
   7:     0x5563435b0e52 - io::Handler<F>.mio..Handler::ready::h17920482439799608308
                        at /home/jedireza/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/ws-0.4.4/src/io.rs:363
   8:     0x5563435aebe3 - event_loop::EventLoop<H>::io_event::h16330785249837823754
                        at /home/jedireza/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/mio-0.5.0/src/event_loop.rs:343
   9:     0x5563435aeaff - event_loop::EventLoop<H>::io_process::h4929044171233749946
                        at /home/jedireza/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/mio-0.5.0/src/event_loop.rs:335
  10:     0x5563435ad715 - event_loop::EventLoop<H>::run_once::h17871687314255144032
                        at /home/jedireza/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/mio-0.5.0/src/event_loop.rs:298
  11:     0x5563435acf6c - event_loop::EventLoop<H>::run::h6742499006111220148
                        at /home/jedireza/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/mio-0.5.0/src/event_loop.rs:247
  12:     0x5563435accc2 - WebSocket<F>::run::h9135685978612240389
                        at /home/jedireza/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/ws-0.4.4/src/lib.rs:544
  13:     0x5563435ab617 - WebSocket<F>::listen::h1657451916728169245
                        at /home/jedireza/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/ws-0.4.4/src/lib.rs:525
  14:     0x55634359b45e - listen::h4044848987074142526
                        at /home/jedireza/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/ws-0.4.4/src/lib.rs:315
  15:     0x55634359b180 - main::he6a4b95c9d49545cgaa
                        at src/main.rs:28
  16:     0x55634365eed4 - sys_common::unwind::try::try_fn::h7220737038340441056
  17:     0x55634365c32b - __rust_try
  18:     0x55634365e95e - rt::lang_start::hcebc170923a2cb13kRy
  19:     0x5563435f3b49 - main
  20:     0x7fc0c154f60f - __libc_start_main
  21:     0x55634359b038 - _start
  22:                0x0 - <unknown>
Process didn't exit successfully: `target/debug/sockmeup` (exit code: 101)

I also got the same result using the server example found in the guide. How can I handle this situation without crashing?

Wrong request URI

Running the following:

extern crate ws;

use ws::{connect, CloseCode};

fn main() {
    connect("ws://localhost:80/foo", |out| {
        move |_| {
            out.close(CloseCode::Normal)
        }
    }).unwrap();
}

results in the following request line: GET ws://localhost:80/foo HTTP/1.1

The correct request line would be: GET /foo HTTP/1.1

Example on implementing a Factory?

Sorry if this is not apparent, but I've scoured the docs and source code but have not found an answer. I'm looking to implement a Factory, not just the Handler, so that I can implement the methods defined here: https://ws-rs.org/api_docs/ws/trait.Factory.html

I've tried a handful of approaches, even the ones verbatim from the docs, and nothing works. Rust errors on things like the trait bound nexus::Nexus: std::ops::Fn<(ws::Message,)> is not satisfied and type mismatch resolving closure.

All I'm simply trying to do is write a chat server using listen() that can uniquely identify and talk to individual connections (users and channels). The Handler doesn't provide enough as I have a hard time hooking into the client's Sender.

Any help would be appreciated.

compilation fails with Clone for mio::Sender<Command> not satisfied

I'm compiling the server example using the stable-x86_64-unknown-linux-gnu toolchain
This is the error I get:
src/communication.rs:49:5: 49:34 error: the trait bound mio::Sender<communication::Command>: std::clone::Clone is not satisfied [E0277]
src/communication.rs:49 channel: mio::Sender,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/communication.rs:46:17: 46:22 note: in this expansion of #[derive_Clone](defined in src/communication.rs)
src/communication.rs:49:5: 49:34 help: run rustc --explain E0277 to see a detailed explanation
src/communication.rs:49:5: 49:34 note: required by std::clone::Clone::clone
error: aborting due to previous error
Build failed, waiting for other jobs to finish...
error: Could not compile ws.

Can't compile

$cargo --version
cargo 0.6.0 (e1ed995 2015-10-22)
$rustc --version
rustc 1.4.0
$cargo build
Compiling ws v0.3.1 (file:///root/ws-rs)
src/result.rs:116:49: 116:57 error: no method named `as_ref` found for type `&Box` in the current scope
src/result.rs:116             Kind::Custom(ref err)   => Some(err.as_ref()),
                                                                  ^~~~~~~~
src/result.rs:116:49: 116:57 note: the method `as_ref` exists but the following trait bounds were not satisfied: `Box : core::convert::AsRef<_>`
error: aborting due to previous error
Could not compile `ws`.

Make the request available to the factory closure

I'd like to be able to reject request based on the url path as early as possible. Right now it seems to only be possible in the Handler on_open() through the request. It would be ideal to be able to do it in the listen() closure.

WS Error <Parse(Token)>: Invalid byte where token is required.

Hi!

I'm trying to implement a simple server to obtain and save automatically some informations.
When I use Telnet to connect to the server, I get this error from WS:
WS Error <Parse(Token)>: Invalid byte where token is required.

Also, this is the error from telnet:

Trying 127.0.0.1...  
Connected to localhost.  
Escape character is '^]'.  
hi  
HTTP/1.1 500 Internal Server Error  
Unable to parse HTTP: Invalid byte where token is required.Connection closed by foreign host.  

This is the code I use for the server:

extern crate argparse;
extern crate env_logger;
#[macro_use] extern crate log;
extern crate ws;

use argparse::{ArgumentParser, Store, StoreTrue};
use std::cell::Cell;
use std::rc::Rc;
use std::thread;
use ws::{CloseCode, connect, Error, Handshake, Handler, listen, Message, Result, Sender};

fn main() {

    // Initialize the environment logger
    env_logger::init().unwrap();

    // Ip field; default is localhost
    let mut ip : String = "127.0.0.1".to_string();
    // Port field; default is 8888
    let mut port : u16 = 8888;
    // Verbose mod for logs
    let mut verbose : bool = false;

    // Parse arguments
    {
        let mut arguments_parser = ArgumentParser::new();
        arguments_parser.set_description("Carolina reaper: The Hot-Pepper framework server.");
        arguments_parser.refer(&mut ip)
                        .add_option(&["--ip"], Store, "IP to launch the server");
        arguments_parser.refer(&mut port)
                        .add_option(&["--port"], Store, "Port to listen");
        arguments_parser.refer(&mut verbose)
                        .add_option(&["-v", "--verbose"], StoreTrue, "Be verbose");
        arguments_parser.parse_args_or_exit();
    }

    debug!("Initialize server with ip {} on port {}", ip, port);

    struct Server {
        out: Sender,
    }

    impl Handler for Server {

        fn on_open(&mut self, _: Handshake) -> Result<()> {
            println!("Open new connection!");
            self.out.send("Hello_World!")
        }

        fn on_message(&mut self, msg: Message) -> Result<()> {
            self.out.send(msg)
        }

        fn on_error(&mut self, err: Error) {
            println!("The server encountered an error: {:?}", err);
        }

    }

    let server = thread::spawn(move || {
        listen("127.0.0.1:8888", |out| {

            Server { out: out }

        }).unwrap()
    });

    let _ = server.join();

}

Thanks for all!

Dependencies in Cargo.toml

Hey,

I noticed Cargo pulls lots of outdated dependencies into this project when building, to the point when it causes errors due to different versions of one crate (this one uses url v0.5.9, and hyper uses url v1.something) being used.

Could you please update your Cargo.toml in order to use specified versions and not *s?

Thanks in advance!

EDIT: Just noticed you've got a stable-branch which contains actual non-starred versions. Then my request is to update the dependencies to their more recent versions.

Implementing Handler and Factory traits for a single struct

(Question)

I'm having a problem when implementing both traits for a since struct.

When implementing the Factory, my associated type for Self::Handler is my 'client' struct. So I try to return self in that case, like so:

impl Factory for MyClient {
    type Handler = MyClient;
    fn connection_made(&mut self, Sender) -> Self::Handler {
        *self
    }
}

However, this means I'm moving a borrowed struct, so this fails to compile:

   Compiling ws-pepe v0.1.0 (file:///Users/jalmeida/tmp/ws-pepe)
src/main.rs:96:3: 96:8 error: cannot move out of borrowed content [E0507]
src/main.rs:96          *self
                        ^~~~~
src/main.rs:96:3: 96:8 help: run `rustc --explain E0507` to see a detailed explanation
error: aborting due to previous error
Could not compile `ws-pepe`.

Could you possibly recommend a work around? I'm trying to have 3+ clients also act as servers in order to have a simple peer-to-peer conversation.

I'm pretty sure I'm doing something wrong, but most of your examples all have separate structs for implementing handlers for clients and servers, so I can't see a trivial solution.

Sending a borrow of a Message?

Let me just start by saying that I'm absolutely in love with what you are doing here.

I'm building a silly WebSocket game for fun, and the first building block that I'm laying down for it is a chat system. One problem I've run into is sending messages to multiple clients at the same time - I end up generating the same owned Vec<u8> per Sender, which is just duplicated data. I've seen that Message implements derived Clone, but I gather that also duplicates the vector (correct me if I'm wrong, still wrapping my head around Rust).

I can't really use the built in broadcast since not all clients are in all chat rooms, generating a single Message and then borrowing it to each Sender seems like the simplest, most idiomatic way to do things, but I don't really know the inner guts of MIO well enough to know if that's a good idea or not. Having a way to send an Arc<Message> or aggregating Senders into a single method call somehow would also work.

Cheers!

Can't connect to example server

When I run the server example and try to do

ws = new WebSocket('ws://127.0.0.1:3012')

in Firefox's devtools, Firefox spits out a "can't estabilish connection" error.
This is the log from such a run, gathered with RUST_LOG=trace (I cut out some repeated lines from mio::timer to keep it relatively short):

TRACE:mio::poll: registering with poller
TRACE:mio::poll: registering with poller
TRACE:mio::sys::windows::selector: unset_readiness; token=Token(0); set=Readable
TRACE:mio::sys::windows::tcp: scheduling an accept
INFO:ws: Listening for new connections on 127.0.0.1:3012.
TRACE:mio::event_loop: event loop tick
TRACE:mio::sys::windows::tcp: finished an accept
TRACE:mio::sys::windows::selector: push_event; token=Token(0); set=Readable; opts=Level-Triggered
TRACE:mio::event_loop: event=IoEvent { kind: Readable, token: Token(0) }
TRACE:mio::sys::windows::selector: unset_readiness; token=Token(0); set=Readable
TRACE:mio::sys::windows::tcp: scheduling an accept
INFO:ws::io: Accepted a new tcp connection from 127.0.0.1:49282.
TRACE:mio::poll: registering with poller
TRACE:mio::sys::windows::selector: unset_readiness; token=Token(1); set=Readable
TRACE:mio::sys::windows::tcp: scheduling a read
TRACE:mio::timer: tick_to; now=65; tick=0
TRACE:mio::timer: ticking; curr=Token(18446744073709551615)
TRACE:mio::timer: ticking; curr=Token(18446744073709551615)
TRACE:mio::timer: ticking; curr=Token(18446744073709551615)
// (...)
TRACE:mio::timer: ticking; curr=Token(18446744073709551615)
TRACE:mio::timer: ticking; curr=Token(18446744073709551615)
TRACE:mio::timer: ticking; curr=Token(18446744073709551615)
TRACE:mio::event_loop: event loop tick
TRACE:mio::sys::windows::tcp: finished a read: 497
TRACE:mio::sys::windows::selector: push_event; token=Token(1); set=Readable; opts=Edge-Triggered | OneShot
TRACE:mio::sys::windows::selector: deregistering because of oneshot
TRACE:mio::event_loop: event=IoEvent { kind: Readable, token: Token(1) }
ERROR:ws::handler: WS Error <Io(Error { repr: Os { code: 10057, message: "\u{17b}\u{105}danie wys\u{142}ania lub odebrania danych zosta\u{142}o zablokowane, poniewa\u{17c} gniazdo nie jest pod\u{142}\u{105}czone i (podczas wysy\u{142}ania przez gniazdo datagramu przy u\u{17c}yciu wywo\u{142}ania \u{201e}wy\u{15b}lij do\u{201d}) nie podano adresu." } })>
ERROR:ws::handler: WS Error <Io(Error { repr: Os { code: 10057, message: "\u{17b}\u{105}danie wys\u{142}ania lub odebrania danych zosta\u{142}o zablokowane, poniewa\u{17c} gniazdo nie jest pod\u{142}\u{105}czone i (podczas wysy\u{142}ania przez gniazdo datagramu przy u\u{17c}yciu wywo\u{142}ania \u{201e}wy\u{15b}lij do\u{201d}) nie podano adresu." } })>
TRACE:mio::sys::windows::selector: deregister; token=Token(1)
TRACE:ws::io: Active connections 0
TRACE:mio::timer: tick_to; now=65; tick=66
TRACE:mio::event_loop: event loop tick

The referenced error is 10057 on this page (error message is in my OS's locale, hence the escaped non-ASCII characters). This happens both on master and stable.

I also took the liberty of bisecting both stable branch and master (making sure to cargo clean between iterations) and, according to bisect, this commit is the one that introduced the regression on stable, and this one introduced it on master. The bisect results seem rather weird to me, but maybe they're at least a little informative.

In case this is relevant (it probably is?) I'm using Windows 8.1.

Handler Implementation Helpers

In more complex applications it is often necessary to wrap handlers and proxy various methods to the subhandler or subhandlers. However, this often entails implementing a bunch of handler methods that do no more than this.inner.handler_method(...). For example, see the router. A nasty side-effect of this requirement is that, if there are ever methods added to the Handler trait, those methods will not be proxied to the inner handler and instead call the default implementation unless the implementor is paying very close attention to changes in WS-RS (again read [router(https://github.com/housleyjk/ws-rs/blob/stable/examples/router.rs) very closely and you will see that it is missing methods).

We need a macro in WS-RS that aids in wrapping handlers within handlers to ensure all non-overriden methods go to the wrapped handler.

In addition, it would be nice to have a router macro that uses a macro-defined enum to proxy to handlers so that url routing doesn't have to rely on boxed handlers or require a bunch of boilerplate in each method (e.g. match self.inner { Sub1 {..} => ..., Sub2{..} => ...).

Can't seem to open more than 100 websocket connections

Hi Guys,

Am trying out the server example and when I connect to the server using websocket library from nodejs, I am unable to open more than 100 ws connections.

Is this some limit win WS-RS that I need to set somewhere ?

How to proxy ssl using nginx

In a production environment, it is a good idea to run the WebSocket server(s) behind a reverse proxy such as nginx. This allows for supporting more complex configurations than would otherwise be possible with a bare WebSocket server. One major advantage of using a reverse proxy is support for wss (SSL). Recent versions of nginx support WebSockets, so an example config is actually rather simple:

server {
    listen localhost:3443;

    ssl on;
    ssl_certificate /etc/nginx/ssl/snakeoil.crt;
    ssl_certificate_key /etc/nginx/ssl/snakeoil.key;

    location / {                                                                                                                                                                                         
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:3012;                                                                                                                                                                                                  
    }     
}

This example demonstrates running the server on a local machine with a self-signed key. In order to work, the WebSocket server needs to run on port 3012, and clients connect through port 3443. For example, in javascript var socket = new WebSocket("wss://localhost:3443"). The location / directive means that only websocket connections will be available on this server.

This local configuration was tested using nginx 1.8.

Fails to compile on Rust stable 1.5 / Windows

   Compiling ws v0.4.1
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:136:28: 136:56 error: the tra
it `std::sys::ext::io::AsRawSocket` is not implemented for the type `mio::net::tcp::TcpStream` [E0277]
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:136             Server => try
!(NonblockingSslStream::accept(

  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:136:23: 138:50 note: in this
expansion of try! (defined in <std macros>)
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:136:28: 136:56 help: run `rus
tc --explain E0277` to see a detailed explanation
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:136:28: 136:56 note: required
 by `openssl::ssl::NonblockingSslStream<S>::accept`
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:140:28: 140:57 error: the tra
it `std::sys::ext::io::AsRawSocket` is not implemented for the type `mio::net::tcp::TcpStream` [E0277]
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:140             Client => try
!(NonblockingSslStream::connect(

  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:140:23: 142:50 note: in this
expansion of try! (defined in <std macros>)
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:140:28: 140:57 help: run `rus
tc --explain E0277` to see a detailed explanation
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:140:28: 140:57 note: required
 by `openssl::ssl::NonblockingSslStream<S>::connect`
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:169:38: 169:67 error: the tra
it `std::sys::ext::io::AsRawSocket` is not implemented for the type `mio::net::tcp::TcpStream` [E0277]
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:169
       try!(NonblockingSslStream::connect(

            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:169:33: 171:43 note: in this
expansion of try! (defined in <std macros>)
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:169:38: 169:67 help: run `rus
tc --explain E0277` to see a detailed explanation
C:\Users\nathan\.cargo\registry\src\github.com-0a35038f75765ae4\ws-0.4.1\src\connection.rs:169:38: 169:67 note: required
 by `openssl::ssl::NonblockingSslStream<S>::connect`
error: aborting due to 3 previous errors
Could not compile `ws`.

Do not work on 32 bit linux

Cannot compile.

ws-0.4.2/src/frame.rs:397:17: 397:26 error: transmute called with differently sized types: usize (32 bits) to [u8; 8](64 bits) [E0512]
ws-0.4.2/src/frame.rs:397 transmute(self.payload.len().to_be())

How to keep client connection?

Hi,

I am newbie in Rust, something confuse me few day.

want to using ws-rs to replace current project with rust-websocket, due to performance seen like better than rust-websocket.

I see the example on Github repo and http://housleyjk.github.io/ws-rs/ws/index.html
And test client without any problem.

But is there any example about client keep connect and Tx/Rx message between server?(Like chat room)

because I found in Handler for client,
fn on_message() always need self.out.close(), that will disconnect from server when client Rx any message from server.

But I need it keep connection. Can I do that in rs-ws?
Thanks!

Close Connection(Sender) By Token ?

example:

struct Server {
    out: Sender,
}
impl Handler for Server {\

    fn on_message(&self, msg: ws::Message) -> ws::Result<()> {
        if msg.to_string() == "/ban 5" {
            // close connection (token is 5)
            //  Where do i find Connection with token 5 ? 
            //  if not support, i will record all Connection to one BTreeMap when trigger for `on_open` event. 
         }
     }
}

Long lived websocket - Client

There seems to be no way to have the websocket running in a thread (i.e. have the blocking connect run in a separate thread) and collect data to send to server via a channel. Mio has message passing to achieve that but here i failed to see that sort of design. Is it possible to have something like on_message_to_send_received(msg: Vec<u8>) in Handler and send_message(msg: Vec<u8>) with Sender exposed to outside connect(...) so that we can do something like:

// From thread-1
sender.send_message(vec_u8);
sender.close_ws();
...
// In thread-2 where Ws Client is running
impl Handler for Client {
fn on_message_to_send_received(&self, msg: Vec<u8>) {
   self.sender.send(Message(msg));
}
fn on_close_ws_received(&self) {
   self.sender.close(CloseCode::Normal)
}

Can we have this kind of paradigm with this crate?

Different behaviour ws:// vs wss:// on refuse connection

I have no server on port 3012.

extern crate ws;
extern crate env_logger;

fn main() {
  env_logger::init().unwrap();

  let bind_addr = "127.0.0.1:3012";
  println!("START");
  if let Err(_) = ws::connect(format!("ws://{}", bind_addr), |out| {
    if let Err(_) = out.send("killprev") {
      println!("Fail to send killprev.")
    };
    move |_msg| {
      out.close(ws::CloseCode::Normal)
    }
  }) {
    println!("no ws listen");
  };
  println!("MIDDLE");
  if let Err(_) = ws::connect(format!("wss://{}", bind_addr), |out| {
    if let Err(_) = out.send("killprev") {
      println!("Fail to send killprev.")
    };
    move |_msg| {
      out.close(ws::CloseCode::Normal)
    }
  }) {
    println!("no wss listen");
  };
  println!("END");
}

Cargo.toml

[dependencies]
env_logger = "0.3.2"

[dependencies.ws]
features = ["ssl"]
git = "https://github.com/housleyjk/ws-rs" 

I expect messages "MIDDLE" and "END"
result:

START
ERROR:ws::handler: WS Error <Io(Error { repr: Os { code: 111, message: "Connection refused" } })>
MIDDLE
ERROR:ws::io: Unable to establish connection to wss://0.0.0.0:3012/: WS Error <Ssl(StreamError(Error { repr: Os { code: 111, message: "Connection refused" } }))>
ERROR:ws::handler: WS Error <Io(Error { repr: Os { code: 2, message: "No such file or directory" } })>

btw:
I think "connect" should have some callback interface for "connection refuse", "disconnect" and other errors.
I expect that connection errors would produce "no ws listen" and "no wss listen" messages.
I expect messages "Fail to send killprev" or no "|out| {" callback call at all.

P.s. branch=stable (df33787) doesn't help.

Interfacing outside websockets

Not really an issue, but I couldn't find anywhere else to put this...
I have a websocket server; when a client connects I need to POST to a http endpoint to verify their token. I could put the request in on_message (using Hyper or so), but that'd gum up the event loop. Is there any better, more idiomatic way to do this with ws-rs?

Specify stricter version requirements on dependencies

When specifying dependencies with * things will break for the users unexpectedly. Tilde requirements would be a good but conservative specification. If you want to track the latest as much as possible but minimize risk go for caret requirements.

Debugger breakpoints errnoeously kill the ws-rs event loop

I've encountered some trouble trying to debug an application which uses this library. When I use gdb to breakpoint such an application: as soon as ws-rs gets control it immediately aborts its event loop and shuts down.

What seems to be happening is that the read times out since GDB is paused, so when the event loop thread gets control it executes src/io.rs:637

fn interrupted(&mut self, eloop: &mut Loop<F>) { ... }

The implementation there immediately shuts down the event loop. (Which in my particular application makes it impossible to debug any I/O coming into the process from the outside world.)

I'm not very familiar with mio but my guess is that ws-rs is treating this as though it's catching SIGINT ... whereas what is probably happening is that while GDB is paused on a breakpoint mio's call to epoll_wait() (or a similar mechanism) is throwing EINTR since the read times out.

As I understand it this shouldn't be a fatal error, but rather a signal to retry later, for e.g:

So as best I can tell: the entire #interrupted() handler should get removed. If this code were to be replaced with anything it should be an actual SIGINT handler, rather than a handler which traps anything of the io::ErrorKind::Interrupted variant. (Though as a consumer of this library I personally would expect that I need to handle SIGINT in my application and tear down the event loop myself.)

WebSocket Config

Hi, i have 2 questions:
Question 1:
How can i new one WebSocket (https://github.com/housleyjk/ws-rs/blob/master/src/lib.rs#L252) struct with Settings (https://github.com/housleyjk/ws-rs/blob/master/src/lib.rs#L123) ?

they are use default setting:

i want change some settings, like max-connections .

Question 2:
how can i close one remote connection ?
does this work ?

struct Server {
    out: Sender,
   // channels: Channels
}
impl Handler for Server {
    fn on_close(&mut self, code: CloseCode, reason: &str) {
        println!("WebSocket closing by ({:?}) for ({:?}:{}) ", self.out.token(), code, reason);
        self.out.close(CloseCode::Normal);
    }
}

thx.

Support SSL server

Unless I am misunderstanding ws-rs only supports SSL for client connections. It would be nice if the server could listen using SSL as well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.