From 16f7649b29d2d7ad3a8acdf00ccf2678030e509d Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Fri, 11 May 2018 14:35:43 -0700 Subject: [PATCH] split websocket-chat example --- Cargo.lock | 221 ++++++++--------- Cargo.toml | 1 + r2d2/Cargo.toml | 2 +- websocket-chat/Cargo.toml | 5 - websocket-chat/README.md | 6 +- websocket-chat/src/main.rs | 17 +- websocket-chat/src/server.rs | 16 +- websocket-chat/src/session.rs | 55 ----- websocket-tcp-chat/Cargo.toml | 29 +++ websocket-tcp-chat/README.md | 32 +++ websocket-tcp-chat/client.py | 72 ++++++ .../src/client.rs | 0 websocket-tcp-chat/src/codec.rs | 122 ++++++++++ websocket-tcp-chat/src/main.rs | 226 ++++++++++++++++++ websocket-tcp-chat/src/server.rs | 200 ++++++++++++++++ websocket-tcp-chat/src/session.rs | 225 +++++++++++++++++ websocket-tcp-chat/static/websocket.html | 90 +++++++ 17 files changed, 1109 insertions(+), 210 deletions(-) create mode 100644 websocket-tcp-chat/Cargo.toml create mode 100644 websocket-tcp-chat/README.md create mode 100755 websocket-tcp-chat/client.py rename {websocket-chat => websocket-tcp-chat}/src/client.rs (100%) create mode 100644 websocket-tcp-chat/src/codec.rs create mode 100644 websocket-tcp-chat/src/main.rs create mode 100644 websocket-tcp-chat/src/server.rs create mode 100644 websocket-tcp-chat/src/session.rs create mode 100644 websocket-tcp-chat/static/websocket.html diff --git a/Cargo.lock b/Cargo.lock index f0763172..f28da45c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,7 +26,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "backoff 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -35,7 +35,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "redis-async 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -43,52 +43,7 @@ dependencies = [ [[package]] name = "actix-web" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "brotli2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "http-range 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "actix-web" -version = "0.6.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -120,13 +75,13 @@ dependencies = [ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-openssl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -139,13 +94,13 @@ name = "actix-web-cors" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -198,7 +153,7 @@ dependencies = [ "askama_shared 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -224,11 +179,11 @@ name = "awc_examples" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "validator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "validator_derive 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -300,7 +255,7 @@ name = "basics" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -368,8 +323,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -388,9 +343,9 @@ name = "chrono" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -400,7 +355,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -409,11 +364,11 @@ name = "cookie-auth" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -421,10 +376,10 @@ name = "cookie-session" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -545,14 +500,14 @@ name = "diesel-example" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "diesel 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -794,7 +749,7 @@ name = "hello-world" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -821,7 +776,7 @@ name = "http-proxy" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -856,7 +811,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -918,13 +873,13 @@ name = "json-example" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -937,8 +892,8 @@ dependencies = [ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "juniper_codegen 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "ordermap 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -948,12 +903,12 @@ name = "juniper-example" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "juniper 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1141,7 +1096,7 @@ name = "multipart-example" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1171,15 +1126,15 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.36" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1218,7 +1173,7 @@ name = "ordermap" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1350,7 +1305,7 @@ name = "protobuf-example" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1408,14 +1363,14 @@ name = "r2d2-example" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2_sqlite 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rusqlite 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1486,7 +1441,7 @@ version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "actix-redis 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1580,7 +1535,7 @@ dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "libsqlite3-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1626,7 +1581,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1636,17 +1591,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.50" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.50" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1656,7 +1611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1666,7 +1621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1733,7 +1688,7 @@ name = "state" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1765,7 +1720,7 @@ dependencies = [ [[package]] name = "syn" -version = "0.13.7" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1804,7 +1759,7 @@ name = "template-askama" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "askama 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1814,7 +1769,7 @@ name = "template-tera" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "tera 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1832,7 +1787,7 @@ dependencies = [ "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "slug 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1867,7 +1822,7 @@ dependencies = [ [[package]] name = "time" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1880,7 +1835,7 @@ name = "tls-example" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2114,7 +2069,7 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2137,7 +2092,7 @@ name = "unix-socket" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2177,7 +2132,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2198,8 +2153,8 @@ dependencies = [ "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2211,7 +2166,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.8 (registry+https://github.com/rust-lang/crates.io-index)", "validator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2245,7 +2200,7 @@ name = "websocket" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2256,14 +2211,31 @@ name = "websocket-example" version = "0.1.0" dependencies = [ "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "websocket-tcp-example" +version = "0.1.0" +dependencies = [ + "actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2339,8 +2311,7 @@ dependencies = [ [metadata] "checksum actix 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e767e3170dc7cdec50fe1b74d22fd9d2f4b78b97b2052a254b5acb07dae68634" "checksum actix-redis 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6ed04247bb9ee9a2a9a0ad808049de379d8197719bbb22ea0a56e9a10f55a50" -"checksum actix-web 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebda1eae1638d03af2fc27a7d57c5fd035901a949f548d7c72ff5e07f5052d9f" -"checksum actix-web 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a32c694413af2fd0f3f3bb9fcc820ca5eb081c810dd77f023d07957fac4296d3" +"checksum actix-web 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "301a0997ba2872ceecf2cfef43542e16f00f83f40212ab24642e200fb537ecb2" "checksum actix_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b1dc922654b9aca7a8a31eab875fde804fa9fbd67f220f2e457787b23590f2" "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" @@ -2450,8 +2421,8 @@ dependencies = [ "checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" -"checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe" -"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" +"checksum num-integer 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "2fef16815bb502c6a3be7fd842b7fd6e3371d5fbd33acc8ada7cc6c616cb4798" +"checksum num-traits 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c22f20a157cb4af265c71e47db525852368feeb4a0013f0f8c68a7f4ef0d0fc1" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum openssl 0.10.7 (registry+https://github.com/rust-lang/crates.io-index)" = "63c6ff2c7d9903daf9f3429eb2f6beedb15b1f7362e3529e5bf00b6caf182400" "checksum openssl-sys 0.9.30 (registry+https://github.com/rust-lang/crates.io-index)" = "73ae718c3562989cd3a0a5c26610feca02f8116822f6f195e6cf4887481e57f5" @@ -2501,8 +2472,8 @@ dependencies = [ "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "428d3d818cb94ee037a17bf4f2200db2552e19b1825d33df2196624290716f92" -"checksum serde_derive 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "ee76093b16868c4c9c8e5329c3d30745833e35390624019738472bd13e996e79" +"checksum serde 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)" = "de4dee3b122edad92d80c66cac8d967ec7f8bf16a3b452247d6eb1dbf83c8f22" +"checksum serde_derive 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)" = "7149ef7af607b09e0e7df38b1fd74264f08a29a67f604d5cb09d3fbdb1e256bc" "checksum serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f3ad6d546e765177cf3dded3c2e424a8040f870083a0e64064746b958ece9cb1" "checksum serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce0fd303af908732989354c6f02e05e2e6d597152870f2c6990efb0577137480" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" @@ -2516,7 +2487,7 @@ dependencies = [ "checksum string 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31f98b200e7caca9efca50fc0aa69cd58a5ec81d5f6e75b2f3ecaad2e998972a" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5" -"checksum syn 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)" = "61b8f1b737f929c6516ba46a3133fd6d5215ad8a62f66760f851f7048aebedfb" +"checksum syn 0.13.8 (registry+https://github.com/rust-lang/crates.io-index)" = "70f57ecb0ad755f810029917826394be7d5d3975e875028ff9d58ac71e640d80" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" @@ -2524,7 +2495,7 @@ dependencies = [ "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" -"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" +"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" "checksum tokio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d00555353b013e170ed8bc4e13f648a317d1fd12157dbcae13f7013f6cf29f5" "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" "checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" @@ -2544,7 +2515,7 @@ dependencies = [ "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90d662d111b0dbb08a180f2761026cba648c258023c355954a7c00e00e354636" +"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unidecode 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc" diff --git a/Cargo.toml b/Cargo.toml index ce6d56a1..535a0cee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,4 +22,5 @@ members = [ "web-cors/backend", "websocket", "websocket-chat", + "websocket-tcp-chat", ] diff --git a/r2d2/Cargo.toml b/r2d2/Cargo.toml index 83e77abb..99bbeded 100644 --- a/r2d2/Cargo.toml +++ b/r2d2/Cargo.toml @@ -7,7 +7,7 @@ workspace = "../" [dependencies] env_logger = "0.5" actix = "0.5" -actix-web = "^0.5" +actix-web = "^0.6" futures = "0.1" uuid = { version = "0.5", features = ["serde", "v4"] } diff --git a/websocket-chat/Cargo.toml b/websocket-chat/Cargo.toml index 2542a512..5b53a70f 100644 --- a/websocket-chat/Cargo.toml +++ b/websocket-chat/Cargo.toml @@ -8,10 +8,6 @@ workspace = "../" name = "server" path = "src/main.rs" -[[bin]] -name = "client" -path = "src/client.rs" - [dependencies] rand = "*" bytes = "0.4" @@ -23,7 +19,6 @@ env_logger = "*" serde = "1.0" serde_json = "1.0" -serde_derive = "1.0" actix = "0.5" actix-web = "^0.6" diff --git a/websocket-chat/README.md b/websocket-chat/README.md index a01dd68b..a463cfed 100644 --- a/websocket-chat/README.md +++ b/websocket-chat/README.md @@ -13,9 +13,9 @@ Added features: Chat server listens for incoming tcp connections. Server can access several types of message: -* `\list` - list all available rooms -* `\join name` - join room, if room does not exist, create new one -* `\name name` - set session name +* `/list` - list all available rooms +* `/join name` - join room, if room does not exist, create new one +* `/name name` - set session name * `some message` - just string, send message to all peers in same room * client has to send heartbeat `Ping` messages, if server does not receive a heartbeat message for 10 seconds connection gets dropped diff --git a/websocket-chat/src/main.rs b/websocket-chat/src/main.rs index be9dfa73..9a97b110 100644 --- a/websocket-chat/src/main.rs +++ b/websocket-chat/src/main.rs @@ -8,8 +8,6 @@ extern crate serde; extern crate serde_json; extern crate tokio_core; extern crate tokio_io; -#[macro_use] -extern crate serde_derive; #[macro_use] extern crate actix; @@ -22,9 +20,7 @@ use actix_web::server::HttpServer; use actix_web::ws::WsWriter; use actix_web::{fs, http, ws, App, Error, HttpRequest, HttpResponse}; -mod codec; mod server; -mod session; /// This is our websocket route state, this state is shared with all route /// instances via `HttpContext::state()` @@ -96,10 +92,10 @@ impl Actor for WsChatSession { } /// Handle messages from chat server, we simply send it to peer websocket -impl Handler for WsChatSession { +impl Handler for WsChatSession { type Result = (); - fn handle(&mut self, msg: session::Message, ctx: &mut Self::Context) { + fn handle(&mut self, msg: server::Message, ctx: &mut Self::Context) { ctx.text(msg.0); } } @@ -170,7 +166,7 @@ impl StreamHandler for WsChatSession { m.to_owned() }; // send message to chat server - ctx.state().addr.do_send(server::Message { + ctx.state().addr.do_send(server::ClientMessage { id: self.id, msg: msg, room: self.room.clone(), @@ -192,13 +188,6 @@ fn main() { // Start chat server actor in separate thread let server: Addr = Arbiter::start(|_| server::ChatServer::default()); - // Start tcp server in separate thread - let srv = server.clone(); - Arbiter::new("tcp-server").do_send::(msgs::Execute::new(move || { - session::TcpServer::new("127.0.0.1:12345", srv); - Ok(()) - })); - // Create Http server with websocket support HttpServer::new(move || { // Websocket sessions state diff --git a/websocket-chat/src/server.rs b/websocket-chat/src/server.rs index a69c49a4..41fcb970 100644 --- a/websocket-chat/src/server.rs +++ b/websocket-chat/src/server.rs @@ -7,7 +7,9 @@ use rand::{self, Rng, ThreadRng}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; -use session; +/// Chat server sends this messages to session +#[derive(Message)] +pub struct Message(pub String); /// Message for chat server communications @@ -15,7 +17,7 @@ use session; #[derive(Message)] #[rtype(usize)] pub struct Connect { - pub addr: Recipient, + pub addr: Recipient, } /// Session is disconnected @@ -26,7 +28,7 @@ pub struct Disconnect { /// Send message to specific room #[derive(Message)] -pub struct Message { +pub struct ClientMessage { /// Id of the client session pub id: usize, /// Peer message @@ -54,7 +56,7 @@ pub struct Join { /// `ChatServer` manages chat rooms and responsible for coordinating chat /// session. implementation is super primitive pub struct ChatServer { - sessions: HashMap>, + sessions: HashMap>, rooms: HashMap>, rng: RefCell, } @@ -80,7 +82,7 @@ impl ChatServer { for id in sessions { if *id != skip_id { if let Some(addr) = self.sessions.get(id) { - let _ = addr.do_send(session::Message(message.to_owned())); + let _ = addr.do_send(Message(message.to_owned())); } } } @@ -148,10 +150,10 @@ impl Handler for ChatServer { } /// Handler for Message message. -impl Handler for ChatServer { +impl Handler for ChatServer { type Result = (); - fn handle(&mut self, msg: Message, _: &mut Context) { + fn handle(&mut self, msg: ClientMessage, _: &mut Context) { self.send_message(&msg.room, msg.msg.as_str(), msg.id); } } diff --git a/websocket-chat/src/session.rs b/websocket-chat/src/session.rs index d53ea2a3..87c63622 100644 --- a/websocket-chat/src/session.rs +++ b/websocket-chat/src/session.rs @@ -168,58 +168,3 @@ impl ChatSession { }); } } - -/// Define tcp server that will accept incoming tcp connection and create -/// chat actors. -pub struct TcpServer { - chat: Addr, -} - -impl TcpServer { - pub fn new(s: &str, chat: Addr) { - // Create server listener - let addr = net::SocketAddr::from_str("127.0.0.1:12345").unwrap(); - let listener = TcpListener::bind(&addr, Arbiter::handle()).unwrap(); - - // Our chat server `Server` is an actor, first we need to start it - // and then add stream on incoming tcp connections to it. - // TcpListener::incoming() returns stream of the (TcpStream, net::SocketAddr) - // items So to be able to handle this events `Server` actor has to - // implement stream handler `StreamHandler<(TcpStream, - // net::SocketAddr), io::Error>` - let _: () = TcpServer::create(|ctx| { - ctx.add_message_stream( - listener - .incoming() - .map_err(|_| ()) - .map(|(t, a)| TcpConnect(t, a)), - ); - TcpServer { chat: chat } - }); - } -} - -/// Make actor from `Server` -impl Actor for TcpServer { - /// Every actor has to provide execution `Context` in which it can run. - type Context = Context; -} - -#[derive(Message)] -struct TcpConnect(TcpStream, net::SocketAddr); - -/// Handle stream of TcpStream's -impl Handler for TcpServer { - type Result = (); - - fn handle(&mut self, msg: TcpConnect, _: &mut Context) { - // For each incoming connection we create `ChatSession` actor - // with out chat server address. - let server = self.chat.clone(); - let _: () = ChatSession::create(|ctx| { - let (r, w) = msg.0.split(); - ChatSession::add_stream(FramedRead::new(r, ChatCodec), ctx); - ChatSession::new(server, actix::io::FramedWrite::new(w, ChatCodec, ctx)) - }); - } -} diff --git a/websocket-tcp-chat/Cargo.toml b/websocket-tcp-chat/Cargo.toml new file mode 100644 index 00000000..3461ba78 --- /dev/null +++ b/websocket-tcp-chat/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "websocket-tcp-example" +version = "0.1.0" +authors = ["Nikolay Kim "] +workspace = "../" + +[[bin]] +name = "server" +path = "src/main.rs" + +[[bin]] +name = "client" +path = "src/client.rs" + +[dependencies] +rand = "*" +bytes = "0.4" +byteorder = "1.1" +futures = "0.1" +tokio-io = "0.1" +tokio-core = "0.1" +env_logger = "*" + +serde = "1.0" +serde_json = "1.0" +serde_derive = "1.0" + +actix = "0.5" +actix-web = "^0.6" diff --git a/websocket-tcp-chat/README.md b/websocket-tcp-chat/README.md new file mode 100644 index 00000000..a463cfed --- /dev/null +++ b/websocket-tcp-chat/README.md @@ -0,0 +1,32 @@ +# Websocket chat example + +This is extension of the +[actix chat example](https://github.com/actix/actix/tree/master/examples/chat) + +Added features: + +* Browser WebSocket client +* Chat server runs in separate thread +* Tcp listener runs in separate thread + +## Server + +Chat server listens for incoming tcp connections. Server can access several types of message: + +* `/list` - list all available rooms +* `/join name` - join room, if room does not exist, create new one +* `/name name` - set session name +* `some message` - just string, send message to all peers in same room +* client has to send heartbeat `Ping` messages, if server does not receive a heartbeat message for 10 seconds connection gets dropped + +To start server use command: `cargo run --bin server` + +## Client + +Client connects to server. Reads input from stdin and sends to server. + +To run client use command: `cargo run --bin client` + +## WebSocket Browser Client + +Open url: [http://localhost:8080/](http://localhost:8080/) diff --git a/websocket-tcp-chat/client.py b/websocket-tcp-chat/client.py new file mode 100755 index 00000000..8a1bd9ae --- /dev/null +++ b/websocket-tcp-chat/client.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +"""websocket cmd client for wssrv.py example.""" +import argparse +import asyncio +import signal +import sys + +import aiohttp + + +def start_client(loop, url): + name = input('Please enter your name: ') + + # send request + ws = yield from aiohttp.ClientSession().ws_connect(url, autoclose=False, autoping=False) + + # input reader + def stdin_callback(): + line = sys.stdin.buffer.readline().decode('utf-8') + if not line: + loop.stop() + else: + ws.send_str(name + ': ' + line) + loop.add_reader(sys.stdin.fileno(), stdin_callback) + + @asyncio.coroutine + def dispatch(): + while True: + msg = yield from ws.receive() + + if msg.type == aiohttp.WSMsgType.TEXT: + print('Text: ', msg.data.strip()) + elif msg.type == aiohttp.WSMsgType.BINARY: + print('Binary: ', msg.data) + elif msg.type == aiohttp.WSMsgType.PING: + ws.pong() + elif msg.type == aiohttp.WSMsgType.PONG: + print('Pong received') + else: + if msg.type == aiohttp.WSMsgType.CLOSE: + yield from ws.close() + elif msg.type == aiohttp.WSMsgType.ERROR: + print('Error during receive %s' % ws.exception()) + elif msg.type == aiohttp.WSMsgType.CLOSED: + pass + + break + + yield from dispatch() + + +ARGS = argparse.ArgumentParser( + description="websocket console client for wssrv.py example.") +ARGS.add_argument( + '--host', action="store", dest='host', + default='127.0.0.1', help='Host name') +ARGS.add_argument( + '--port', action="store", dest='port', + default=8080, type=int, help='Port number') + +if __name__ == '__main__': + args = ARGS.parse_args() + if ':' in args.host: + args.host, port = args.host.split(':', 1) + args.port = int(port) + + url = 'http://{}:{}/ws/'.format(args.host, args.port) + + loop = asyncio.get_event_loop() + loop.add_signal_handler(signal.SIGINT, loop.stop) + asyncio.Task(start_client(loop, url)) + loop.run_forever() diff --git a/websocket-chat/src/client.rs b/websocket-tcp-chat/src/client.rs similarity index 100% rename from websocket-chat/src/client.rs rename to websocket-tcp-chat/src/client.rs diff --git a/websocket-tcp-chat/src/codec.rs b/websocket-tcp-chat/src/codec.rs new file mode 100644 index 00000000..0670d6a7 --- /dev/null +++ b/websocket-tcp-chat/src/codec.rs @@ -0,0 +1,122 @@ +#![allow(dead_code)] +use byteorder::{BigEndian, ByteOrder}; +use bytes::{BufMut, BytesMut}; +use serde_json as json; +use std::io; +use tokio_io::codec::{Decoder, Encoder}; + +/// Client request +#[derive(Serialize, Deserialize, Debug, Message)] +#[serde(tag = "cmd", content = "data")] +pub enum ChatRequest { + /// List rooms + List, + /// Join rooms + Join(String), + /// Send message + Message(String), + /// Ping + Ping, +} + +/// Server response +#[derive(Serialize, Deserialize, Debug, Message)] +#[serde(tag = "cmd", content = "data")] +pub enum ChatResponse { + Ping, + + /// List of rooms + Rooms(Vec), + + /// Joined + Joined(String), + + /// Message + Message(String), +} + +/// Codec for Client -> Server transport +pub struct ChatCodec; + +impl Decoder for ChatCodec { + type Item = ChatRequest; + type Error = io::Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { + let size = { + if src.len() < 2 { + return Ok(None); + } + BigEndian::read_u16(src.as_ref()) as usize + }; + + if src.len() >= size + 2 { + src.split_to(2); + let buf = src.split_to(size); + Ok(Some(json::from_slice::(&buf)?)) + } else { + Ok(None) + } + } +} + +impl Encoder for ChatCodec { + type Item = ChatResponse; + type Error = io::Error; + + fn encode( + &mut self, msg: ChatResponse, dst: &mut BytesMut, + ) -> Result<(), Self::Error> { + let msg = json::to_string(&msg).unwrap(); + let msg_ref: &[u8] = msg.as_ref(); + + dst.reserve(msg_ref.len() + 2); + dst.put_u16::(msg_ref.len() as u16); + dst.put(msg_ref); + + Ok(()) + } +} + +/// Codec for Server -> Client transport +pub struct ClientChatCodec; + +impl Decoder for ClientChatCodec { + type Item = ChatResponse; + type Error = io::Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { + let size = { + if src.len() < 2 { + return Ok(None); + } + BigEndian::read_u16(src.as_ref()) as usize + }; + + if src.len() >= size + 2 { + src.split_to(2); + let buf = src.split_to(size); + Ok(Some(json::from_slice::(&buf)?)) + } else { + Ok(None) + } + } +} + +impl Encoder for ClientChatCodec { + type Item = ChatRequest; + type Error = io::Error; + + fn encode( + &mut self, msg: ChatRequest, dst: &mut BytesMut, + ) -> Result<(), Self::Error> { + let msg = json::to_string(&msg).unwrap(); + let msg_ref: &[u8] = msg.as_ref(); + + dst.reserve(msg_ref.len() + 2); + dst.put_u16::(msg_ref.len() as u16); + dst.put(msg_ref); + + Ok(()) + } +} diff --git a/websocket-tcp-chat/src/main.rs b/websocket-tcp-chat/src/main.rs new file mode 100644 index 00000000..be9dfa73 --- /dev/null +++ b/websocket-tcp-chat/src/main.rs @@ -0,0 +1,226 @@ +#![allow(unused_variables)] +extern crate byteorder; +extern crate bytes; +extern crate env_logger; +extern crate futures; +extern crate rand; +extern crate serde; +extern crate serde_json; +extern crate tokio_core; +extern crate tokio_io; +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate actix; +extern crate actix_web; + +use std::time::Instant; + +use actix::*; +use actix_web::server::HttpServer; +use actix_web::ws::WsWriter; +use actix_web::{fs, http, ws, App, Error, HttpRequest, HttpResponse}; + +mod codec; +mod server; +mod session; + +/// This is our websocket route state, this state is shared with all route +/// instances via `HttpContext::state()` +struct WsChatSessionState { + addr: Addr, +} + +/// Entry point for our route +fn chat_route(req: HttpRequest) -> Result { + ws::start( + req, + WsChatSession { + id: 0, + hb: Instant::now(), + room: "Main".to_owned(), + name: None, + }, + ) +} + +struct WsChatSession { + /// unique session id + id: usize, + /// Client must send ping at least once per 10 seconds, otherwise we drop + /// connection. + hb: Instant, + /// joined room + room: String, + /// peer name + name: Option, +} + +impl Actor for WsChatSession { + type Context = ws::WebsocketContext; + + /// Method is called on actor start. + /// We register ws session with ChatServer + fn started(&mut self, ctx: &mut Self::Context) { + // register self in chat server. `AsyncContext::wait` register + // future within context, but context waits until this future resolves + // before processing any other events. + // HttpContext::state() is instance of WsChatSessionState, state is shared + // across all routes within application + let addr: Addr = ctx.address(); + ctx.state() + .addr + .send(server::Connect { + addr: addr.recipient(), + }) + .into_actor(self) + .then(|res, act, ctx| { + match res { + Ok(res) => act.id = res, + // something is wrong with chat server + _ => ctx.stop(), + } + fut::ok(()) + }) + .wait(ctx); + } + + fn stopping(&mut self, ctx: &mut Self::Context) -> Running { + // notify chat server + ctx.state() + .addr + .do_send(server::Disconnect { id: self.id }); + Running::Stop + } +} + +/// Handle messages from chat server, we simply send it to peer websocket +impl Handler for WsChatSession { + type Result = (); + + fn handle(&mut self, msg: session::Message, ctx: &mut Self::Context) { + ctx.text(msg.0); + } +} + +/// WebSocket message handler +impl StreamHandler for WsChatSession { + fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) { + println!("WEBSOCKET MESSAGE: {:?}", msg); + match msg { + ws::Message::Ping(msg) => ctx.pong(&msg), + ws::Message::Pong(msg) => self.hb = Instant::now(), + ws::Message::Text(text) => { + let m = text.trim(); + // we check for /sss type of messages + if m.starts_with('/') { + let v: Vec<&str> = m.splitn(2, ' ').collect(); + match v[0] { + "/list" => { + // Send ListRooms message to chat server and wait for + // response + println!("List rooms"); + ctx.state() + .addr + .send(server::ListRooms) + .into_actor(self) + .then(|res, _, ctx| { + match res { + Ok(rooms) => { + for room in rooms { + ctx.text(room); + } + } + _ => println!("Something is wrong"), + } + fut::ok(()) + }) + .wait(ctx) + // .wait(ctx) pauses all events in context, + // so actor wont receive any new messages until it get list + // of rooms back + } + "/join" => { + if v.len() == 2 { + self.room = v[1].to_owned(); + ctx.state().addr.do_send(server::Join { + id: self.id, + name: self.room.clone(), + }); + + ctx.text("joined"); + } else { + ctx.text("!!! room name is required"); + } + } + "/name" => { + if v.len() == 2 { + self.name = Some(v[1].to_owned()); + } else { + ctx.text("!!! name is required"); + } + } + _ => ctx.text(format!("!!! unknown command: {:?}", m)), + } + } else { + let msg = if let Some(ref name) = self.name { + format!("{}: {}", name, m) + } else { + m.to_owned() + }; + // send message to chat server + ctx.state().addr.do_send(server::Message { + id: self.id, + msg: msg, + room: self.room.clone(), + }) + } + } + ws::Message::Binary(bin) => println!("Unexpected binary"), + ws::Message::Close(_) => { + ctx.stop(); + } + } + } +} + +fn main() { + let _ = env_logger::init(); + let sys = actix::System::new("websocket-example"); + + // Start chat server actor in separate thread + let server: Addr = Arbiter::start(|_| server::ChatServer::default()); + + // Start tcp server in separate thread + let srv = server.clone(); + Arbiter::new("tcp-server").do_send::(msgs::Execute::new(move || { + session::TcpServer::new("127.0.0.1:12345", srv); + Ok(()) + })); + + // Create Http server with websocket support + HttpServer::new(move || { + // Websocket sessions state + let state = WsChatSessionState { + addr: server.clone(), + }; + + App::with_state(state) + // redirect to websocket.html + .resource("/", |r| r.method(http::Method::GET).f(|_| { + HttpResponse::Found() + .header("LOCATION", "/static/websocket.html") + .finish() + })) + // websocket + .resource("/ws/", |r| r.route().f(chat_route)) + // static resources + .handler("/static/", fs::StaticFiles::new("static/")) + }).bind("127.0.0.1:8080") + .unwrap() + .start(); + + println!("Started http server: 127.0.0.1:8080"); + let _ = sys.run(); +} diff --git a/websocket-tcp-chat/src/server.rs b/websocket-tcp-chat/src/server.rs new file mode 100644 index 00000000..a69c49a4 --- /dev/null +++ b/websocket-tcp-chat/src/server.rs @@ -0,0 +1,200 @@ +//! `ChatServer` is an actor. It maintains list of connection client session. +//! And manages available rooms. Peers send messages to other peers in same +//! room through `ChatServer`. + +use actix::prelude::*; +use rand::{self, Rng, ThreadRng}; +use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; + +use session; + +/// Message for chat server communications + +/// New chat session is created +#[derive(Message)] +#[rtype(usize)] +pub struct Connect { + pub addr: Recipient, +} + +/// Session is disconnected +#[derive(Message)] +pub struct Disconnect { + pub id: usize, +} + +/// Send message to specific room +#[derive(Message)] +pub struct Message { + /// Id of the client session + pub id: usize, + /// Peer message + pub msg: String, + /// Room name + pub room: String, +} + +/// List of available rooms +pub struct ListRooms; + +impl actix::Message for ListRooms { + type Result = Vec; +} + +/// Join room, if room does not exists create new one. +#[derive(Message)] +pub struct Join { + /// Client id + pub id: usize, + /// Room name + pub name: String, +} + +/// `ChatServer` manages chat rooms and responsible for coordinating chat +/// session. implementation is super primitive +pub struct ChatServer { + sessions: HashMap>, + rooms: HashMap>, + rng: RefCell, +} + +impl Default for ChatServer { + fn default() -> ChatServer { + // default room + let mut rooms = HashMap::new(); + rooms.insert("Main".to_owned(), HashSet::new()); + + ChatServer { + sessions: HashMap::new(), + rooms: rooms, + rng: RefCell::new(rand::thread_rng()), + } + } +} + +impl ChatServer { + /// Send message to all users in the room + fn send_message(&self, room: &str, message: &str, skip_id: usize) { + if let Some(sessions) = self.rooms.get(room) { + for id in sessions { + if *id != skip_id { + if let Some(addr) = self.sessions.get(id) { + let _ = addr.do_send(session::Message(message.to_owned())); + } + } + } + } + } +} + +/// Make actor from `ChatServer` +impl Actor for ChatServer { + /// We are going to use simple Context, we just need ability to communicate + /// with other actors. + type Context = Context; +} + +/// Handler for Connect message. +/// +/// Register new session and assign unique id to this session +impl Handler for ChatServer { + type Result = usize; + + fn handle(&mut self, msg: Connect, _: &mut Context) -> Self::Result { + println!("Someone joined"); + + // notify all users in same room + self.send_message(&"Main".to_owned(), "Someone joined", 0); + + // register session with random id + let id = self.rng.borrow_mut().gen::(); + self.sessions.insert(id, msg.addr); + + // auto join session to Main room + self.rooms + .get_mut(&"Main".to_owned()) + .unwrap() + .insert(id); + + // send id back + id + } +} + +/// Handler for Disconnect message. +impl Handler for ChatServer { + type Result = (); + + fn handle(&mut self, msg: Disconnect, _: &mut Context) { + println!("Someone disconnected"); + + let mut rooms: Vec = Vec::new(); + + // remove address + if self.sessions.remove(&msg.id).is_some() { + // remove session from all rooms + for (name, sessions) in &mut self.rooms { + if sessions.remove(&msg.id) { + rooms.push(name.to_owned()); + } + } + } + // send message to other users + for room in rooms { + self.send_message(&room, "Someone disconnected", 0); + } + } +} + +/// Handler for Message message. +impl Handler for ChatServer { + type Result = (); + + fn handle(&mut self, msg: Message, _: &mut Context) { + self.send_message(&msg.room, msg.msg.as_str(), msg.id); + } +} + +/// Handler for `ListRooms` message. +impl Handler for ChatServer { + type Result = MessageResult; + + fn handle(&mut self, _: ListRooms, _: &mut Context) -> Self::Result { + let mut rooms = Vec::new(); + + for key in self.rooms.keys() { + rooms.push(key.to_owned()) + } + + MessageResult(rooms) + } +} + +/// Join room, send disconnect message to old room +/// send join message to new room +impl Handler for ChatServer { + type Result = (); + + fn handle(&mut self, msg: Join, _: &mut Context) { + let Join { id, name } = msg; + let mut rooms = Vec::new(); + + // remove session from all rooms + for (n, sessions) in &mut self.rooms { + if sessions.remove(&id) { + rooms.push(n.to_owned()); + } + } + // send message to other users + for room in rooms { + self.send_message(&room, "Someone disconnected", 0); + } + + if self.rooms.get_mut(&name).is_none() { + self.rooms.insert(name.clone(), HashSet::new()); + } + self.send_message(&name, "Someone connected", id); + self.rooms.get_mut(&name).unwrap().insert(id); + } +} diff --git a/websocket-tcp-chat/src/session.rs b/websocket-tcp-chat/src/session.rs new file mode 100644 index 00000000..d53ea2a3 --- /dev/null +++ b/websocket-tcp-chat/src/session.rs @@ -0,0 +1,225 @@ +//! `ClientSession` is an actor, it manages peer tcp connection and +//! proxies commands from peer to `ChatServer`. +use futures::Stream; +use std::str::FromStr; +use std::time::{Duration, Instant}; +use std::{io, net}; +use tokio_core::net::{TcpListener, TcpStream}; +use tokio_io::codec::FramedRead; +use tokio_io::io::WriteHalf; +use tokio_io::AsyncRead; + +use actix::prelude::*; + +use codec::{ChatCodec, ChatRequest, ChatResponse}; +use server::{self, ChatServer}; + +/// Chat server sends this messages to session +#[derive(Message)] +pub struct Message(pub String); + +/// `ChatSession` actor is responsible for tcp peer communications. +pub struct ChatSession { + /// unique session id + id: usize, + /// this is address of chat server + addr: Addr, + /// Client must send ping at least once per 10 seconds, otherwise we drop + /// connection. + hb: Instant, + /// joined room + room: String, + /// Framed wrapper + framed: actix::io::FramedWrite, ChatCodec>, +} + +impl Actor for ChatSession { + /// For tcp communication we are going to use `FramedContext`. + /// It is convenient wrapper around `Framed` object from `tokio_io` + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + // we'll start heartbeat process on session start. + self.hb(ctx); + + // register self in chat server. `AsyncContext::wait` register + // future within context, but context waits until this future resolves + // before processing any other events. + let addr: Addr = ctx.address(); + self.addr + .send(server::Connect { + addr: addr.recipient(), + }) + .into_actor(self) + .then(|res, act, ctx| { + match res { + Ok(res) => act.id = res, + // something is wrong with chat server + _ => ctx.stop(), + } + actix::fut::ok(()) + }) + .wait(ctx); + } + + fn stopping(&mut self, ctx: &mut Self::Context) -> Running { + // notify chat server + self.addr.do_send(server::Disconnect { id: self.id }); + Running::Stop + } +} + +impl actix::io::WriteHandler for ChatSession {} + +/// To use `Framed` we have to define Io type and Codec +impl StreamHandler for ChatSession { + /// This is main event loop for client requests + fn handle(&mut self, msg: ChatRequest, ctx: &mut Context) { + match msg { + ChatRequest::List => { + // Send ListRooms message to chat server and wait for response + println!("List rooms"); + self.addr + .send(server::ListRooms) + .into_actor(self) + .then(|res, act, ctx| { + match res { + Ok(rooms) => { + act.framed.write(ChatResponse::Rooms(rooms)); + } + _ => println!("Something is wrong"), + } + actix::fut::ok(()) + }) + .wait(ctx) + // .wait(ctx) pauses all events in context, + // so actor wont receive any new messages until it get list of rooms back + } + ChatRequest::Join(name) => { + println!("Join to room: {}", name); + self.room = name.clone(); + self.addr.do_send(server::Join { + id: self.id, + name: name.clone(), + }); + self.framed.write(ChatResponse::Joined(name)); + } + ChatRequest::Message(message) => { + // send message to chat server + println!("Peer message: {}", message); + self.addr.do_send(server::Message { + id: self.id, + msg: message, + room: self.room.clone(), + }) + } + // we update heartbeat time on ping from peer + ChatRequest::Ping => self.hb = Instant::now(), + } + } +} + +/// Handler for Message, chat server sends this message, we just send string to +/// peer +impl Handler for ChatSession { + type Result = (); + + fn handle(&mut self, msg: Message, ctx: &mut Context) { + // send message to peer + self.framed.write(ChatResponse::Message(msg.0)); + } +} + +/// Helper methods +impl ChatSession { + pub fn new( + addr: Addr, + framed: actix::io::FramedWrite, ChatCodec>, + ) -> ChatSession { + ChatSession { + id: 0, + addr: addr, + hb: Instant::now(), + room: "Main".to_owned(), + framed: framed, + } + } + + /// helper method that sends ping to client every second. + /// + /// also this method check heartbeats from client + fn hb(&self, ctx: &mut Context) { + ctx.run_later(Duration::new(1, 0), |act, ctx| { + // check client heartbeats + if Instant::now().duration_since(act.hb) > Duration::new(10, 0) { + // heartbeat timed out + println!("Client heartbeat failed, disconnecting!"); + + // notify chat server + act.addr.do_send(server::Disconnect { id: act.id }); + + // stop actor + ctx.stop(); + } + + act.framed.write(ChatResponse::Ping); + // if we can not send message to sink, sink is closed (disconnected) + act.hb(ctx); + }); + } +} + +/// Define tcp server that will accept incoming tcp connection and create +/// chat actors. +pub struct TcpServer { + chat: Addr, +} + +impl TcpServer { + pub fn new(s: &str, chat: Addr) { + // Create server listener + let addr = net::SocketAddr::from_str("127.0.0.1:12345").unwrap(); + let listener = TcpListener::bind(&addr, Arbiter::handle()).unwrap(); + + // Our chat server `Server` is an actor, first we need to start it + // and then add stream on incoming tcp connections to it. + // TcpListener::incoming() returns stream of the (TcpStream, net::SocketAddr) + // items So to be able to handle this events `Server` actor has to + // implement stream handler `StreamHandler<(TcpStream, + // net::SocketAddr), io::Error>` + let _: () = TcpServer::create(|ctx| { + ctx.add_message_stream( + listener + .incoming() + .map_err(|_| ()) + .map(|(t, a)| TcpConnect(t, a)), + ); + TcpServer { chat: chat } + }); + } +} + +/// Make actor from `Server` +impl Actor for TcpServer { + /// Every actor has to provide execution `Context` in which it can run. + type Context = Context; +} + +#[derive(Message)] +struct TcpConnect(TcpStream, net::SocketAddr); + +/// Handle stream of TcpStream's +impl Handler for TcpServer { + type Result = (); + + fn handle(&mut self, msg: TcpConnect, _: &mut Context) { + // For each incoming connection we create `ChatSession` actor + // with out chat server address. + let server = self.chat.clone(); + let _: () = ChatSession::create(|ctx| { + let (r, w) = msg.0.split(); + ChatSession::add_stream(FramedRead::new(r, ChatCodec), ctx); + ChatSession::new(server, actix::io::FramedWrite::new(w, ChatCodec, ctx)) + }); + } +} diff --git a/websocket-tcp-chat/static/websocket.html b/websocket-tcp-chat/static/websocket.html new file mode 100644 index 00000000..e59e13f1 --- /dev/null +++ b/websocket-tcp-chat/static/websocket.html @@ -0,0 +1,90 @@ + + + + + + + + +

Chat!

+
+  | Status: + disconnected +
+
+
+
+ + +
+ +