├── .gitignore ├── signalling-server ├── .gitignore ├── Makefile.toml ├── Cargo.toml ├── src │ └── signalling-server.rs └── Cargo.lock ├── wasm_client ├── .gitignore ├── src │ ├── utils.rs │ ├── lib.rs │ ├── sdp.rs │ ├── ice.rs │ ├── websockets.rs │ └── common.rs ├── Makefile.toml ├── Cargo.toml └── index.html ├── Crustacean_over_ip.png ├── Crustacean_over_ip_smol.png ├── Cargo.toml ├── shared-protocol ├── Cargo.toml └── src │ └── lib.rs ├── turn-server ├── Cargo.toml └── src │ └── main.rs ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | 3 | /target 4 | /wasm_client/pkg 5 | -------------------------------------------------------------------------------- /signalling-server/.gitignore: -------------------------------------------------------------------------------- 1 | target/* 2 | signalling_server_prototype.log 3 | -------------------------------------------------------------------------------- /wasm_client/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | bin/ 5 | pkg/ 6 | .travis.yml 7 | 8 | 9 | -------------------------------------------------------------------------------- /Crustacean_over_ip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Charles-Schleich/WebRTC-in-Rust/HEAD/Crustacean_over_ip.png -------------------------------------------------------------------------------- /Crustacean_over_ip_smol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Charles-Schleich/WebRTC-in-Rust/HEAD/Crustacean_over_ip_smol.png -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | # Potential Workspace IDEAs 2 | [workspace] 3 | members = [ 4 | "wasm_client", 5 | "signalling-server", 6 | "shared-protocol", 7 | "turn-server" 8 | ] -------------------------------------------------------------------------------- /shared-protocol/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shared-protocol" 3 | version = "0.1.0" 4 | authors = ["CSchleich "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | serde = { version = "1.0", features = ["derive"] } 11 | -------------------------------------------------------------------------------- /wasm_client/src/utils.rs: -------------------------------------------------------------------------------- 1 | pub fn set_panic_hook() { 2 | // When the `console_error_panic_hook` feature is enabled, we can call the 3 | // `set_panic_hook` function at least once during initialization, and then 4 | // we will get better error messages if our code ever panics. 5 | // 6 | // For more details see 7 | // https://github.com/rustwasm/console_error_panic_hook#readme 8 | #[cfg(feature = "console_error_panic_hook")] 9 | console_error_panic_hook::set_once(); 10 | } 11 | -------------------------------------------------------------------------------- /signalling-server/Makefile.toml: -------------------------------------------------------------------------------- 1 | [env] 2 | PORT = "9000" 3 | 4 | [config] 5 | skip_core_tasks = true 6 | 7 | [tasks.servesignal] 8 | description = "Start Singalling server" 9 | command = "cargo" 10 | args = ["run"] 11 | 12 | 13 | # ---- BUILD ---- 14 | 15 | [tasks.build] 16 | description = "Build Signalling Server" 17 | command = "cargo" 18 | args = ["build"] 19 | 20 | [tasks.build_release] 21 | description = "Build Signalling Server Release !" 22 | command = "cargo" 23 | args = ["build", "--release"] 24 | 25 | -------------------------------------------------------------------------------- /signalling-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "signalling-server" 3 | version = "0.1.0" 4 | authors = ["CSchleich "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [[bin]] 10 | name="signalling-server" 11 | path="./src/signalling-server.rs" 12 | 13 | 14 | [dependencies] 15 | async-tungstenite = "0.12.0" 16 | serde = { version = "1.0.117", features = ["derive"] } 17 | serde_json = "1.0.62" 18 | simplelog = "0.8.0" 19 | log = "0.4.8" 20 | futures="0.3.12" 21 | async-std="1.9.0" 22 | rand="0.8.3" 23 | 24 | 25 | # From Workspace 26 | shared-protocol = {path = "../shared-protocol"} 27 | -------------------------------------------------------------------------------- /turn-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "turn-server" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | stun = "0.4.2" 10 | tokio = { version = "1.15.0", features = ["full"] } 11 | async-trait = "0.1.52" 12 | log = "0.4.14" 13 | base64 = "0.13.0" 14 | rand = "0.8.4" 15 | ring = "0.16.20" 16 | md-5 = "0.10.0" 17 | thiserror = "1.0.30" 18 | turn = "0.5.4" 19 | # turn = {path ="../../turn"} 20 | 21 | # webrtc-util = "0.5.3" 22 | util = { package = "webrtc-util", version = "0.5.3", default-features = false, features = ["conn", "vnet"] } 23 | env_logger = "0.9.0" 24 | 25 | 26 | [dev-dependencies] 27 | tokio-test = "0.4.2" 28 | env_logger = "0.9.0" 29 | chrono = "0.4.19" 30 | hex = "0.4.3" 31 | criterion = "0.3.5" 32 | -------------------------------------------------------------------------------- /wasm_client/Makefile.toml: -------------------------------------------------------------------------------- 1 | [env] 2 | PORT = "9000" 3 | 4 | [config] 5 | skip_core_tasks = true 6 | 7 | # ---- SERVE ---- 8 | 9 | [tasks.serve] 10 | description = "Start Application Server (to host Web Page)" 11 | install_crate = { crate_name = "microserver", binary = "microserver", test_arg = "-h" } 12 | command = "microserver" 13 | args = ["--port", "${PORT}"] 14 | 15 | 16 | # ---- BUILD ---- 17 | 18 | [tasks.watch] 19 | description = "Watch files and recompile the project on change" 20 | run_task = [ 21 | { name = "build" }, 22 | ] 23 | watch = { ignore_pattern="pkg/*", watch = ["."] } 24 | 25 | [tasks.build] 26 | description = "Build with wasm-pack" 27 | install_crate = { crate_name = "wasm-pack", binary = "wasm-pack", test_arg = "-V" } 28 | command = "wasm-pack" 29 | args = ["build", "--target", "web", "--out-name", "wasm_client", "--dev"] 30 | 31 | [tasks.build_release] 32 | description = "Build with wasm-pack in release mode" 33 | install_crate = { crate_name = "wasm-pack", binary = "wasm-pack", test_arg = "-V" } 34 | command = "wasm-pack" 35 | args = ["build", "--target", "web", "--out-name", "wasm_client"] 36 | 37 | [tasks.servesignal] 38 | # Empty Task to bypass for wasm_client 39 | -------------------------------------------------------------------------------- /shared-protocol/src/lib.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | pub const SERVER_PORT: &str = "9000"; 4 | 5 | // The reason im wrapping the IDs in SessionID and UserID is so that rust can type check for us that we arent accidentally using the wrong ID type in the wrong place. 6 | 7 | #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] 8 | pub struct SessionID(String); 9 | 10 | impl SessionID { 11 | pub fn new(inner: String) -> Self { 12 | SessionID(inner) 13 | } 14 | pub fn inner(self) -> String { 15 | self.0 16 | } 17 | } 18 | 19 | impl From<&str> for SessionID { 20 | fn from(session_id: &str) -> Self { 21 | SessionID(session_id.to_string()) 22 | } 23 | } 24 | 25 | #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] 26 | pub struct UserID(String); 27 | 28 | impl UserID { 29 | pub fn new(inner: String) -> Self { 30 | UserID(inner) 31 | } 32 | pub fn inner(self) -> String { 33 | self.0 34 | } 35 | } 36 | 37 | #[derive(Debug, Serialize, Deserialize)] 38 | pub enum SignalEnum { 39 | // Return called by the server as soon as the user connects 40 | NewUser(UserID), 41 | 42 | // To manage a live session between two users 43 | SessionNew, 44 | SessionReady(SessionID), 45 | SessionJoin(SessionID), 46 | SessionJoinSuccess(SessionID), 47 | SessionJoinError(SessionID), 48 | 49 | // When Connecting to a Session 50 | VideoOffer(String, SessionID), 51 | VideoAnswer(String, SessionID), 52 | IceCandidate(String, SessionID), 53 | ICEError(String, SessionID), 54 | 55 | // 56 | Debug, 57 | } 58 | -------------------------------------------------------------------------------- /wasm_client/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | mod ice; 3 | mod sdp; 4 | mod utils; 5 | mod websockets; 6 | 7 | use std::cell::RefCell; 8 | use std::rc::Rc; 9 | 10 | use log::info; 11 | use wasm_bindgen::prelude::wasm_bindgen; 12 | use wasm_bindgen::UnwrapThrowExt; 13 | 14 | use common::{ 15 | create_stun_peer_connection, create_turn_peer_connection, create_plain_peer_connection, setup_initiator, setup_listener, 16 | setup_show_signalling_server_state, setup_show_state, AppState, 17 | }; 18 | use ice::{received_new_ice_candidate, setup_rtc_peer_connection_ice_callbacks}; 19 | use sdp::{create_sdp_offer, receive_sdp_answer, receive_sdp_offer_send_answer}; 20 | use utils::set_panic_hook; 21 | use websockets::open_web_socket; 22 | 23 | #[wasm_bindgen(start)] 24 | pub async fn start() { 25 | set_panic_hook(); 26 | 27 | wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); 28 | 29 | let state: Rc> = Rc::new(RefCell::new(AppState::new())); 30 | 31 | let rtc_connection = create_plain_peer_connection().unwrap_throw(); 32 | 33 | // To run the TURN client you need to be running a turn server as well. 34 | // let rtc_connection = create_turn_peer_connection().unwrap_throw(); 35 | 36 | let websocket = open_web_socket(rtc_connection.clone(), state.clone()) 37 | .await 38 | .unwrap_throw(); 39 | 40 | setup_show_state(rtc_connection.clone(), state.clone()); 41 | setup_show_signalling_server_state(websocket.clone()); 42 | 43 | setup_initiator(rtc_connection.clone(), websocket.clone(), state.clone()) 44 | .await 45 | .unwrap_throw(); 46 | info!("Setup Initiator"); 47 | 48 | setup_listener(rtc_connection.clone(), websocket.clone(), state.clone()) 49 | .await 50 | .unwrap_throw(); 51 | info!("Setup Listener"); 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebRTC Tutorial in Rust+WASM ! 2 | 3 | 4 |

5 | WebRTC in Rust 6 |

7 | 8 | 9 | 10 | 11 | #### Quick prerequisites 12 | You will need to install `cargo-make` and `microserver` 13 | `cargo install --force cargo-make` 14 | `cargo install microserver` 15 | 16 | ## Start Right away 17 | You need two terminals opened in the root directory of the project. 18 | 19 | From Terminal 1 20 | Terminal 1 🛠 : `cd ./wasm_client` 21 | Terminal 1 🛠 : `cargo make build` or `cargo make watch` (if you plan on tinkering) 22 | Terminal 1 🚀 : `cargo make serve` 23 | 24 | From Terminal 2: 25 | Terminal 2 🔌 : `cd ./signalling-server` 26 | Terminal 2 🔌 : `cargo make servesignal` 27 | 28 | ⚠️ Don't forget to set your own ip address for your web-socket's signalling server inside `/wasm_client/src/websockets.rs` 29 | 30 | This is to be read with the following [Medium Article](https://charles-schleich.medium.com/webrtc-video-chat-tutorial-using-rust-wasm-fa340f7aeef9). 31 | 32 | 33 | ## Useful Terminology 34 | - ICE : Interactive Connectivity Establishment 35 | - SCTP : Stream Control Transmission Protocol (SCTP) 36 | - SDP : Session Description Protocol 37 | - STUN : Session Traversal Utilities for NAT 38 | - NAT : Network Address Translation 39 | - TURN : Traversal Using Relays around NAT 40 | 41 | - Signaling: Signaling is the process of sending control information between two devices to determine the communication protocols, channels, media codecs and formats, and method of data transfer, as well as any required routing information. The most important thing to know about the signaling process for WebRTC: it is not defined in the specification. 42 | This is something that be implemented by the programmer, this project makes use of websockets to achieve this. 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /wasm_client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm_client" 3 | version = "0.1.0" 4 | authors = ["charles"] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "rlib"] 9 | 10 | [features] 11 | default = ["console_error_panic_hook"] 12 | 13 | [dependencies] 14 | arc-swap = "1.2.0" 15 | async-std = "1.9.0" 16 | log = "0.4.11" 17 | js-sys = "0.3" 18 | serde = { version = "1.0", features = ["derive"] } 19 | serde-json-wasm = "0.3.1" 20 | wasm-bindgen = { version = "0.2.63", features = ["serde-serialize"] } 21 | wasm-logger = "0.2.0" 22 | wasm-bindgen-futures = "0.4.20" 23 | 24 | # The `console_error_panic_hook` crate provides better debugging of panics by 25 | # logging them with `console.error`. This is great for development, but requires 26 | # all the `std::fmt` and `std::panicking` infrastructure, so isn't great for 27 | # code size when deploying. 28 | console_error_panic_hook = { version = "0.1.6", optional = true } 29 | 30 | 31 | # From Workspace 32 | shared-protocol = {path = "../shared-protocol"} 33 | 34 | 35 | [dependencies.web-sys] 36 | version = "0.3.47" 37 | features = [ 38 | "MessageEvent", 39 | "RtcPeerConnection", 40 | "RtcSignalingState", 41 | "RtcSdpType", 42 | "RtcSessionDescriptionInit", 43 | "RtcPeerConnectionIceEvent", 44 | "RtcIceCandidate", 45 | "RtcIceCandidateInit", 46 | "RtcIceConnectionState", 47 | "RtcDataChannel", 48 | "RtcDataChannelEvent", 49 | "RtcSessionDescription", 50 | "RtcIceGatheringState", 51 | "RtcIceCredentialType", 52 | "RtcIceTransportPolicy", 53 | "RtcConfiguration", 54 | "Navigator", 55 | "RtcIceServer", 56 | "MediaDevices", 57 | "Window", 58 | "Document", 59 | "MediaStream", 60 | "Element", 61 | "MediaStreamConstraints", 62 | "HtmlVideoElement", 63 | "HtmlMediaElement", 64 | "WebSocket", 65 | "HtmlButtonElement", 66 | "HtmlParagraphElement", 67 | "HtmlLabelElement", 68 | "EventListener", 69 | "MouseEvent", 70 | "BinaryType", 71 | "Blob", 72 | "ErrorEvent", 73 | "FileReader", 74 | "ProgressEvent", 75 | "HtmlButtonElement", 76 | "HtmlInputElement", 77 | ] 78 | 79 | [dev-dependencies] 80 | wasm-bindgen-test = "0.3.13" 81 | 82 | [profile.release] 83 | # Tell `rustc` to optimize for small code size. 84 | opt-level = "s" 85 | -------------------------------------------------------------------------------- /wasm_client/src/sdp.rs: -------------------------------------------------------------------------------- 1 | use js_sys::Reflect; 2 | use log::{info, warn}; 3 | use wasm_bindgen::JsValue; 4 | use wasm_bindgen_futures::JsFuture; 5 | use web_sys::{RtcPeerConnection, RtcSdpType, RtcSessionDescriptionInit}; 6 | 7 | pub async fn receive_sdp_answer( 8 | peer_a: RtcPeerConnection, 9 | answer_sdp: String, 10 | ) -> Result<(), JsValue> { 11 | warn!("SDP: Receive Answer {:?}", answer_sdp); 12 | 13 | // Setting Remote Description 14 | let mut answer_obj = RtcSessionDescriptionInit::new(RtcSdpType::Answer); 15 | answer_obj.sdp(&answer_sdp); 16 | let srd_promise = peer_a.set_remote_description(&answer_obj); 17 | JsFuture::from(srd_promise).await?; 18 | Ok(()) 19 | } 20 | 21 | pub async fn receive_sdp_offer_send_answer( 22 | peer_b: RtcPeerConnection, 23 | offer_sdp: String, 24 | ) -> Result { 25 | warn!("SDP: Video Offer Receive! {}", offer_sdp); 26 | 27 | // Set Remote Description 28 | let mut offer_obj = RtcSessionDescriptionInit::new(RtcSdpType::Offer); 29 | offer_obj.sdp(&offer_sdp); 30 | let srd_promise = peer_b.set_remote_description(&offer_obj); 31 | JsFuture::from(srd_promise).await?; 32 | 33 | // Create SDP Answer 34 | let answer = JsFuture::from(peer_b.create_answer()).await?; 35 | let answer_sdp = Reflect::get(&answer, &JsValue::from_str("sdp"))? 36 | .as_string() 37 | .unwrap(); 38 | 39 | let mut answer_obj = RtcSessionDescriptionInit::new(RtcSdpType::Answer); 40 | answer_obj.sdp(&answer_sdp); 41 | 42 | let sld_promise = peer_b.set_local_description(&answer_obj); 43 | JsFuture::from(sld_promise).await?; 44 | 45 | info!("SDP: Sending Video Answer {:?}", answer_sdp); 46 | Ok(answer_sdp) 47 | } 48 | 49 | pub async fn create_sdp_offer(peer_a: RtcPeerConnection) -> Result { 50 | // Create SDP Offer 51 | let offer = JsFuture::from(peer_a.create_offer()).await?; 52 | let offer_sdp = Reflect::get(&offer, &JsValue::from_str("sdp"))? 53 | .as_string() 54 | .unwrap(); 55 | 56 | // Set SDP Type -> Offer 57 | let mut offer_obj = RtcSessionDescriptionInit::new(RtcSdpType::Offer); 58 | offer_obj.sdp(&offer_sdp); 59 | 60 | // Set SDP Type -> Offer 61 | let sld_promise = peer_a.set_local_description(&offer_obj); 62 | JsFuture::from(sld_promise).await?; 63 | 64 | // Send Offer from Peer A -> Peer B Via WebSocket 65 | info!("SDP: Sending Offer {:?}", offer_sdp); 66 | 67 | Ok(offer_sdp) 68 | } 69 | -------------------------------------------------------------------------------- /wasm_client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | WebRTC-in-Rust 8 | 24 | 25 | 26 | 27 |
28 |
29 |

WebRTC in Rust

30 | 31 | 32 | 33 | 34 |
35 | 36 | 37 | 38 | 39 |

Peer A Video

40 | 41 |
42 | 43 | 44 |

45 | 46 |
47 | 48 | 49 |
50 | 51 | 52 |
53 | 54 | 55 |
56 |

Peer B Video

57 | 58 |
59 | 60 | 61 |
62 | 63 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /turn-server/src/main.rs: -------------------------------------------------------------------------------- 1 | use turn::auth::*; 2 | use turn::relay::relay_range::RelayAddressGeneratorRanges; 3 | use turn::relay::relay_static::RelayAddressGeneratorStatic; 4 | use turn::server::{config::*, *}; 5 | use turn::Error; 6 | 7 | use std::collections::HashMap; 8 | use std::net::{IpAddr, SocketAddr}; 9 | use std::str::FromStr; 10 | use std::sync::Arc; 11 | use tokio::net::UdpSocket; 12 | use tokio::signal; 13 | use tokio::time::Duration; 14 | use util::vnet::net::*; 15 | 16 | struct MyAuthHandler { 17 | cred_map: HashMap>, 18 | } 19 | 20 | impl MyAuthHandler { 21 | fn new(cred_map: HashMap>) -> Self { 22 | MyAuthHandler { cred_map } 23 | } 24 | } 25 | 26 | impl AuthHandler for MyAuthHandler { 27 | fn auth_handle( 28 | &self, 29 | username: &str, 30 | _realm: &str, 31 | src_addr: SocketAddr, 32 | ) -> Result, Error> { 33 | // println!("Attempt: username={}", username); 34 | println!("src_addr={}", src_addr); 35 | println!("username={}", username); 36 | if let Some(pw) = self.cred_map.get(username) { 37 | println!(" password={:?}", pw); 38 | Ok(pw.to_vec()) 39 | } else { 40 | Err(Error::ErrFakeErr) 41 | } 42 | } 43 | } 44 | 45 | // RUST_LOG=trace cargo run --color=always 46 | 47 | #[tokio::main] 48 | async fn main() -> Result<(), Error> { 49 | env_logger::init(); 50 | 51 | // const SHARED_SECRET: &str = "HELLO_WORLD"; 52 | // let long_term_auth_handler= LongTermAuthHandler::new(SHARED_SECRET.to_string()); 53 | // let (user, pass) = generate_long_term_credentials(SHARED_SECRET, Duration::from_secs(600000))?; 54 | 55 | let public_ip = "192.168.178.60"; 56 | let port = "3478"; 57 | let realm = "realm"; 58 | 59 | let mut cred_map: HashMap> = HashMap::new(); 60 | for user_id in 0..11 { 61 | let user = format!("user{}",user_id); 62 | let pass = format!("pass{}",user_id); 63 | println!("{} : {}",user,pass); 64 | let key = generate_auth_key(&user, realm, &pass); 65 | cred_map.insert(user.to_owned(), key); 66 | } 67 | 68 | // let conn = Arc::new(UdpSocket::bind(format!("192.168.178.60:{}", port)).await?); 69 | let conn = Arc::new(UdpSocket::bind(format!("0.0.0.0:{}", port)).await?); 70 | println!("listening {}...", conn.local_addr()?); 71 | 72 | let box_relay_adress_genenrator_range = Box::new(RelayAddressGeneratorRanges{ 73 | relay_address: IpAddr::from_str(public_ip)?, 74 | min_port: 3000, 75 | max_port: 60000, 76 | max_retries: 10, 77 | address: "192.168.178.60".to_owned(), 78 | net: Arc::new(Net::new(None)), 79 | }); 80 | 81 | let box_relay_adress_gen_static = Box::new(RelayAddressGeneratorStatic{ 82 | relay_address: IpAddr::from_str(public_ip)?, 83 | address: "0.0.0.0".to_owned(), 84 | net: Arc::new(Net::new(None)), 85 | }); 86 | 87 | let server = Server::new(ServerConfig { 88 | conn_configs: vec![ConnConfig { 89 | conn, 90 | relay_addr_generator: box_relay_adress_genenrator_range 91 | }], 92 | realm: realm.to_owned(), 93 | 94 | // auth_handler: Arc::new(long_term_auth_handler), 95 | auth_handler: Arc::new(MyAuthHandler::new(cred_map)), 96 | channel_bind_timeout: Duration::from_secs(600), 97 | }) 98 | .await?; 99 | 100 | println!("Waiting for Ctrl-C..."); 101 | signal::ctrl_c().await.expect("failed to listen for event"); 102 | println!("\nClosing connection now..."); 103 | server.close().await?; 104 | 105 | Ok(()) 106 | } -------------------------------------------------------------------------------- /wasm_client/src/ice.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::rc::Rc; 3 | 4 | use js_sys::JSON; 5 | use log::{error, info, warn}; 6 | use serde::{Deserialize, Serialize}; 7 | use wasm_bindgen::closure::Closure; 8 | use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; 9 | use wasm_bindgen_futures::JsFuture; 10 | use web_sys::{ 11 | RtcIceCandidate, RtcIceCandidateInit, RtcPeerConnection, RtcPeerConnectionIceEvent, WebSocket, 12 | }; 13 | 14 | use shared_protocol::SignalEnum; 15 | 16 | use crate::common::AppState; 17 | 18 | #[derive(Debug, Serialize, Deserialize)] 19 | #[allow(non_snake_case)] 20 | pub struct IceCandidate { 21 | pub candidate: String, 22 | pub sdpMid: String, // must be non-snake case as this is the key in the parsed JSON 23 | pub sdpMLineIndex: u16, // must be non-snake case as this is the key in the parsed JSON 24 | } 25 | 26 | pub async fn setup_rtc_peer_connection_ice_callbacks( 27 | rtc_conn: RtcPeerConnection, 28 | ws: WebSocket, 29 | rc_state: Rc>, 30 | ) -> Result { 31 | let onicecandidate_callback = 32 | Closure::wrap( 33 | Box::new(move |ev: RtcPeerConnectionIceEvent| 34 | { 35 | let ws = ws.clone(); 36 | let rc_state = rc_state.clone(); 37 | send_ice_candidate(ws,rc_state,ev); 38 | } 39 | ) as Box, 40 | ); 41 | rtc_conn.set_onicecandidate(Some(onicecandidate_callback.as_ref().unchecked_ref())); 42 | onicecandidate_callback.forget(); 43 | Ok(rtc_conn) 44 | } 45 | 46 | 47 | pub fn sleep(ms: i32) -> js_sys::Promise { 48 | js_sys::Promise::new(&mut |resolve, _| { 49 | web_sys::window() 50 | .unwrap() 51 | .set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, ms) 52 | .unwrap(); 53 | }) 54 | } 55 | 56 | pub fn send_ice_candidate( 57 | ws: WebSocket, 58 | rc_state: Rc>, 59 | ev: RtcPeerConnectionIceEvent 60 | ) { 61 | match ev.candidate() { 62 | Some(candidate) => { 63 | let json_obj_candidate = candidate.to_json(); 64 | let res = JSON::stringify(&json_obj_candidate).unwrap_throw(); 65 | 66 | let js_ob = String::from(res.clone()); 67 | 68 | let ws= ws.clone(); 69 | let rc_state = rc_state.clone(); 70 | 71 | let state = rc_state.borrow(); 72 | let opt_session_id = state.get_session_id_ref().clone(); 73 | drop(state); 74 | let session_id = match opt_session_id { 75 | Some(sid) => sid, 76 | None => { 77 | error!("No Session ID has been set yet"); 78 | let sleep_promise= sleep(3000); 79 | wasm_bindgen_futures::spawn_local(async move { 80 | let _ = wasm_bindgen_futures::JsFuture::from(sleep_promise).await; 81 | send_ice_candidate(ws,rc_state,ev); 82 | error!("Session ID set now ???? "); 83 | }); 84 | return; 85 | } 86 | }; 87 | let signal = SignalEnum::IceCandidate(js_ob, session_id); 88 | let ice_candidate: String = serde_json_wasm::to_string(&signal).unwrap(); 89 | info!("Sending IceCandidate to Other peer {:?}", res); 90 | match ws.send_with_str(&ice_candidate) { 91 | Ok(_) => info!("IceCandidate sent {}", ice_candidate), 92 | Err(err) => error!("error sending IceCandidate SignalEnum: {:?}", err), 93 | } 94 | } 95 | None => { 96 | info!("No ICE candidate in RtcPeerConnectionIceEvent"); 97 | } 98 | } 99 | } 100 | 101 | 102 | pub async fn received_new_ice_candidate( 103 | candidate: String, 104 | rtc_conn: RtcPeerConnection, 105 | ) -> Result<(), JsValue> { 106 | warn!("ICECandidate Received! {}", candidate); 107 | 108 | let icecandidate = serde_json_wasm::from_str::(&candidate).map_err(|_| { 109 | let message = format!("Could not deserialize Ice Candidate {} ", candidate); 110 | JsValue::from_str(&message) 111 | })?; 112 | 113 | let mut rtc_ice_init = RtcIceCandidateInit::new(""); 114 | rtc_ice_init.candidate(&icecandidate.candidate); 115 | rtc_ice_init.sdp_m_line_index(Some(icecandidate.sdpMLineIndex)); 116 | rtc_ice_init.sdp_mid(Some(&icecandidate.sdpMid)); 117 | 118 | match RtcIceCandidate::new(&rtc_ice_init) { 119 | Ok(x) => { 120 | let result = 121 | JsFuture::from(rtc_conn.add_ice_candidate_with_opt_rtc_ice_candidate(Some(&x))) 122 | .await?; 123 | info!("Added other peer's Ice Candidate ! {:?}", result); 124 | } 125 | Err(e) => { 126 | info!("Ice Candidate Addition error, {} | {:?}", candidate, e); 127 | return Err(e); 128 | } 129 | }; 130 | Ok(()) 131 | } 132 | -------------------------------------------------------------------------------- /wasm_client/src/websockets.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::rc::Rc; 3 | 4 | use log::{error, info}; 5 | use wasm_bindgen::closure::Closure; 6 | use wasm_bindgen::{JsCast, JsValue}; 7 | use web_sys::{Document, ErrorEvent, HtmlLabelElement, MessageEvent, RtcPeerConnection, WebSocket}; 8 | 9 | use crate::common::{handle_message_reply, AppState}; 10 | 11 | // From Workspace 12 | 13 | // __ __ _ _____ _ _ 14 | // \ \ / / | | / ____| | | | | 15 | // \ \ /\ / / ___ | |__ | (___ ___ ___ | | __ ___ | |_ 16 | // \ \/ \/ / / _ \ | '_ \ \___ \ / _ \ / __| | |/ / / _ \ | __| 17 | // \ /\ / | __/ | |_) | ____) | | (_) | | (__ | < | __/ | |_ 18 | // \/ \/ \___| |_.__/ |_____/ \___/ \___| |_|\_\ \___| \__| 19 | 20 | const WS_IP_PORT: &str = "ws://192.168.178.60:2794"; 21 | 22 | 23 | pub async fn open_web_socket( 24 | rtc_conn: RtcPeerConnection, 25 | rc_state: Rc>, 26 | ) -> Result { 27 | info!("Opening WS Connection"); 28 | 29 | let ws = WebSocket::new(WS_IP_PORT)?; 30 | 31 | ws.set_binary_type(web_sys::BinaryType::Arraybuffer); 32 | let cloned_ws_ext = ws.clone(); 33 | let cloned_state_ext = rc_state; 34 | // ON MESSAGE CALLBACK 35 | let onmessage_callback = Closure::wrap(Box::new(move |ev: MessageEvent| { 36 | if let Ok(array_buffer) = ev.data().dyn_into::() { 37 | info!( 38 | "WS: message event, received arraybuffer: {:?}", 39 | array_buffer 40 | ); 41 | } else if let Ok(blob) = ev.data().dyn_into::() { 42 | info!("WS: message event, received blob: {:?}", blob); 43 | } else if let Ok(txt) = ev.data().dyn_into::() { 44 | info!("WS: message event, received string: {:?}", txt); 45 | let rust_string = String::from(txt); 46 | let rtc_conn_clone = rtc_conn.clone(); 47 | let cloned_ws = cloned_ws_ext.clone(); 48 | let cloned_state = cloned_state_ext.clone(); 49 | wasm_bindgen_futures::spawn_local(async move { 50 | let result = handle_message_reply( 51 | rust_string, 52 | rtc_conn_clone.clone(), 53 | cloned_ws.clone(), 54 | cloned_state, 55 | ) 56 | .await; 57 | match result { 58 | Err(x) => error!("{:?}", x), 59 | _ => { 60 | // debug!("Handle Signalling message done") 61 | } 62 | } 63 | }); 64 | } else { 65 | info!("message event, received Unknown: {:?}", ev.data()); 66 | } 67 | }) as Box); 68 | ws.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref())); 69 | onmessage_callback.forget(); 70 | 71 | let window = web_sys::window().expect("No window Found, We've got bigger problems here"); 72 | let document: Document = window.document().expect("Couldn't Get Document"); 73 | let ws_conn_lbl = "ws_conn_lbl"; 74 | let ws_conn_lbl_err = "ws_conn_lbl_err"; 75 | 76 | // ON ERROR 77 | let document_clone: Document = document.clone(); 78 | let onerror_callback = Closure::wrap(Box::new(move |e: ErrorEvent| { 79 | error!("WS: onerror_callback error event: {:?}", e); 80 | 81 | document_clone 82 | .get_element_by_id(ws_conn_lbl_err) 83 | .unwrap_or_else(|| panic!("Should have {} on the page", ws_conn_lbl_err)) 84 | .dyn_ref::() 85 | .expect("#Button should be a be an `HtmlLabelElement`") 86 | .set_text_content(Some(&format!( 87 | "{} {} ?", 88 | "Could not make Websocket Connection, Is the Signalling Server running on: ", 89 | WS_IP_PORT 90 | ))); 91 | }) as Box); 92 | ws.set_onerror(Some(onerror_callback.as_ref().unchecked_ref())); 93 | onerror_callback.forget(); 94 | 95 | // ON OPEN 96 | let document_clone: Document = document; 97 | let onopen_callback = Closure::wrap(Box::new(move |_| { 98 | document_clone 99 | .get_element_by_id(ws_conn_lbl) 100 | .unwrap_or_else(|| panic!("Should have {} on the page", ws_conn_lbl)) 101 | .dyn_ref::() 102 | .expect("#Button should be a be an `HtmlLabelElement`") 103 | .set_text_content(Some(&"Websocket Connected !".to_string())); 104 | 105 | document_clone 106 | .get_element_by_id(ws_conn_lbl_err) 107 | .unwrap_or_else(|| panic!("Should have {} on the page", ws_conn_lbl_err)) 108 | .dyn_ref::() 109 | .expect("#Button should be a be an `HtmlLabelElement`") 110 | .set_text_content(Some(&"".to_string())); 111 | }) as Box); 112 | ws.set_onopen(Some(onopen_callback.as_ref().unchecked_ref())); 113 | onopen_callback.forget(); 114 | 115 | // input 116 | Ok(ws) 117 | } 118 | -------------------------------------------------------------------------------- /signalling-server/src/signalling-server.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::{ 3 | collections::HashMap, 4 | io::Error as IoError, 5 | net::SocketAddr, 6 | sync::{Arc, Mutex}, 7 | }; 8 | 9 | use async_std::net::{TcpListener, TcpStream}; 10 | use async_std::task; 11 | use async_tungstenite::tungstenite::protocol::Message; 12 | use futures::{ 13 | channel::mpsc::{unbounded, UnboundedSender}, 14 | future, pin_mut, StreamExt, TryStreamExt, 15 | }; 16 | use log::{debug, error, info, warn, SetLoggerError}; 17 | use rand::distributions::Alphanumeric; 18 | use rand::{thread_rng, Rng}; 19 | use simplelog::{CombinedLogger, LevelFilter, TermLogger, TerminalMode, WriteLogger}; 20 | 21 | type Tx = UnboundedSender; 22 | type PeerMap = Arc>>; 23 | type UserList = Arc>>; 24 | 25 | type SessionList = Arc>>; 26 | 27 | const LOG_FILE: &str = "signalling_server_prototype.log"; 28 | 29 | #[derive(Debug, Clone)] 30 | struct SessionMembers { 31 | host: UserID, 32 | guest: Option, 33 | } 34 | 35 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 36 | // Setup Logging 37 | fn setup_logging() -> Result<(), SetLoggerError> { 38 | CombinedLogger::init(vec![ 39 | TermLogger::new( 40 | LevelFilter::Debug, 41 | simplelog::Config::default(), 42 | TerminalMode::Mixed, 43 | ), 44 | WriteLogger::new( 45 | LevelFilter::Debug, 46 | simplelog::Config::default(), 47 | File::create(LOG_FILE).unwrap(), 48 | ), 49 | ]) 50 | } 51 | 52 | // Get Server IP 53 | use shared_protocol::{SessionID, SignalEnum, UserID}; 54 | use std::net::UdpSocket; 55 | 56 | pub fn get_local_ip() -> Option { 57 | let socket = match UdpSocket::bind("0.0.0.0:0") { 58 | Ok(s) => s, 59 | Err(_) => return None, 60 | }; 61 | match socket.connect("8.8.8.8:80") { 62 | Ok(()) => (), 63 | Err(_) => return None, 64 | }; 65 | match socket.local_addr() { 66 | Ok(addr) => Some(addr.ip().to_string()), 67 | Err(_) => None, 68 | } 69 | } 70 | 71 | fn generate_id(length: u8) -> String { 72 | let rand_string: String = thread_rng() 73 | .sample_iter(&Alphanumeric) 74 | .take(length as usize) 75 | .map(char::from) 76 | .collect(); 77 | println!("{}", rand_string); 78 | rand_string 79 | } 80 | 81 | type PeerID = UserID; 82 | 83 | #[derive(Debug, Clone)] 84 | enum Destination { 85 | SourcePeer, 86 | OtherPeer(PeerID), 87 | } 88 | 89 | // _ _ _ _ __ __ 90 | // | | | | | | | | | \/ | 91 | // | |__| | __ _ _ __ __| | | | ___ | \ / | ___ ___ ___ __ _ __ _ ___ 92 | // | __ | / _` | | '_ \ / _` | | | / _ \ | |\/| | / _ \ / __| / __| / _` | / _` | / _ \ 93 | // | | | | | (_| | | | | | | (_| | | | | __/ | | | | | __/ \__ \ \__ \ | (_| | | (_| | | __/ 94 | // |_| |_| \__,_| |_| |_| \__,_| |_| \___| |_| |_| \___| |___/ |___/ \__,_| \__, | \___| 95 | // __/ | 96 | // |___/ 97 | 98 | fn handle_message( 99 | peer_map: PeerMap, 100 | user_list: UserList, 101 | session_list: SessionList, 102 | addr: SocketAddr, 103 | user_id: UserID, 104 | message_from_client: String, 105 | ) -> Result<(), String> { 106 | let result: SignalEnum = match serde_json::from_str(&message_from_client) { 107 | Ok(x) => x, 108 | Err(_) => { 109 | println!("Could not deserialize Message {} ", message_from_client); 110 | return Err("Could not deserialize Message".to_string()); 111 | } 112 | }; 113 | warn!("Handle {:?} from {:?} , {:?}", result, addr, user_id); 114 | 115 | // Result and who it needs to go to 116 | // 2 types of messages, either send to origin, or to other peer 117 | let (message_to_client, destination) = match result { 118 | SignalEnum::VideoOffer(offer, session_id) => { 119 | let mut session_list_lock = session_list.lock().unwrap(); 120 | let possible_session = session_list_lock.get_mut(&session_id); 121 | 122 | match possible_session { 123 | None => { 124 | let e_msg = format!( 125 | "VideoOffer Session {} Does NOT Exist, Groot kak", 126 | session_id.inner() 127 | ); 128 | error!("VideoOffer Session Does NOT Exist, Groot kak"); 129 | return Err(e_msg); 130 | } 131 | Some(session_members) => { 132 | let doc_id = session_members.host.clone(); 133 | let sig_msg = SignalEnum::VideoOffer(offer, session_id.clone()); 134 | let message = match serde_json::to_string(&sig_msg) { 135 | Ok(msg) => msg, 136 | Err(e) => { 137 | let e_msg = format!( 138 | "Could not Serialize {:?} as VideoOffer, {:?}", 139 | session_id, e 140 | ); 141 | return Err(e_msg); 142 | } 143 | }; 144 | (message, Destination::OtherPeer(doc_id)) 145 | } 146 | } 147 | } 148 | SignalEnum::VideoAnswer(answer, session_id) => { 149 | let mut session_list_lock = session_list.lock().unwrap(); 150 | let possible_session = session_list_lock.get_mut(&session_id); 151 | 152 | match possible_session { 153 | None => { 154 | let e_msg = format!( 155 | "VideoAnswer Session {} Doesn NOT Exist, Groot kak", 156 | session_id.inner() 157 | ); 158 | error!("VideoAnswer Session Doesn NOT Exist, Groot kak"); 159 | return Err(e_msg); 160 | } 161 | Some(session_members) => { 162 | let opt_guest = session_members.guest.clone(); 163 | let guest = match opt_guest { 164 | Some(guest) => guest, 165 | None => { 166 | let emsg= String::from("IceCandidate Error: No guest in Session, where are you sending Ice Candidates mate? "); 167 | return Err(emsg); 168 | } 169 | }; 170 | let sig_msg = SignalEnum::VideoAnswer(answer, session_id.clone()); 171 | let message = match serde_json::to_string(&sig_msg) { 172 | Ok(msg) => msg, 173 | Err(e) => { 174 | let e_msg = format!( 175 | "Could not Serialize {:?} as VideoAnswer, {:?}", 176 | session_id, e 177 | ); 178 | return Err(e_msg); 179 | } 180 | }; 181 | (message, Destination::OtherPeer(guest)) 182 | } 183 | } 184 | } 185 | SignalEnum::IceCandidate(candidate, session_id) => { 186 | let mut session_list_lock = session_list.lock().unwrap(); 187 | let possible_session = session_list_lock.get_mut(&session_id); 188 | 189 | match possible_session { 190 | None => { 191 | let e_msg = format!( 192 | "IceCandidate Session {} Does NOT Exist, Groot kak", 193 | session_id.inner() 194 | ); 195 | error!("IceCandidate Session Does NOT Exist, Groot kak"); 196 | return Err(e_msg); 197 | } 198 | Some(session_members) => { 199 | let opt_guest = session_members.guest.clone(); 200 | let guest = match opt_guest { 201 | Some(guest) => guest, 202 | None => { 203 | let emsg= String::from("IceCandidate Error: No guest in Session, where are you sending Ice Candidates mate? "); 204 | return Err(emsg); 205 | } 206 | }; 207 | 208 | let host = session_members.host.clone(); 209 | let destination_peer; 210 | if user_id == guest { 211 | destination_peer = host; 212 | } else if user_id == host { 213 | destination_peer = guest; 214 | } else { 215 | let user_list_lock = user_list.lock().unwrap(); 216 | let socket_of_misalligned_user = user_list_lock.get(&user_id); 217 | error!("UserID connection with {} attempted to send ICE peers to session {} when not assigned to the session", user_id.clone().inner(), session_id.clone().inner()); 218 | error!( 219 | "Socket Address of Illegal user {:?}", 220 | socket_of_misalligned_user 221 | ); 222 | error!("Not Forwarding Ice candidate"); 223 | let e_msg = format!("User {:?}, attempted to send Ice Candidate on session {:?}, which User is not a part of", user_id.inner(), session_id.clone()); 224 | return Err(e_msg); 225 | } 226 | 227 | let sig_msg = SignalEnum::IceCandidate(candidate, session_id.clone()); 228 | let message = match serde_json::to_string(&sig_msg) { 229 | Ok(msg) => msg, 230 | Err(e) => { 231 | let e_msg = format!( 232 | "Could not Serialize {:?} as VideoAnswer, {:?}", 233 | session_id.clone(), 234 | e 235 | ); 236 | return Err(e_msg); 237 | } 238 | }; 239 | (message, Destination::OtherPeer(destination_peer)) 240 | } 241 | } 242 | } 243 | SignalEnum::ICEError(_, _) => { 244 | unimplemented!("IceError Handling") 245 | } 246 | SignalEnum::SessionNew => { 247 | let session_id = SessionID::new(generate_id(5)); 248 | let sig_msg = SignalEnum::SessionReady(session_id.clone()); 249 | let message = match serde_json::to_string(&sig_msg) { 250 | Ok(msg) => msg, 251 | Err(e) => { 252 | let e_msg = format!( 253 | "Could not Serialize {:?} as SessionReady, {:?}", 254 | session_id, e 255 | ); 256 | return Err(e_msg); 257 | } 258 | }; 259 | let session = SessionMembers { 260 | host: user_id, 261 | guest: None, 262 | }; 263 | let insert_result = session_list 264 | .lock() 265 | .unwrap() 266 | .insert(session_id.clone(), session.clone()); 267 | if insert_result.is_some() { 268 | warn!("Session_id {:?} Replaced \n old Session value: {:?} \n New Session value: {:?} \n ",session_id,insert_result, session); 269 | } 270 | (message, Destination::SourcePeer) 271 | } 272 | /////////////////////////////////// 273 | SignalEnum::SessionJoin(session_id) => { 274 | debug!("inside Session Join "); 275 | // Either Send back SessionJoinError Or SessionJoinSuccess 276 | let mut session_list_lock = session_list.lock().unwrap(); 277 | let possible_session = session_list_lock.get_mut(&session_id); 278 | 279 | match possible_session { 280 | None => { 281 | debug!("Session Doesn NOT Exist"); 282 | // Session Does not Exists Send back error ! 283 | let sig_msg = SignalEnum::SessionJoinError("Session Does Not Exist".into()); 284 | let message = match serde_json::to_string(&sig_msg) { 285 | Ok(msg) => msg, 286 | Err(e) => { 287 | let e_msg = format!( 288 | "Could not Serialize {:?} as SessionJoinError, {:?}", 289 | session_id, e 290 | ); 291 | return Err(e_msg); 292 | } 293 | }; 294 | (message, Destination::SourcePeer) 295 | } 296 | Some(session_members) => { 297 | debug!("Session Exists ! Begin Signalling Flow ... "); 298 | 299 | // Session Exists Send back ready to start signalling ! 300 | session_members.guest = Some(user_id); 301 | 302 | let sig_msg = SignalEnum::SessionJoinSuccess(session_id.clone()); 303 | let message = match serde_json::to_string(&sig_msg) { 304 | Ok(msg) => msg, 305 | Err(e) => { 306 | let e_msg = format!( 307 | "Could not Serialize {:?} as SessionJoinSuccess, {:?}", 308 | session_id, e 309 | ); 310 | return Err(e_msg); 311 | } 312 | }; 313 | (message, Destination::SourcePeer) 314 | } 315 | } 316 | } 317 | SignalEnum::Debug => { 318 | debug!("====================================="); 319 | debug!("====== Signalling Server State ======"); 320 | debug!(" User List {:?}", user_list); 321 | debug!(" Session List {:?}", session_list); 322 | debug!("===================================="); 323 | return Ok(()); 324 | } 325 | _ => { 326 | error!("Should not recieve state, {:?}", result); 327 | return Err(format!("Should not recieve state, {:?}", result)); 328 | } 329 | }; 330 | 331 | info!( 332 | "Message Handled, Replying to Client {:?} {:?}", 333 | message_to_client, destination 334 | ); 335 | // Sending Message 336 | match destination { 337 | Destination::SourcePeer => { 338 | let peers = peer_map.lock().unwrap(); 339 | let sender = match peers.get(&addr) { 340 | Some(x) => x, 341 | None => { 342 | warn!("Peer was connection dropped from Hashmap, do nothing"); 343 | return Err("Peer was connection dropped from Hashmap, do nothing".into()); 344 | } 345 | }; 346 | 347 | debug!("Sending {} to {}", message_to_client, addr); 348 | let send_res = sender.unbounded_send(Message::Text(message_to_client)); 349 | if send_res.is_err() { 350 | error!("{}", format!("Error Sending {:?}", send_res)) 351 | } 352 | } 353 | Destination::OtherPeer(destination_peer) => { 354 | let user_list_lock = user_list.lock().unwrap(); 355 | let opt_dest_socket = user_list_lock.get(&destination_peer); 356 | 357 | match opt_dest_socket { 358 | None => { 359 | let e_msg = format!("Could not find socket with address {:?}", opt_dest_socket); 360 | error!("{}", e_msg); 361 | return Err(e_msg); 362 | } 363 | Some(socketaddr) => { 364 | let peers = peer_map.lock().unwrap(); 365 | let sender = match peers.get(socketaddr) { 366 | Some(x) => x, 367 | None => { 368 | warn!("Peer was connection dropped from Hashmap, do nothing"); 369 | return Err( 370 | "Peer was connection dropped from Hashmap, do nothing".into() 371 | ); 372 | } 373 | }; 374 | 375 | debug!("Sending {} to {}", message_to_client, addr); 376 | let send_res = sender.unbounded_send(Message::Text(message_to_client)); 377 | if send_res.is_err() { 378 | error!("{}", format!("Error Sending {:?}", send_res)) 379 | } 380 | } 381 | } 382 | } 383 | } 384 | 385 | Ok(()) 386 | } 387 | 388 | fn reply_with_id(tx: UnboundedSender, user_id: UserID) -> Result<(), String> { 389 | let sig_enum = SignalEnum::NewUser(user_id); 390 | 391 | let message = match serde_json::to_string(&sig_enum) { 392 | Ok(x) => x, 393 | Err(_) => { 394 | error!("Could not deserialize Message {:?} ", sig_enum); 395 | return Err("Could not deserialize Message".to_string()); 396 | } 397 | }; 398 | 399 | // Todo better error handling 400 | let res = tx.unbounded_send(Message::Text(message)); 401 | if res.is_err() { 402 | error!("{:?}", res.unwrap_err()); 403 | } else { 404 | info!("{:?}", res); 405 | } 406 | Ok(()) 407 | } 408 | 409 | // _ _ _ _ _____ _ _ 410 | // | | | | | | | | / ____| | | (_) 411 | // | |__| | __ _ _ __ __| | | | ___ | | ___ _ __ _ __ ___ ___ | |_ _ ___ _ __ 412 | // | __ | / _` | | '_ \ / _` | | | / _ \ | | / _ \ | '_ \ | '_ \ / _ \ / __| | __| | | / _ \ | '_ \ 413 | // | | | | | (_| | | | | | | (_| | | | | __/ | |____ | (_) | | | | | | | | | | __/ | (__ | |_ | | | (_) | | | | | 414 | // |_| |_| \__,_| |_| |_| \__,_| |_| \___| \_____| \___/ |_| |_| |_| |_| \___| \___| \__| |_| \___/ |_| |_| 415 | 416 | async fn handle_connection( 417 | peer_map: PeerMap, 418 | user_list: UserList, 419 | session_list: SessionList, 420 | raw_stream: TcpStream, 421 | addr: SocketAddr, 422 | ) { 423 | info!("Incoming TCP connection from: {}", addr); 424 | 425 | let ws_stream = async_tungstenite::accept_async(raw_stream) 426 | .await 427 | .expect("Error during the websocket handshake occurred"); 428 | info!("WebSocket connection established: {}", addr); 429 | 430 | // Insert the write part of this peer to the peer map. 431 | let (tx, rx) = unbounded(); 432 | peer_map.lock().unwrap().insert(addr, tx.clone()); 433 | 434 | // Insert the User_ID to the user_list 435 | let user_id = UserID::new(generate_id(10)); 436 | 437 | { 438 | user_list.lock().unwrap().insert(user_id.clone(), addr); 439 | } 440 | 441 | // Here we reply with WS Connection ID 442 | // TODO better Error handling 443 | reply_with_id(tx, user_id.clone()).unwrap_or_else(|e| { 444 | error!("Failed to reply with id: {}", e); 445 | }); 446 | 447 | // HERE THE FUN BEGINS 448 | let (outgoing, incoming) = ws_stream.split(); 449 | 450 | let broadcast_incoming = incoming 451 | .try_filter(|msg| { 452 | // Broadcasting a Close message from one client 453 | // will close the other clients. 454 | future::ready(!msg.is_close()) 455 | }) 456 | .try_for_each(|msg| { 457 | warn!( 458 | "Received a message from {}: {}", 459 | addr, 460 | msg.to_text().unwrap() 461 | ); 462 | 463 | let message = msg.to_text().unwrap().to_string(); 464 | let result = handle_message( 465 | peer_map.clone(), 466 | user_list.clone(), 467 | session_list.clone(), 468 | addr, 469 | user_id.clone(), 470 | message, 471 | ); 472 | // handle_message(peer_map: PeerMap, user_list:UserList, addr: SocketAddr, message:String) -> Result<(), String>{ 473 | if result.is_err() { 474 | error!("Handle Message Error {:?}", result); 475 | } else { 476 | info!("Handle Message Ok : result {:?}", result); 477 | } 478 | 479 | future::ok(()) 480 | }); 481 | 482 | let receive_from_others = rx.map(Ok).forward(outgoing); 483 | 484 | pin_mut!(broadcast_incoming, receive_from_others); 485 | future::select(broadcast_incoming, receive_from_others).await; 486 | 487 | info!("{} disconnected", &addr); 488 | // Remove from peer map 489 | peer_map.lock().unwrap().remove(&addr); 490 | 491 | // Remove from User_List 492 | user_list.lock().unwrap().remove(&user_id); 493 | 494 | // TODO: Close any sessions associated with the address IF user hosted the session. 495 | let sess_list: Vec = { 496 | session_list 497 | .lock() 498 | .unwrap() 499 | .iter() 500 | .filter_map(|(sid, members)| { 501 | if members.host == user_id { 502 | Some(sid.clone()) 503 | } else { 504 | None 505 | } 506 | }) 507 | .collect() 508 | }; 509 | 510 | for s in sess_list { 511 | session_list.lock().unwrap().remove(&s); 512 | } 513 | } 514 | 515 | async fn run() -> Result<(), IoError> { 516 | let user_list = UserList::new(Mutex::new(HashMap::new())); 517 | let session_list = SessionList::new(Mutex::new(HashMap::new())); 518 | let peer_map = PeerMap::new(Mutex::new(HashMap::new())); 519 | 520 | // Create the event loop and TCP listener we'll accept connections on. 521 | let try_socket = TcpListener::bind("0.0.0.0:2794").await; 522 | 523 | let listener = try_socket.expect("Failed to bind"); 524 | 525 | // Let's spawn the handling of each connection in a separate Async task. 526 | while let Ok((stream, addr)) = listener.accept().await { 527 | task::spawn(handle_connection( 528 | peer_map.clone(), 529 | user_list.clone(), 530 | session_list.clone(), 531 | stream, 532 | addr, 533 | )); 534 | } 535 | Ok(()) 536 | } 537 | 538 | fn main() -> Result<(), IoError> { 539 | match setup_logging() { 540 | Ok(_) => (), 541 | Err(e) => { 542 | println!("Could not start logger,{}\n...exiting", e); 543 | std::process::exit(1); 544 | } 545 | } 546 | 547 | task::block_on(run()) 548 | } 549 | -------------------------------------------------------------------------------- /wasm_client/src/common.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::convert::TryInto; 3 | use std::rc::Rc; 4 | 5 | 6 | use js_sys::{Array, Object, Promise, Reflect}; 7 | use log::{debug, error, info, warn}; 8 | use wasm_bindgen::closure::Closure; 9 | use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; 10 | use web_sys::{ 11 | Document, Element, HtmlButtonElement, HtmlInputElement, HtmlLabelElement, HtmlVideoElement, 12 | MediaStream, MediaStreamConstraints, MessageEvent, RtcConfiguration, RtcDataChannel, 13 | RtcDataChannelEvent, RtcIceConnectionState, RtcPeerConnection, WebSocket, 14 | RtcIceCredentialType, RtcIceServer, RtcIceTransportPolicy, 15 | }; 16 | 17 | use shared_protocol::{SessionID, SignalEnum, UserID}; 18 | 19 | use crate::{ 20 | create_sdp_offer, receive_sdp_answer, receive_sdp_offer_send_answer, 21 | received_new_ice_candidate, setup_rtc_peer_connection_ice_callbacks, wasm_bindgen, 22 | }; 23 | 24 | const STUN_SERVER: &str = "stun:stun.l.google.com:19302"; 25 | const TURN: &str = "turn:192.168.178.60:3478"; 26 | 27 | #[derive(Debug)] 28 | pub struct AppState { 29 | session_id: Option, 30 | user_id: Option, 31 | } 32 | 33 | impl AppState { 34 | pub(crate) fn new() -> Self { 35 | AppState { 36 | session_id: None, 37 | user_id: None, 38 | } 39 | } 40 | 41 | pub(crate) fn set_session_id(&mut self, s_id: SessionID) { 42 | self.session_id = Some(s_id) 43 | } 44 | 45 | pub(crate) fn get_session_id(&mut self) -> Option { 46 | self.session_id.clone() 47 | } 48 | 49 | pub(crate) fn get_session_id_ref(&self) -> Option { 50 | self.session_id.clone() 51 | } 52 | 53 | pub(crate) fn set_user_id(&mut self, user_id: UserID) { 54 | self.user_id = Some(user_id) 55 | } 56 | 57 | pub(crate) fn get_user_id(&mut self) -> Option { 58 | self.user_id.clone() 59 | } 60 | } 61 | 62 | pub fn create_plain_peer_connection() -> Result { 63 | RtcPeerConnection::new() 64 | } 65 | 66 | pub fn create_turn_peer_connection() -> Result { 67 | 68 | // STUN HERE 69 | let mut stun_server = RtcIceServer::new(); 70 | stun_server.url(&STUN_SERVER); 71 | 72 | // TURN SERVER 73 | let turn_url = format!("{}",TURN); 74 | warn!("Turn URL: {}", TURN); 75 | let mut turn_server = RtcIceServer::new(); 76 | turn_server.url(&turn_url); 77 | let r_num= f64::ceil(js_sys::Math::random()*10.0) ; 78 | let r_num2 = r_num as u8; 79 | 80 | // Both users can have the same username + password, 81 | // The turn server doesnt really care 82 | let user = format!("user{}",r_num2); 83 | let pass = format!("pass{}",r_num2); 84 | 85 | info!("{}",format!("Creds: user:{} pass:{}",user, pass)); 86 | turn_server.username(&user); 87 | turn_server.credential(&pass); 88 | 89 | // turn_server.credential_type( RtcIceCredentialType::Token); 90 | turn_server.credential_type(RtcIceCredentialType::Password); 91 | let turn_server_ref: &JsValue = turn_server.as_ref(); 92 | let mut rtc_config = RtcConfiguration::new(); 93 | // let arr_ice_svr = Array::of2(turn_server_ref,stun_server_ref); 94 | let arr_ice_svr = Array::of1(turn_server_ref); 95 | warn!("ICE server Length {}",arr_ice_svr.length()); 96 | let arr_ice_svr_ref: &JsValue = arr_ice_svr.as_ref(); 97 | rtc_config.ice_servers(arr_ice_svr_ref); 98 | 99 | // rtc_config.ice_transport_policy(RtcIceTransportPolicy::All); 100 | // warn!("All transport"); 101 | // let transport_policy = RtcIceTransportPolicy::All; 102 | let transport_policy = RtcIceTransportPolicy::Relay; 103 | warn!("ICE transport {:?}",transport_policy); 104 | rtc_config.ice_transport_policy(transport_policy); // This is to force use of a TURN Server 105 | 106 | RtcPeerConnection::new_with_configuration(&rtc_config) 107 | 108 | } 109 | 110 | pub fn create_stun_peer_connection() -> Result { 111 | let ice_servers = Array::new(); 112 | { 113 | let server_entry = Object::new(); 114 | 115 | Reflect::set(&server_entry, &"urls".into(), &STUN_SERVER.into())?; 116 | 117 | ice_servers.push(&*server_entry); 118 | } 119 | 120 | let mut rtc_configuration = RtcConfiguration::new(); 121 | rtc_configuration.ice_servers(&ice_servers); 122 | 123 | RtcPeerConnection::new_with_configuration(&rtc_configuration) 124 | } 125 | 126 | pub async fn handle_message_reply( 127 | message: String, 128 | peer_connection: RtcPeerConnection, 129 | websocket: WebSocket, 130 | app_state: Rc>, 131 | ) -> Result<(), JsValue> { 132 | let result = match serde_json_wasm::from_str(&message) { 133 | Ok(x) => x, 134 | Err(_) => { 135 | error!("Could not deserialize Message {} ", message); 136 | return Ok(()); 137 | } 138 | }; 139 | 140 | match result { 141 | SignalEnum::VideoOffer(offer, session_id) => { 142 | warn!("VideoOffer Received "); 143 | let sdp_answer = receive_sdp_offer_send_answer(peer_connection.clone(), offer).await?; 144 | let signal = SignalEnum::VideoAnswer(sdp_answer, session_id); 145 | let response: String = match serde_json_wasm::to_string(&signal) { 146 | Ok(x) => x, 147 | Err(e) => { 148 | error!("Could not Serialize Video Offer {}", e); 149 | return Err(JsValue::from_str("Could not Serialize Video Offer")); 150 | } 151 | }; 152 | 153 | match websocket.send_with_str(&response) { 154 | Ok(_) => info!("Video Offer SignalEnum sent"), 155 | Err(err) => error!("Error sending Video Offer SignalEnum: {:?}", err), 156 | } 157 | } 158 | SignalEnum::VideoAnswer(answer, _) => { 159 | info!("Video Answer Received! {}", answer); 160 | receive_sdp_answer(peer_connection.clone(), answer).await?; 161 | } 162 | SignalEnum::IceCandidate(candidate, _) => { 163 | received_new_ice_candidate(candidate, peer_connection.clone()).await?; 164 | } 165 | SignalEnum::SessionReady(session_id) => { 166 | info!("SessionReady Received ! {:?}", session_id); 167 | let mut state = app_state.borrow_mut(); 168 | state.set_session_id(session_id.clone()); 169 | set_html_label("sessionid_lbl", session_id.inner()); 170 | } 171 | SignalEnum::SessionJoinSuccess(session_id) => { 172 | info!("SessionJoinSuccess {}", session_id.clone().inner()); 173 | set_session_connection_status_error("".into()); 174 | let mut state = app_state.borrow_mut(); 175 | state.set_session_id(session_id.clone()); 176 | drop(state); 177 | // Initiate the video call 178 | send_video_offer( 179 | peer_connection.clone(), 180 | websocket.clone(), 181 | session_id.clone(), 182 | ) 183 | .await; 184 | let full_string = format!("Connecting to Session: {}", session_id.inner()); 185 | set_html_label("session_connection_status", full_string); 186 | set_html_label("sessionid_heading", "".into()); 187 | } 188 | SignalEnum::SessionJoinError(session_id) => { 189 | error!("SessionJoinError! {}", session_id.clone().inner()); 190 | set_session_connection_status_error(session_id.inner()); 191 | } 192 | SignalEnum::SessionJoin(session_id) => { 193 | info!("{}", session_id.inner()) 194 | } 195 | SignalEnum::NewUser(user_id) => { 196 | info!("New User Received ! {}", user_id.clone().inner()); 197 | let mut state = app_state.borrow_mut(); 198 | state.set_user_id(user_id); 199 | } 200 | SignalEnum::ICEError(err, session_id) => { 201 | error!("ICEError! {}, {} ", err, session_id.inner()); 202 | } 203 | remaining => { 204 | error!("Frontend should not receive {:?}", remaining); 205 | } 206 | }; 207 | Ok(()) 208 | } 209 | 210 | #[wasm_bindgen] 211 | pub async fn get_video(video_id: String) -> Result { 212 | info!("Starting Video Device Capture!"); 213 | let window = web_sys::window().expect("No window Found"); 214 | let navigator = window.navigator(); 215 | let media_devices = match navigator.media_devices() { 216 | Ok(md) => md, 217 | Err(e) => return Err(e), 218 | }; 219 | 220 | let mut constraints = MediaStreamConstraints::new(); 221 | constraints.audio(&JsValue::FALSE); // Change this if you want Audio as well ! 222 | constraints.video(&JsValue::TRUE); 223 | 224 | let stream_promise: Promise = match media_devices.get_user_media_with_constraints(&constraints) 225 | { 226 | Ok(s) => s, 227 | Err(e) => return Err(e), 228 | }; 229 | 230 | let document: Document = window.document().expect("Couldn't Get Document"); 231 | 232 | let video_element: Element = match document.get_element_by_id(&video_id) { 233 | Some(ms) => ms, 234 | None => return Err(JsValue::from_str("No Element video found")), 235 | }; 236 | 237 | // debug!("video_element {:?}", video_element); 238 | 239 | let media_stream: MediaStream = match wasm_bindgen_futures::JsFuture::from(stream_promise).await 240 | { 241 | Ok(ms) => MediaStream::from(ms), 242 | Err(e) => { 243 | error!("{:?}", e); 244 | error!("{:?}","Its possible that the There is already a tab open with a handle to the Media Stream"); 245 | error!( 246 | "{:?}", 247 | "Check if Other tab is open with Video/Audio Stream open" 248 | ); 249 | return Err(JsValue::from_str("User Did not allow access to the Camera")); 250 | } 251 | }; 252 | 253 | let vid_elem: HtmlVideoElement = match video_element.dyn_into::() { 254 | Ok(x) => x, 255 | Err(e) => { 256 | error!("{:?}", e); 257 | return Err(JsValue::from_str("User Did not allow access to the Camera")); 258 | } 259 | }; 260 | 261 | vid_elem.set_src_object(Some(&media_stream)); 262 | Ok(media_stream) 263 | } 264 | 265 | pub fn setup_show_state(rtc_conn: RtcPeerConnection, state: Rc>) { 266 | let window = web_sys::window().expect("No window Found"); 267 | let document: Document = window.document().expect("Couldn't Get Document"); 268 | 269 | // DEBUG BUTTONS 270 | let rtc_clone_external = rtc_conn; 271 | let btn_cb = Closure::wrap(Box::new(move || { 272 | let rtc_clone = rtc_clone_external.clone(); 273 | show_rtc_state(rtc_clone, state.clone()); 274 | }) as Box); 275 | 276 | document 277 | .get_element_by_id("debug_client_state") 278 | .expect("should have debug_client_state on the page") 279 | .dyn_ref::() 280 | .expect("#Button should be a be an `HtmlButtonElement`") 281 | .set_onclick(Some(btn_cb.as_ref().unchecked_ref())); 282 | btn_cb.forget(); 283 | } 284 | 285 | fn show_rtc_state(rtc_conn: RtcPeerConnection, state: Rc>) { 286 | debug!("==========================="); 287 | debug!("Signalling State : {:?}", rtc_conn.signaling_state()); 288 | debug!("Ice Conn State : {:?}", rtc_conn.ice_connection_state()); 289 | debug!("ice gathering_state : {:?}", rtc_conn.ice_gathering_state()); 290 | debug!("local_description : {:?}", rtc_conn.local_description()); 291 | debug!("remote_description : {:?}", rtc_conn.remote_description()); 292 | debug!("get_senders : {:?}", rtc_conn.get_senders()); 293 | debug!("get_receivers : {:?}", rtc_conn.get_receivers()); 294 | debug!("==========================="); 295 | 296 | let mut state = state.borrow_mut(); 297 | 298 | debug!("==========================="); 299 | debug!(" User ID : {:?}", state.get_user_id()); 300 | debug!(" Session ID : {:?}", state.get_session_id()); 301 | } 302 | 303 | pub fn setup_show_signalling_server_state(ws: WebSocket) { 304 | let window = web_sys::window().expect("No window Found"); 305 | let document: Document = window.document().expect("Couldn't Get Document"); 306 | 307 | // DEBUG BUTTONS 308 | let btn_cb = Closure::wrap(Box::new(move || { 309 | let msg = SignalEnum::Debug; 310 | let ser_msg: String = 311 | serde_json_wasm::to_string(&msg).expect("Couldn't Serialize SignalEnum::Debug Message"); 312 | 313 | match ws.clone().send_with_str(&ser_msg) { 314 | Ok(_) => {} 315 | Err(e) => { 316 | error!("Error Sending SessionNew {:?}", e); 317 | } 318 | } 319 | }) as Box); 320 | 321 | document 322 | .get_element_by_id("debug_signal_server_state") 323 | .expect("should have debug_signal_server_state on the page") 324 | .dyn_ref::() 325 | .expect("#Button should be a be an `HtmlButtonElement`") 326 | .set_onclick(Some(btn_cb.as_ref().unchecked_ref())); 327 | btn_cb.forget(); 328 | } 329 | 330 | /// RTC Listener 331 | pub async fn setup_listener( 332 | peer_b: RtcPeerConnection, 333 | websocket: WebSocket, 334 | rc_state: Rc>, 335 | ) -> Result<(), JsValue> { 336 | let window = web_sys::window().expect("No window Found"); 337 | let document: Document = window.document().expect("Couldn't Get Document"); 338 | 339 | let ws_clone_external = websocket; 340 | let peer_b_clone_external = peer_b; 341 | let document_clone_external = document.clone(); 342 | let rc_state_clone_external = rc_state; 343 | 344 | let btn_cb = Closure::wrap(Box::new(move || { 345 | let ws_clone = ws_clone_external.clone(); 346 | let peer_b_clone = peer_b_clone_external.clone(); 347 | let document_clone = document_clone_external.clone(); 348 | let rc_state_clone_internal = rc_state_clone_external.clone(); 349 | 350 | // Start Remote Video Callback 351 | let video_elem = "peer_a_video".into(); 352 | 353 | let ice_state_change = 354 | rtc_ice_state_change(peer_b_clone.clone(), document_clone, video_elem); 355 | peer_b_clone 356 | .set_oniceconnectionstatechange(Some(ice_state_change.as_ref().unchecked_ref())); 357 | ice_state_change.forget(); 358 | 359 | // Start Local Video Callback 360 | let peer_b_clone_media = peer_b_clone_external.clone(); 361 | wasm_bindgen_futures::spawn_local(async move { 362 | let media_stream = get_video(String::from("peer_b_video")) 363 | .await 364 | .expect_throw("Couldn't Get Media Stream"); 365 | peer_b_clone_media.add_stream(&media_stream); 366 | }); 367 | 368 | // Need to setup Media Stream BEFORE sending SDP offer!!! 369 | // SDP offer Contains information about the Video Streaming technologies available to this and the other browser 370 | // If negotiation has completed, this closure will be called 371 | let ondatachannel_callback = Closure::wrap(Box::new(move |ev: RtcDataChannelEvent| { 372 | let dc2 = ev.channel(); 373 | info!("peer_b.ondatachannel! : {}", dc2.label()); 374 | let onmessage_callback = Closure::wrap(Box::new(move |ev: MessageEvent| { 375 | if let Some(message) = ev.data().as_string() { 376 | warn!("{:?}", message) 377 | } 378 | }) as Box); 379 | dc2.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref())); 380 | onmessage_callback.forget(); 381 | dc2.send_with_str("Ping from peer_b.dc!").unwrap(); 382 | }) 383 | as Box); 384 | 385 | peer_b_clone.set_ondatachannel(Some(ondatachannel_callback.as_ref().unchecked_ref())); 386 | ondatachannel_callback.forget(); 387 | 388 | let peer_b_clone = peer_b_clone_external.clone(); 389 | let ws_clone1 = ws_clone.clone(); 390 | let rc_state_clone = rc_state_clone_internal; 391 | 392 | // Setup ICE callbacks 393 | // let res = setup_rtc_peer_connection_ice_callbacks(peer_b_clone, ws_clone1, rc_state_clone).await; 394 | // if res.is_err() { 395 | // log::error!("Error Setting up ice callbacks {:?}", res.unwrap_err()) 396 | // } 397 | 398 | wasm_bindgen_futures::spawn_local(async move { 399 | let res = setup_rtc_peer_connection_ice_callbacks(peer_b_clone, ws_clone1, rc_state_clone).await; 400 | if res.is_err() { 401 | log::error!("Error Setting up ice callbacks {:?}", res.unwrap_err()) 402 | } 403 | }); 404 | 405 | 406 | host_session(ws_clone); 407 | }) as Box); 408 | 409 | document 410 | .get_element_by_id("start_session") 411 | .expect("should have start_session on the page") 412 | .dyn_ref::() 413 | .expect("#Button should be a be an `HtmlButtonElement`") 414 | .set_onclick(Some(btn_cb.as_ref().unchecked_ref())); 415 | btn_cb.forget(); 416 | 417 | Ok(()) 418 | } 419 | 420 | fn host_session(ws: WebSocket) { 421 | info!("Sending SessionNew"); 422 | let msg = SignalEnum::SessionNew; 423 | let ser_msg: String = match serde_json_wasm::to_string(&msg) { 424 | Ok(x) => x, 425 | Err(e) => { 426 | error!("Could not serialize SessionNew {}", e); 427 | return; 428 | } 429 | }; 430 | 431 | match ws.send_with_str(&ser_msg) { 432 | Ok(_) => {} 433 | Err(e) => { 434 | error!("Error Sending SessionNew {:?}", e); 435 | } 436 | } 437 | } 438 | 439 | fn peer_a_dc_on_message(dc: RtcDataChannel) -> Closure { 440 | Closure::wrap(Box::new(move |ev: MessageEvent| { 441 | if let Some(message) = ev.data().as_string() { 442 | warn!("{:?}", message); 443 | dc.send_with_str("Pong from peer_a data channel!").unwrap(); 444 | } 445 | }) as Box) 446 | } 447 | 448 | pub async fn setup_initiator( 449 | peer_a: RtcPeerConnection, 450 | websocket: WebSocket, 451 | rc_state: Rc>, 452 | ) -> Result<(), JsValue> { 453 | let window = web_sys::window().expect("No window Found"); 454 | let document: Document = window.document().expect("Couldn't Get Document"); 455 | 456 | let ws_clone_external = websocket; 457 | let peer_a_clone_external = peer_a.clone(); 458 | let rc_state_clone_ext = rc_state; 459 | 460 | /* 461 | * Create DataChannel on peer_a to negotiate 462 | * Message will be shown here after connection established 463 | */ 464 | 465 | info!("peer_a State 1: {:?}", peer_a.signaling_state()); 466 | let dc1 = peer_a.create_data_channel("my-data-channel"); 467 | info!("dc1 created: label {:?}", dc1.label()); 468 | 469 | let dc1_clone = dc1.clone(); 470 | let onmessage_callback = peer_a_dc_on_message(dc1_clone); 471 | dc1.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref())); 472 | onmessage_callback.forget(); 473 | 474 | let btn_cb = Closure::wrap(Box::new(move || { 475 | let ws_clone = ws_clone_external.clone(); 476 | let peer_a_clone = peer_a_clone_external.clone(); 477 | let rc_state_clone = rc_state_clone_ext.clone(); 478 | 479 | // let res = 480 | // setup_rtc_peer_connection_ice_callbacks(peer_a_clone, ws_clone.clone(), rc_state_clone); 481 | // if res.is_err() { 482 | // error!( 483 | // "Error Setting up RTCPeerConnection ICE Callbacks {:?}", 484 | // res.unwrap_err() 485 | // ) 486 | // } 487 | 488 | let ws_clone1 = ws_clone.clone(); 489 | wasm_bindgen_futures::spawn_local(async move { 490 | let res = setup_rtc_peer_connection_ice_callbacks(peer_a_clone, ws_clone1, rc_state_clone).await; 491 | if res.is_err() { 492 | log::error!("Error Setting up ice callbacks {:?}", res.unwrap_err()) 493 | } 494 | }); 495 | 496 | 497 | try_connect_to_session(ws_clone); 498 | }) as Box); 499 | document 500 | .get_element_by_id("connect_to_session") 501 | .expect("should have connect_to_session on the page") 502 | .dyn_ref::() 503 | .expect("#Button should be a be an `HtmlButtonElement`") 504 | .set_onclick(Some(btn_cb.as_ref().unchecked_ref())); 505 | btn_cb.forget(); 506 | 507 | // Start Remote Video Callback 508 | let video_element = "peer_b_video".into(); 509 | // let state_lbl = "InitiatorState".into(); 510 | let ice_state_change = rtc_ice_state_change(peer_a.clone(), document, video_element); 511 | peer_a.set_oniceconnectionstatechange(Some(ice_state_change.as_ref().unchecked_ref())); 512 | ice_state_change.forget(); 513 | 514 | Ok(()) 515 | } 516 | 517 | fn rtc_ice_state_change( 518 | rtc_connection: RtcPeerConnection, 519 | document: Document, 520 | video_element: String, 521 | ) -> Closure { 522 | Closure::wrap(Box::new(move || { 523 | /////////////////////////////////////////////////////////////// 524 | /////// Start Video When connected 525 | /////////////////////////////////////////////////////////////// 526 | match rtc_connection.ice_connection_state() { 527 | RtcIceConnectionState::Connected => { 528 | // let remote_streams = rtc_conn.get_senders().to_vec(); 529 | let remote_streams = rtc_connection.get_remote_streams().to_vec(); 530 | debug!("remote_streams {:?}", remote_streams); 531 | // remote_streams 532 | if remote_streams.len() == 1 { 533 | let first_stream = remote_streams[0].clone(); 534 | debug!("First Stream {:?}", first_stream); 535 | let res_media_stream: Result = first_stream.try_into(); 536 | let media_stream = res_media_stream.unwrap(); 537 | debug!("Media Stream {:?}", media_stream); 538 | let video_element: Element = 539 | document.get_element_by_id(&video_element).unwrap_throw(); 540 | let vid_elem: HtmlVideoElement = 541 | video_element.dyn_into::().unwrap_throw(); 542 | let res = vid_elem.set_src_object(Some(&media_stream)); 543 | debug!("Result Video Set src Object {:?} ", res); 544 | } 545 | } 546 | _ => { 547 | warn!("Ice State: {:?}", rtc_connection.ice_connection_state()); 548 | } 549 | } 550 | }) as Box) 551 | } 552 | 553 | fn set_html_label(html_label: &str, session_id: String) { 554 | let window = web_sys::window().expect("No window Found, We've got bigger problems here"); 555 | let document: Document = window.document().expect("Couldn't Get Document"); 556 | document 557 | .get_element_by_id(html_label) 558 | .unwrap_or_else(|| panic!("Should have {} on the page", html_label)) 559 | .dyn_ref::() 560 | .expect("#Button should be a be an `HtmlLabelElement`") 561 | .set_text_content(Some(&session_id)); 562 | } 563 | 564 | fn get_session_id_from_input() -> String { 565 | let window = web_sys::window().expect("No window Found, We've got bigger problems here"); 566 | let document: Document = window.document().expect("Couldn't Get Document"); 567 | let sid_input = "sid_input"; 568 | 569 | let sid_input = document 570 | .get_element_by_id(sid_input) 571 | .unwrap_or_else(|| panic!("Should have {} on the page", sid_input)) 572 | .dyn_ref::() 573 | .expect("#HtmlInputElement should be a be an `HtmlInputElement`") 574 | .value() 575 | .trim() 576 | .to_string(); 577 | info!("sid_inputs {}", sid_input); 578 | sid_input 579 | } 580 | 581 | fn set_session_connection_status_error(error: String) { 582 | let window = web_sys::window().expect("No window Found, We've got bigger problems here"); 583 | let document: Document = window.document().expect("Couldn't Get Document"); 584 | let ws_conn_lbl = "session_connection_status_error"; 585 | 586 | let e_string; 587 | if error.is_empty() { 588 | e_string = format!("") 589 | } else { 590 | e_string = format!("Could not connect: {} ", error) 591 | } 592 | 593 | document 594 | .get_element_by_id(ws_conn_lbl) 595 | .unwrap_or_else(|| panic!("Should have {} on the page", ws_conn_lbl)) 596 | .dyn_ref::() 597 | .expect("#Button should be a be an `HtmlLabelElement`") 598 | .set_text_content(Some(&e_string)); 599 | } 600 | 601 | fn try_connect_to_session(ws: WebSocket) { 602 | let session_id_string = get_session_id_from_input(); 603 | let session_id = SessionID::new(session_id_string); 604 | let msg = SignalEnum::SessionJoin(session_id); 605 | let ser_msg: String = match serde_json_wasm::to_string(&msg) { 606 | Ok(x) => x, 607 | Err(e) => { 608 | error!("Could not serialize SessionJoin {}", e); 609 | return; 610 | } 611 | }; 612 | match ws.send_with_str(&ser_msg) { 613 | Ok(_) => {} 614 | Err(e) => { 615 | error!("Error Sending SessionJoin {:?}", e); 616 | } 617 | } 618 | } 619 | 620 | async fn send_video_offer(rtc_conn: RtcPeerConnection, ws: WebSocket, session_id: SessionID) { 621 | // NB !!! 622 | // Need to setup Media Stream BEFORE sending SDP offer 623 | // SDP offer Contains information about the Video Streaming technologies available to this and the other browser 624 | let media_stream = get_video(String::from("peer_a_video")) 625 | .await 626 | .expect_throw("Couldn't Get Media Stream"); 627 | debug!("peer_a_video result {:?}", media_stream); 628 | rtc_conn.add_stream(&media_stream); 629 | let tracks = media_stream.get_tracks(); 630 | debug!("peer_a_video Tracks {:?}", tracks); 631 | 632 | // Send SDP offer 633 | let sdp_offer = create_sdp_offer(rtc_conn).await.unwrap_throw(); 634 | let msg = SignalEnum::VideoOffer(sdp_offer, session_id); 635 | let ser_msg: String = match serde_json_wasm::to_string(&msg) { 636 | Ok(x) => x, 637 | Err(e) => { 638 | error!("Could not serialize VideoOffer {}", e); 639 | return; 640 | } 641 | }; 642 | 643 | info!("SDP VideoOffer {}", ser_msg); 644 | match ws.clone().send_with_str(&ser_msg) { 645 | Ok(_) => {} 646 | Err(e) => { 647 | error!("Error Sending Video Offer {:?}", e); 648 | } 649 | } 650 | } 651 | -------------------------------------------------------------------------------- /signalling-server/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "async-channel" 5 | version = "1.6.1" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" 8 | dependencies = [ 9 | "concurrent-queue", 10 | "event-listener", 11 | "futures-core", 12 | ] 13 | 14 | [[package]] 15 | name = "async-executor" 16 | version = "1.4.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146" 19 | dependencies = [ 20 | "async-task", 21 | "concurrent-queue", 22 | "fastrand", 23 | "futures-lite", 24 | "once_cell", 25 | "vec-arena", 26 | ] 27 | 28 | [[package]] 29 | name = "async-global-executor" 30 | version = "2.0.2" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" 33 | dependencies = [ 34 | "async-channel", 35 | "async-executor", 36 | "async-io", 37 | "async-mutex", 38 | "blocking", 39 | "futures-lite", 40 | "num_cpus", 41 | "once_cell", 42 | ] 43 | 44 | [[package]] 45 | name = "async-io" 46 | version = "1.3.1" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "9315f8f07556761c3e48fec2e6b276004acf426e6dc068b2c2251854d65ee0fd" 49 | dependencies = [ 50 | "concurrent-queue", 51 | "fastrand", 52 | "futures-lite", 53 | "libc", 54 | "log", 55 | "nb-connect", 56 | "once_cell", 57 | "parking", 58 | "polling", 59 | "vec-arena", 60 | "waker-fn", 61 | "winapi", 62 | ] 63 | 64 | [[package]] 65 | name = "async-lock" 66 | version = "2.3.0" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "1996609732bde4a9988bc42125f55f2af5f3c36370e27c778d5191a4a1b63bfb" 69 | dependencies = [ 70 | "event-listener", 71 | ] 72 | 73 | [[package]] 74 | name = "async-mutex" 75 | version = "1.4.0" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" 78 | dependencies = [ 79 | "event-listener", 80 | ] 81 | 82 | [[package]] 83 | name = "async-std" 84 | version = "1.9.0" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "d9f06685bad74e0570f5213741bea82158279a4103d988e57bfada11ad230341" 87 | dependencies = [ 88 | "async-channel", 89 | "async-global-executor", 90 | "async-io", 91 | "async-lock", 92 | "crossbeam-utils", 93 | "futures-channel", 94 | "futures-core", 95 | "futures-io", 96 | "futures-lite", 97 | "gloo-timers", 98 | "kv-log-macro", 99 | "log", 100 | "memchr", 101 | "num_cpus", 102 | "once_cell", 103 | "pin-project-lite", 104 | "pin-utils", 105 | "slab", 106 | "wasm-bindgen-futures", 107 | ] 108 | 109 | [[package]] 110 | name = "async-task" 111 | version = "4.0.3" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" 114 | 115 | [[package]] 116 | name = "async-tungstenite" 117 | version = "0.12.0" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "e00550829ef8e2c4115250d0ee43305649b0fa95f78a32ce5b07da0b73d95c5c" 120 | dependencies = [ 121 | "futures-io", 122 | "futures-util", 123 | "log", 124 | "pin-project-lite", 125 | "tungstenite", 126 | ] 127 | 128 | [[package]] 129 | name = "atomic-waker" 130 | version = "1.0.0" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" 133 | 134 | [[package]] 135 | name = "autocfg" 136 | version = "1.0.1" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 139 | 140 | [[package]] 141 | name = "base64" 142 | version = "0.13.0" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 145 | 146 | [[package]] 147 | name = "block-buffer" 148 | version = "0.9.0" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 151 | dependencies = [ 152 | "generic-array", 153 | ] 154 | 155 | [[package]] 156 | name = "blocking" 157 | version = "1.0.2" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" 160 | dependencies = [ 161 | "async-channel", 162 | "async-task", 163 | "atomic-waker", 164 | "fastrand", 165 | "futures-lite", 166 | "once_cell", 167 | ] 168 | 169 | [[package]] 170 | name = "bumpalo" 171 | version = "3.6.1" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" 174 | 175 | [[package]] 176 | name = "byteorder" 177 | version = "1.4.3" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 180 | 181 | [[package]] 182 | name = "bytes" 183 | version = "1.0.1" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" 186 | 187 | [[package]] 188 | name = "cache-padded" 189 | version = "1.1.1" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" 192 | 193 | [[package]] 194 | name = "cc" 195 | version = "1.0.67" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" 198 | 199 | [[package]] 200 | name = "cfg-if" 201 | version = "0.1.10" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 204 | 205 | [[package]] 206 | name = "cfg-if" 207 | version = "1.0.0" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 210 | 211 | [[package]] 212 | name = "chrono" 213 | version = "0.4.19" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 216 | dependencies = [ 217 | "libc", 218 | "num-integer", 219 | "num-traits", 220 | "time", 221 | "winapi", 222 | ] 223 | 224 | [[package]] 225 | name = "concurrent-queue" 226 | version = "1.2.2" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" 229 | dependencies = [ 230 | "cache-padded", 231 | ] 232 | 233 | [[package]] 234 | name = "cpuid-bool" 235 | version = "0.1.2" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" 238 | 239 | [[package]] 240 | name = "crossbeam-utils" 241 | version = "0.8.3" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" 244 | dependencies = [ 245 | "autocfg", 246 | "cfg-if 1.0.0", 247 | "lazy_static", 248 | ] 249 | 250 | [[package]] 251 | name = "ctor" 252 | version = "0.1.19" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19" 255 | dependencies = [ 256 | "quote", 257 | "syn", 258 | ] 259 | 260 | [[package]] 261 | name = "digest" 262 | version = "0.9.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 265 | dependencies = [ 266 | "generic-array", 267 | ] 268 | 269 | [[package]] 270 | name = "event-listener" 271 | version = "2.5.1" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" 274 | 275 | [[package]] 276 | name = "fastrand" 277 | version = "1.4.0" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" 280 | dependencies = [ 281 | "instant", 282 | ] 283 | 284 | [[package]] 285 | name = "fnv" 286 | version = "1.0.7" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 289 | 290 | [[package]] 291 | name = "form_urlencoded" 292 | version = "1.0.1" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 295 | dependencies = [ 296 | "matches", 297 | "percent-encoding", 298 | ] 299 | 300 | [[package]] 301 | name = "futures" 302 | version = "0.3.13" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" 305 | dependencies = [ 306 | "futures-channel", 307 | "futures-core", 308 | "futures-executor", 309 | "futures-io", 310 | "futures-sink", 311 | "futures-task", 312 | "futures-util", 313 | ] 314 | 315 | [[package]] 316 | name = "futures-channel" 317 | version = "0.3.13" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" 320 | dependencies = [ 321 | "futures-core", 322 | "futures-sink", 323 | ] 324 | 325 | [[package]] 326 | name = "futures-core" 327 | version = "0.3.13" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" 330 | 331 | [[package]] 332 | name = "futures-executor" 333 | version = "0.3.13" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" 336 | dependencies = [ 337 | "futures-core", 338 | "futures-task", 339 | "futures-util", 340 | ] 341 | 342 | [[package]] 343 | name = "futures-io" 344 | version = "0.3.13" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" 347 | 348 | [[package]] 349 | name = "futures-lite" 350 | version = "1.11.3" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb" 353 | dependencies = [ 354 | "fastrand", 355 | "futures-core", 356 | "futures-io", 357 | "memchr", 358 | "parking", 359 | "pin-project-lite", 360 | "waker-fn", 361 | ] 362 | 363 | [[package]] 364 | name = "futures-macro" 365 | version = "0.3.13" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7" 368 | dependencies = [ 369 | "proc-macro-hack", 370 | "proc-macro2", 371 | "quote", 372 | "syn", 373 | ] 374 | 375 | [[package]] 376 | name = "futures-sink" 377 | version = "0.3.13" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3" 380 | 381 | [[package]] 382 | name = "futures-task" 383 | version = "0.3.13" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80" 386 | 387 | [[package]] 388 | name = "futures-util" 389 | version = "0.3.13" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" 392 | dependencies = [ 393 | "futures-channel", 394 | "futures-core", 395 | "futures-io", 396 | "futures-macro", 397 | "futures-sink", 398 | "futures-task", 399 | "memchr", 400 | "pin-project-lite", 401 | "pin-utils", 402 | "proc-macro-hack", 403 | "proc-macro-nested", 404 | "slab", 405 | ] 406 | 407 | [[package]] 408 | name = "generic-array" 409 | version = "0.14.4" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 412 | dependencies = [ 413 | "typenum", 414 | "version_check", 415 | ] 416 | 417 | [[package]] 418 | name = "getrandom" 419 | version = "0.2.2" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" 422 | dependencies = [ 423 | "cfg-if 1.0.0", 424 | "libc", 425 | "wasi", 426 | ] 427 | 428 | [[package]] 429 | name = "gloo-timers" 430 | version = "0.2.1" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" 433 | dependencies = [ 434 | "futures-channel", 435 | "futures-core", 436 | "js-sys", 437 | "wasm-bindgen", 438 | "web-sys", 439 | ] 440 | 441 | [[package]] 442 | name = "hermit-abi" 443 | version = "0.1.18" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 446 | dependencies = [ 447 | "libc", 448 | ] 449 | 450 | [[package]] 451 | name = "http" 452 | version = "0.2.3" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" 455 | dependencies = [ 456 | "bytes", 457 | "fnv", 458 | "itoa", 459 | ] 460 | 461 | [[package]] 462 | name = "httparse" 463 | version = "1.3.5" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691" 466 | 467 | [[package]] 468 | name = "idna" 469 | version = "0.2.2" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" 472 | dependencies = [ 473 | "matches", 474 | "unicode-bidi", 475 | "unicode-normalization", 476 | ] 477 | 478 | [[package]] 479 | name = "input_buffer" 480 | version = "0.4.0" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" 483 | dependencies = [ 484 | "bytes", 485 | ] 486 | 487 | [[package]] 488 | name = "instant" 489 | version = "0.1.9" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" 492 | dependencies = [ 493 | "cfg-if 1.0.0", 494 | ] 495 | 496 | [[package]] 497 | name = "itoa" 498 | version = "0.4.7" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" 501 | 502 | [[package]] 503 | name = "js-sys" 504 | version = "0.3.48" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78" 507 | dependencies = [ 508 | "wasm-bindgen", 509 | ] 510 | 511 | [[package]] 512 | name = "kv-log-macro" 513 | version = "1.0.7" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" 516 | dependencies = [ 517 | "log", 518 | ] 519 | 520 | [[package]] 521 | name = "lazy_static" 522 | version = "1.4.0" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 525 | 526 | [[package]] 527 | name = "libc" 528 | version = "0.2.88" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" 531 | 532 | [[package]] 533 | name = "log" 534 | version = "0.4.14" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 537 | dependencies = [ 538 | "cfg-if 1.0.0", 539 | "value-bag", 540 | ] 541 | 542 | [[package]] 543 | name = "matches" 544 | version = "0.1.8" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 547 | 548 | [[package]] 549 | name = "memchr" 550 | version = "2.3.4" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 553 | 554 | [[package]] 555 | name = "nb-connect" 556 | version = "1.0.3" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "670361df1bc2399ee1ff50406a0d422587dd3bb0da596e1978fe8e05dabddf4f" 559 | dependencies = [ 560 | "libc", 561 | "socket2", 562 | ] 563 | 564 | [[package]] 565 | name = "num-integer" 566 | version = "0.1.44" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 569 | dependencies = [ 570 | "autocfg", 571 | "num-traits", 572 | ] 573 | 574 | [[package]] 575 | name = "num-traits" 576 | version = "0.2.14" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 579 | dependencies = [ 580 | "autocfg", 581 | ] 582 | 583 | [[package]] 584 | name = "num_cpus" 585 | version = "1.13.0" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 588 | dependencies = [ 589 | "hermit-abi", 590 | "libc", 591 | ] 592 | 593 | [[package]] 594 | name = "once_cell" 595 | version = "1.7.2" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" 598 | 599 | [[package]] 600 | name = "opaque-debug" 601 | version = "0.3.0" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 604 | 605 | [[package]] 606 | name = "parking" 607 | version = "2.0.0" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" 610 | 611 | [[package]] 612 | name = "percent-encoding" 613 | version = "2.1.0" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 616 | 617 | [[package]] 618 | name = "pin-project-lite" 619 | version = "0.2.6" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" 622 | 623 | [[package]] 624 | name = "pin-utils" 625 | version = "0.1.0" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 628 | 629 | [[package]] 630 | name = "polling" 631 | version = "2.0.2" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" 634 | dependencies = [ 635 | "cfg-if 0.1.10", 636 | "libc", 637 | "log", 638 | "wepoll-sys", 639 | "winapi", 640 | ] 641 | 642 | [[package]] 643 | name = "ppv-lite86" 644 | version = "0.2.10" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 647 | 648 | [[package]] 649 | name = "proc-macro-hack" 650 | version = "0.5.19" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 653 | 654 | [[package]] 655 | name = "proc-macro-nested" 656 | version = "0.1.7" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" 659 | 660 | [[package]] 661 | name = "proc-macro2" 662 | version = "1.0.24" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 665 | dependencies = [ 666 | "unicode-xid", 667 | ] 668 | 669 | [[package]] 670 | name = "quote" 671 | version = "1.0.9" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 674 | dependencies = [ 675 | "proc-macro2", 676 | ] 677 | 678 | [[package]] 679 | name = "rand" 680 | version = "0.8.3" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" 683 | dependencies = [ 684 | "libc", 685 | "rand_chacha", 686 | "rand_core", 687 | "rand_hc", 688 | ] 689 | 690 | [[package]] 691 | name = "rand_chacha" 692 | version = "0.3.0" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" 695 | dependencies = [ 696 | "ppv-lite86", 697 | "rand_core", 698 | ] 699 | 700 | [[package]] 701 | name = "rand_core" 702 | version = "0.6.2" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" 705 | dependencies = [ 706 | "getrandom", 707 | ] 708 | 709 | [[package]] 710 | name = "rand_hc" 711 | version = "0.3.0" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" 714 | dependencies = [ 715 | "rand_core", 716 | ] 717 | 718 | [[package]] 719 | name = "ryu" 720 | version = "1.0.5" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 723 | 724 | [[package]] 725 | name = "serde" 726 | version = "1.0.124" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" 729 | dependencies = [ 730 | "serde_derive", 731 | ] 732 | 733 | [[package]] 734 | name = "serde_derive" 735 | version = "1.0.124" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" 738 | dependencies = [ 739 | "proc-macro2", 740 | "quote", 741 | "syn", 742 | ] 743 | 744 | [[package]] 745 | name = "serde_json" 746 | version = "1.0.64" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" 749 | dependencies = [ 750 | "itoa", 751 | "ryu", 752 | "serde", 753 | ] 754 | 755 | [[package]] 756 | name = "sha-1" 757 | version = "0.9.4" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" 760 | dependencies = [ 761 | "block-buffer", 762 | "cfg-if 1.0.0", 763 | "cpuid-bool", 764 | "digest", 765 | "opaque-debug", 766 | ] 767 | 768 | [[package]] 769 | name = "signalling-server" 770 | version = "0.1.0" 771 | dependencies = [ 772 | "async-std", 773 | "async-tungstenite", 774 | "futures", 775 | "log", 776 | "rand", 777 | "serde", 778 | "serde_json", 779 | "simplelog", 780 | ] 781 | 782 | [[package]] 783 | name = "simplelog" 784 | version = "0.8.0" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "2b2736f58087298a448859961d3f4a0850b832e72619d75adc69da7993c2cd3c" 787 | dependencies = [ 788 | "chrono", 789 | "log", 790 | "termcolor", 791 | ] 792 | 793 | [[package]] 794 | name = "slab" 795 | version = "0.4.2" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 798 | 799 | [[package]] 800 | name = "socket2" 801 | version = "0.3.19" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" 804 | dependencies = [ 805 | "cfg-if 1.0.0", 806 | "libc", 807 | "winapi", 808 | ] 809 | 810 | [[package]] 811 | name = "syn" 812 | version = "1.0.63" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "8fd9bc7ccc2688b3344c2f48b9b546648b25ce0b20fc717ee7fa7981a8ca9717" 815 | dependencies = [ 816 | "proc-macro2", 817 | "quote", 818 | "unicode-xid", 819 | ] 820 | 821 | [[package]] 822 | name = "termcolor" 823 | version = "1.1.2" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 826 | dependencies = [ 827 | "winapi-util", 828 | ] 829 | 830 | [[package]] 831 | name = "time" 832 | version = "0.1.43" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 835 | dependencies = [ 836 | "libc", 837 | "winapi", 838 | ] 839 | 840 | [[package]] 841 | name = "tinyvec" 842 | version = "1.1.1" 843 | source = "registry+https://github.com/rust-lang/crates.io-index" 844 | checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" 845 | dependencies = [ 846 | "tinyvec_macros", 847 | ] 848 | 849 | [[package]] 850 | name = "tinyvec_macros" 851 | version = "0.1.0" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 854 | 855 | [[package]] 856 | name = "tungstenite" 857 | version = "0.12.0" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24" 860 | dependencies = [ 861 | "base64", 862 | "byteorder", 863 | "bytes", 864 | "http", 865 | "httparse", 866 | "input_buffer", 867 | "log", 868 | "rand", 869 | "sha-1", 870 | "url", 871 | "utf-8", 872 | ] 873 | 874 | [[package]] 875 | name = "typenum" 876 | version = "1.13.0" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" 879 | 880 | [[package]] 881 | name = "unicode-bidi" 882 | version = "0.3.4" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 885 | dependencies = [ 886 | "matches", 887 | ] 888 | 889 | [[package]] 890 | name = "unicode-normalization" 891 | version = "0.1.17" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" 894 | dependencies = [ 895 | "tinyvec", 896 | ] 897 | 898 | [[package]] 899 | name = "unicode-xid" 900 | version = "0.2.1" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 903 | 904 | [[package]] 905 | name = "url" 906 | version = "2.2.1" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" 909 | dependencies = [ 910 | "form_urlencoded", 911 | "idna", 912 | "matches", 913 | "percent-encoding", 914 | ] 915 | 916 | [[package]] 917 | name = "utf-8" 918 | version = "0.7.5" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" 921 | 922 | [[package]] 923 | name = "value-bag" 924 | version = "1.0.0-alpha.6" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "6b676010e055c99033117c2343b33a40a30b91fecd6c49055ac9cd2d6c305ab1" 927 | dependencies = [ 928 | "ctor", 929 | ] 930 | 931 | [[package]] 932 | name = "vec-arena" 933 | version = "1.0.0" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" 936 | 937 | [[package]] 938 | name = "version_check" 939 | version = "0.9.2" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" 942 | 943 | [[package]] 944 | name = "waker-fn" 945 | version = "1.1.0" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" 948 | 949 | [[package]] 950 | name = "wasi" 951 | version = "0.10.2+wasi-snapshot-preview1" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 954 | 955 | [[package]] 956 | name = "wasm-bindgen" 957 | version = "0.2.71" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7" 960 | dependencies = [ 961 | "cfg-if 1.0.0", 962 | "wasm-bindgen-macro", 963 | ] 964 | 965 | [[package]] 966 | name = "wasm-bindgen-backend" 967 | version = "0.2.71" 968 | source = "registry+https://github.com/rust-lang/crates.io-index" 969 | checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8" 970 | dependencies = [ 971 | "bumpalo", 972 | "lazy_static", 973 | "log", 974 | "proc-macro2", 975 | "quote", 976 | "syn", 977 | "wasm-bindgen-shared", 978 | ] 979 | 980 | [[package]] 981 | name = "wasm-bindgen-futures" 982 | version = "0.4.21" 983 | source = "registry+https://github.com/rust-lang/crates.io-index" 984 | checksum = "8e67a5806118af01f0d9045915676b22aaebecf4178ae7021bc171dab0b897ab" 985 | dependencies = [ 986 | "cfg-if 1.0.0", 987 | "js-sys", 988 | "wasm-bindgen", 989 | "web-sys", 990 | ] 991 | 992 | [[package]] 993 | name = "wasm-bindgen-macro" 994 | version = "0.2.71" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b" 997 | dependencies = [ 998 | "quote", 999 | "wasm-bindgen-macro-support", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "wasm-bindgen-macro-support" 1004 | version = "0.2.71" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e" 1007 | dependencies = [ 1008 | "proc-macro2", 1009 | "quote", 1010 | "syn", 1011 | "wasm-bindgen-backend", 1012 | "wasm-bindgen-shared", 1013 | ] 1014 | 1015 | [[package]] 1016 | name = "wasm-bindgen-shared" 1017 | version = "0.2.71" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1" 1020 | 1021 | [[package]] 1022 | name = "web-sys" 1023 | version = "0.3.48" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b" 1026 | dependencies = [ 1027 | "js-sys", 1028 | "wasm-bindgen", 1029 | ] 1030 | 1031 | [[package]] 1032 | name = "wepoll-sys" 1033 | version = "3.0.1" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" 1036 | dependencies = [ 1037 | "cc", 1038 | ] 1039 | 1040 | [[package]] 1041 | name = "winapi" 1042 | version = "0.3.9" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1045 | dependencies = [ 1046 | "winapi-i686-pc-windows-gnu", 1047 | "winapi-x86_64-pc-windows-gnu", 1048 | ] 1049 | 1050 | [[package]] 1051 | name = "winapi-i686-pc-windows-gnu" 1052 | version = "0.4.0" 1053 | source = "registry+https://github.com/rust-lang/crates.io-index" 1054 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1055 | 1056 | [[package]] 1057 | name = "winapi-util" 1058 | version = "0.1.5" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1061 | dependencies = [ 1062 | "winapi", 1063 | ] 1064 | 1065 | [[package]] 1066 | name = "winapi-x86_64-pc-windows-gnu" 1067 | version = "0.4.0" 1068 | source = "registry+https://github.com/rust-lang/crates.io-index" 1069 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1070 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.15" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "arc-swap" 16 | version = "1.2.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d4d7d63395147b81a9e570bcc6243aaf71c017bd666d4909cfef0085bdda8d73" 19 | 20 | [[package]] 21 | name = "async-channel" 22 | version = "1.6.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" 25 | dependencies = [ 26 | "concurrent-queue", 27 | "event-listener", 28 | "futures-core", 29 | ] 30 | 31 | [[package]] 32 | name = "async-executor" 33 | version = "1.4.0" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146" 36 | dependencies = [ 37 | "async-task", 38 | "concurrent-queue", 39 | "fastrand", 40 | "futures-lite", 41 | "once_cell", 42 | "vec-arena", 43 | ] 44 | 45 | [[package]] 46 | name = "async-global-executor" 47 | version = "2.0.2" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" 50 | dependencies = [ 51 | "async-channel", 52 | "async-executor", 53 | "async-io", 54 | "async-mutex", 55 | "blocking", 56 | "futures-lite", 57 | "num_cpus", 58 | "once_cell", 59 | ] 60 | 61 | [[package]] 62 | name = "async-io" 63 | version = "1.3.1" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "9315f8f07556761c3e48fec2e6b276004acf426e6dc068b2c2251854d65ee0fd" 66 | dependencies = [ 67 | "concurrent-queue", 68 | "fastrand", 69 | "futures-lite", 70 | "libc", 71 | "log", 72 | "nb-connect", 73 | "once_cell", 74 | "parking", 75 | "polling", 76 | "vec-arena", 77 | "waker-fn", 78 | "winapi", 79 | ] 80 | 81 | [[package]] 82 | name = "async-lock" 83 | version = "2.3.0" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "1996609732bde4a9988bc42125f55f2af5f3c36370e27c778d5191a4a1b63bfb" 86 | dependencies = [ 87 | "event-listener", 88 | ] 89 | 90 | [[package]] 91 | name = "async-mutex" 92 | version = "1.4.0" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" 95 | dependencies = [ 96 | "event-listener", 97 | ] 98 | 99 | [[package]] 100 | name = "async-std" 101 | version = "1.9.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "d9f06685bad74e0570f5213741bea82158279a4103d988e57bfada11ad230341" 104 | dependencies = [ 105 | "async-channel", 106 | "async-global-executor", 107 | "async-io", 108 | "async-lock", 109 | "crossbeam-utils 0.8.3", 110 | "futures-channel", 111 | "futures-core", 112 | "futures-io", 113 | "futures-lite", 114 | "gloo-timers", 115 | "kv-log-macro", 116 | "log", 117 | "memchr", 118 | "num_cpus", 119 | "once_cell", 120 | "pin-project-lite", 121 | "pin-utils", 122 | "slab", 123 | "wasm-bindgen-futures", 124 | ] 125 | 126 | [[package]] 127 | name = "async-stream" 128 | version = "0.3.2" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" 131 | dependencies = [ 132 | "async-stream-impl", 133 | "futures-core", 134 | ] 135 | 136 | [[package]] 137 | name = "async-stream-impl" 138 | version = "0.3.2" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" 141 | dependencies = [ 142 | "proc-macro2", 143 | "quote", 144 | "syn", 145 | ] 146 | 147 | [[package]] 148 | name = "async-task" 149 | version = "4.0.3" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" 152 | 153 | [[package]] 154 | name = "async-trait" 155 | version = "0.1.52" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" 158 | dependencies = [ 159 | "proc-macro2", 160 | "quote", 161 | "syn", 162 | ] 163 | 164 | [[package]] 165 | name = "async-tungstenite" 166 | version = "0.12.0" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "e00550829ef8e2c4115250d0ee43305649b0fa95f78a32ce5b07da0b73d95c5c" 169 | dependencies = [ 170 | "futures-io", 171 | "futures-util", 172 | "log", 173 | "pin-project-lite", 174 | "tungstenite", 175 | ] 176 | 177 | [[package]] 178 | name = "atomic-waker" 179 | version = "1.0.0" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" 182 | 183 | [[package]] 184 | name = "atty" 185 | version = "0.2.14" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 188 | dependencies = [ 189 | "hermit-abi", 190 | "libc", 191 | "winapi", 192 | ] 193 | 194 | [[package]] 195 | name = "autocfg" 196 | version = "1.0.1" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 199 | 200 | [[package]] 201 | name = "base64" 202 | version = "0.13.0" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 205 | 206 | [[package]] 207 | name = "bitflags" 208 | version = "1.3.2" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 211 | 212 | [[package]] 213 | name = "block-buffer" 214 | version = "0.9.0" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 217 | dependencies = [ 218 | "generic-array", 219 | ] 220 | 221 | [[package]] 222 | name = "block-buffer" 223 | version = "0.10.2" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" 226 | dependencies = [ 227 | "generic-array", 228 | ] 229 | 230 | [[package]] 231 | name = "blocking" 232 | version = "1.0.2" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" 235 | dependencies = [ 236 | "async-channel", 237 | "async-task", 238 | "atomic-waker", 239 | "fastrand", 240 | "futures-lite", 241 | "once_cell", 242 | ] 243 | 244 | [[package]] 245 | name = "bstr" 246 | version = "0.2.15" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" 249 | dependencies = [ 250 | "lazy_static", 251 | "memchr", 252 | "regex-automata", 253 | "serde", 254 | ] 255 | 256 | [[package]] 257 | name = "bumpalo" 258 | version = "3.6.1" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" 261 | 262 | [[package]] 263 | name = "byteorder" 264 | version = "1.4.3" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 267 | 268 | [[package]] 269 | name = "bytes" 270 | version = "1.1.0" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 273 | 274 | [[package]] 275 | name = "cache-padded" 276 | version = "1.1.1" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" 279 | 280 | [[package]] 281 | name = "cast" 282 | version = "0.2.7" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" 285 | dependencies = [ 286 | "rustc_version", 287 | ] 288 | 289 | [[package]] 290 | name = "cc" 291 | version = "1.0.73" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 294 | 295 | [[package]] 296 | name = "cfg-if" 297 | version = "0.1.10" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 300 | 301 | [[package]] 302 | name = "cfg-if" 303 | version = "1.0.0" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 306 | 307 | [[package]] 308 | name = "chrono" 309 | version = "0.4.19" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 312 | dependencies = [ 313 | "libc", 314 | "num-integer", 315 | "num-traits", 316 | "time", 317 | "winapi", 318 | ] 319 | 320 | [[package]] 321 | name = "clap" 322 | version = "2.34.0" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 325 | dependencies = [ 326 | "bitflags", 327 | "textwrap", 328 | "unicode-width", 329 | ] 330 | 331 | [[package]] 332 | name = "concurrent-queue" 333 | version = "1.2.2" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" 336 | dependencies = [ 337 | "cache-padded", 338 | ] 339 | 340 | [[package]] 341 | name = "console_error_panic_hook" 342 | version = "0.1.6" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211" 345 | dependencies = [ 346 | "cfg-if 0.1.10", 347 | "wasm-bindgen", 348 | ] 349 | 350 | [[package]] 351 | name = "cpuid-bool" 352 | version = "0.1.2" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" 355 | 356 | [[package]] 357 | name = "crc" 358 | version = "2.1.0" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" 361 | dependencies = [ 362 | "crc-catalog", 363 | ] 364 | 365 | [[package]] 366 | name = "crc-catalog" 367 | version = "1.1.1" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" 370 | 371 | [[package]] 372 | name = "criterion" 373 | version = "0.3.5" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" 376 | dependencies = [ 377 | "atty", 378 | "cast", 379 | "clap", 380 | "criterion-plot", 381 | "csv", 382 | "itertools", 383 | "lazy_static", 384 | "num-traits", 385 | "oorandom", 386 | "plotters", 387 | "rayon", 388 | "regex", 389 | "serde", 390 | "serde_cbor", 391 | "serde_derive", 392 | "serde_json", 393 | "tinytemplate", 394 | "walkdir", 395 | ] 396 | 397 | [[package]] 398 | name = "criterion-plot" 399 | version = "0.4.4" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" 402 | dependencies = [ 403 | "cast", 404 | "itertools", 405 | ] 406 | 407 | [[package]] 408 | name = "crossbeam-channel" 409 | version = "0.4.4" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" 412 | dependencies = [ 413 | "crossbeam-utils 0.7.2", 414 | "maybe-uninit", 415 | ] 416 | 417 | [[package]] 418 | name = "crossbeam-deque" 419 | version = "0.7.4" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" 422 | dependencies = [ 423 | "crossbeam-epoch", 424 | "crossbeam-utils 0.7.2", 425 | "maybe-uninit", 426 | ] 427 | 428 | [[package]] 429 | name = "crossbeam-epoch" 430 | version = "0.8.2" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" 433 | dependencies = [ 434 | "autocfg", 435 | "cfg-if 0.1.10", 436 | "crossbeam-utils 0.7.2", 437 | "lazy_static", 438 | "maybe-uninit", 439 | "memoffset 0.5.6", 440 | "scopeguard", 441 | ] 442 | 443 | [[package]] 444 | name = "crossbeam-utils" 445 | version = "0.7.2" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" 448 | dependencies = [ 449 | "autocfg", 450 | "cfg-if 0.1.10", 451 | "lazy_static", 452 | ] 453 | 454 | [[package]] 455 | name = "crossbeam-utils" 456 | version = "0.8.3" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" 459 | dependencies = [ 460 | "autocfg", 461 | "cfg-if 1.0.0", 462 | "lazy_static", 463 | ] 464 | 465 | [[package]] 466 | name = "crypto-common" 467 | version = "0.1.3" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" 470 | dependencies = [ 471 | "generic-array", 472 | "typenum", 473 | ] 474 | 475 | [[package]] 476 | name = "csv" 477 | version = "1.1.6" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" 480 | dependencies = [ 481 | "bstr", 482 | "csv-core", 483 | "itoa", 484 | "ryu", 485 | "serde", 486 | ] 487 | 488 | [[package]] 489 | name = "csv-core" 490 | version = "0.1.10" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" 493 | dependencies = [ 494 | "memchr", 495 | ] 496 | 497 | [[package]] 498 | name = "ctor" 499 | version = "0.1.19" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19" 502 | dependencies = [ 503 | "quote", 504 | "syn", 505 | ] 506 | 507 | [[package]] 508 | name = "digest" 509 | version = "0.9.0" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 512 | dependencies = [ 513 | "generic-array", 514 | ] 515 | 516 | [[package]] 517 | name = "digest" 518 | version = "0.10.3" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" 521 | dependencies = [ 522 | "block-buffer 0.10.2", 523 | "crypto-common", 524 | ] 525 | 526 | [[package]] 527 | name = "either" 528 | version = "1.6.1" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 531 | 532 | [[package]] 533 | name = "env_logger" 534 | version = "0.9.0" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" 537 | dependencies = [ 538 | "atty", 539 | "humantime", 540 | "log", 541 | "regex", 542 | "termcolor", 543 | ] 544 | 545 | [[package]] 546 | name = "event-listener" 547 | version = "2.5.1" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" 550 | 551 | [[package]] 552 | name = "fastrand" 553 | version = "1.4.0" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" 556 | dependencies = [ 557 | "instant", 558 | ] 559 | 560 | [[package]] 561 | name = "fnv" 562 | version = "1.0.7" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 565 | 566 | [[package]] 567 | name = "form_urlencoded" 568 | version = "1.0.1" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 571 | dependencies = [ 572 | "matches", 573 | "percent-encoding", 574 | ] 575 | 576 | [[package]] 577 | name = "futures" 578 | version = "0.3.13" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" 581 | dependencies = [ 582 | "futures-channel", 583 | "futures-core", 584 | "futures-executor", 585 | "futures-io", 586 | "futures-sink", 587 | "futures-task", 588 | "futures-util", 589 | ] 590 | 591 | [[package]] 592 | name = "futures-channel" 593 | version = "0.3.13" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" 596 | dependencies = [ 597 | "futures-core", 598 | "futures-sink", 599 | ] 600 | 601 | [[package]] 602 | name = "futures-core" 603 | version = "0.3.13" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" 606 | 607 | [[package]] 608 | name = "futures-executor" 609 | version = "0.3.13" 610 | source = "registry+https://github.com/rust-lang/crates.io-index" 611 | checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" 612 | dependencies = [ 613 | "futures-core", 614 | "futures-task", 615 | "futures-util", 616 | ] 617 | 618 | [[package]] 619 | name = "futures-io" 620 | version = "0.3.13" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" 623 | 624 | [[package]] 625 | name = "futures-lite" 626 | version = "1.11.3" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb" 629 | dependencies = [ 630 | "fastrand", 631 | "futures-core", 632 | "futures-io", 633 | "memchr", 634 | "parking", 635 | "pin-project-lite", 636 | "waker-fn", 637 | ] 638 | 639 | [[package]] 640 | name = "futures-macro" 641 | version = "0.3.13" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7" 644 | dependencies = [ 645 | "proc-macro-hack", 646 | "proc-macro2", 647 | "quote", 648 | "syn", 649 | ] 650 | 651 | [[package]] 652 | name = "futures-sink" 653 | version = "0.3.13" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3" 656 | 657 | [[package]] 658 | name = "futures-task" 659 | version = "0.3.13" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80" 662 | 663 | [[package]] 664 | name = "futures-util" 665 | version = "0.3.13" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" 668 | dependencies = [ 669 | "futures-channel", 670 | "futures-core", 671 | "futures-io", 672 | "futures-macro", 673 | "futures-sink", 674 | "futures-task", 675 | "memchr", 676 | "pin-project-lite", 677 | "pin-utils", 678 | "proc-macro-hack", 679 | "proc-macro-nested", 680 | "slab", 681 | ] 682 | 683 | [[package]] 684 | name = "generic-array" 685 | version = "0.14.4" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 688 | dependencies = [ 689 | "typenum", 690 | "version_check", 691 | ] 692 | 693 | [[package]] 694 | name = "getrandom" 695 | version = "0.2.2" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" 698 | dependencies = [ 699 | "cfg-if 1.0.0", 700 | "libc", 701 | "wasi", 702 | ] 703 | 704 | [[package]] 705 | name = "gloo-timers" 706 | version = "0.2.1" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" 709 | dependencies = [ 710 | "futures-channel", 711 | "futures-core", 712 | "js-sys", 713 | "wasm-bindgen", 714 | "web-sys", 715 | ] 716 | 717 | [[package]] 718 | name = "half" 719 | version = "1.8.2" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" 722 | 723 | [[package]] 724 | name = "hermit-abi" 725 | version = "0.1.18" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 728 | dependencies = [ 729 | "libc", 730 | ] 731 | 732 | [[package]] 733 | name = "hex" 734 | version = "0.4.3" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 737 | 738 | [[package]] 739 | name = "http" 740 | version = "0.2.3" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" 743 | dependencies = [ 744 | "bytes", 745 | "fnv", 746 | "itoa", 747 | ] 748 | 749 | [[package]] 750 | name = "httparse" 751 | version = "1.3.5" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691" 754 | 755 | [[package]] 756 | name = "humantime" 757 | version = "2.1.0" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 760 | 761 | [[package]] 762 | name = "idna" 763 | version = "0.2.2" 764 | source = "registry+https://github.com/rust-lang/crates.io-index" 765 | checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" 766 | dependencies = [ 767 | "matches", 768 | "unicode-bidi", 769 | "unicode-normalization", 770 | ] 771 | 772 | [[package]] 773 | name = "input_buffer" 774 | version = "0.4.0" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" 777 | dependencies = [ 778 | "bytes", 779 | ] 780 | 781 | [[package]] 782 | name = "instant" 783 | version = "0.1.9" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" 786 | dependencies = [ 787 | "cfg-if 1.0.0", 788 | ] 789 | 790 | [[package]] 791 | name = "ipnet" 792 | version = "2.3.1" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" 795 | 796 | [[package]] 797 | name = "itertools" 798 | version = "0.10.3" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 801 | dependencies = [ 802 | "either", 803 | ] 804 | 805 | [[package]] 806 | name = "itoa" 807 | version = "0.4.7" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" 810 | 811 | [[package]] 812 | name = "js-sys" 813 | version = "0.3.56" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" 816 | dependencies = [ 817 | "wasm-bindgen", 818 | ] 819 | 820 | [[package]] 821 | name = "kv-log-macro" 822 | version = "1.0.7" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" 825 | dependencies = [ 826 | "log", 827 | ] 828 | 829 | [[package]] 830 | name = "lazy_static" 831 | version = "1.4.0" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 834 | 835 | [[package]] 836 | name = "libc" 837 | version = "0.2.119" 838 | source = "registry+https://github.com/rust-lang/crates.io-index" 839 | checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" 840 | 841 | [[package]] 842 | name = "lock_api" 843 | version = "0.4.6" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" 846 | dependencies = [ 847 | "scopeguard", 848 | ] 849 | 850 | [[package]] 851 | name = "log" 852 | version = "0.4.14" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 855 | dependencies = [ 856 | "cfg-if 1.0.0", 857 | "value-bag", 858 | ] 859 | 860 | [[package]] 861 | name = "matches" 862 | version = "0.1.8" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 865 | 866 | [[package]] 867 | name = "maybe-uninit" 868 | version = "2.0.0" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 871 | 872 | [[package]] 873 | name = "md-5" 874 | version = "0.10.1" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" 877 | dependencies = [ 878 | "digest 0.10.3", 879 | ] 880 | 881 | [[package]] 882 | name = "memchr" 883 | version = "2.3.4" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 886 | 887 | [[package]] 888 | name = "memoffset" 889 | version = "0.5.6" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" 892 | dependencies = [ 893 | "autocfg", 894 | ] 895 | 896 | [[package]] 897 | name = "memoffset" 898 | version = "0.6.5" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 901 | dependencies = [ 902 | "autocfg", 903 | ] 904 | 905 | [[package]] 906 | name = "mio" 907 | version = "0.8.0" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" 910 | dependencies = [ 911 | "libc", 912 | "log", 913 | "miow", 914 | "ntapi", 915 | "winapi", 916 | ] 917 | 918 | [[package]] 919 | name = "miow" 920 | version = "0.3.7" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 923 | dependencies = [ 924 | "winapi", 925 | ] 926 | 927 | [[package]] 928 | name = "nb-connect" 929 | version = "1.0.3" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "670361df1bc2399ee1ff50406a0d422587dd3bb0da596e1978fe8e05dabddf4f" 932 | dependencies = [ 933 | "libc", 934 | "socket2 0.3.19", 935 | ] 936 | 937 | [[package]] 938 | name = "nix" 939 | version = "0.23.1" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" 942 | dependencies = [ 943 | "bitflags", 944 | "cc", 945 | "cfg-if 1.0.0", 946 | "libc", 947 | "memoffset 0.6.5", 948 | ] 949 | 950 | [[package]] 951 | name = "ntapi" 952 | version = "0.3.7" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" 955 | dependencies = [ 956 | "winapi", 957 | ] 958 | 959 | [[package]] 960 | name = "num-integer" 961 | version = "0.1.44" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 964 | dependencies = [ 965 | "autocfg", 966 | "num-traits", 967 | ] 968 | 969 | [[package]] 970 | name = "num-traits" 971 | version = "0.2.14" 972 | source = "registry+https://github.com/rust-lang/crates.io-index" 973 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 974 | dependencies = [ 975 | "autocfg", 976 | ] 977 | 978 | [[package]] 979 | name = "num_cpus" 980 | version = "1.13.0" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 983 | dependencies = [ 984 | "hermit-abi", 985 | "libc", 986 | ] 987 | 988 | [[package]] 989 | name = "once_cell" 990 | version = "1.7.2" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" 993 | 994 | [[package]] 995 | name = "oorandom" 996 | version = "11.1.3" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" 999 | 1000 | [[package]] 1001 | name = "opaque-debug" 1002 | version = "0.3.0" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 1005 | 1006 | [[package]] 1007 | name = "parking" 1008 | version = "2.0.0" 1009 | source = "registry+https://github.com/rust-lang/crates.io-index" 1010 | checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" 1011 | 1012 | [[package]] 1013 | name = "parking_lot" 1014 | version = "0.11.2" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 1017 | dependencies = [ 1018 | "instant", 1019 | "lock_api", 1020 | "parking_lot_core 0.8.5", 1021 | ] 1022 | 1023 | [[package]] 1024 | name = "parking_lot" 1025 | version = "0.12.0" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" 1028 | dependencies = [ 1029 | "lock_api", 1030 | "parking_lot_core 0.9.1", 1031 | ] 1032 | 1033 | [[package]] 1034 | name = "parking_lot_core" 1035 | version = "0.8.5" 1036 | source = "registry+https://github.com/rust-lang/crates.io-index" 1037 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 1038 | dependencies = [ 1039 | "cfg-if 1.0.0", 1040 | "instant", 1041 | "libc", 1042 | "redox_syscall", 1043 | "smallvec", 1044 | "winapi", 1045 | ] 1046 | 1047 | [[package]] 1048 | name = "parking_lot_core" 1049 | version = "0.9.1" 1050 | source = "registry+https://github.com/rust-lang/crates.io-index" 1051 | checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" 1052 | dependencies = [ 1053 | "cfg-if 1.0.0", 1054 | "libc", 1055 | "redox_syscall", 1056 | "smallvec", 1057 | "windows-sys", 1058 | ] 1059 | 1060 | [[package]] 1061 | name = "percent-encoding" 1062 | version = "2.1.0" 1063 | source = "registry+https://github.com/rust-lang/crates.io-index" 1064 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1065 | 1066 | [[package]] 1067 | name = "pin-project-lite" 1068 | version = "0.2.6" 1069 | source = "registry+https://github.com/rust-lang/crates.io-index" 1070 | checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" 1071 | 1072 | [[package]] 1073 | name = "pin-utils" 1074 | version = "0.1.0" 1075 | source = "registry+https://github.com/rust-lang/crates.io-index" 1076 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1077 | 1078 | [[package]] 1079 | name = "plotters" 1080 | version = "0.3.1" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" 1083 | dependencies = [ 1084 | "num-traits", 1085 | "plotters-backend", 1086 | "plotters-svg", 1087 | "wasm-bindgen", 1088 | "web-sys", 1089 | ] 1090 | 1091 | [[package]] 1092 | name = "plotters-backend" 1093 | version = "0.3.2" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" 1096 | 1097 | [[package]] 1098 | name = "plotters-svg" 1099 | version = "0.3.1" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" 1102 | dependencies = [ 1103 | "plotters-backend", 1104 | ] 1105 | 1106 | [[package]] 1107 | name = "polling" 1108 | version = "2.0.2" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" 1111 | dependencies = [ 1112 | "cfg-if 0.1.10", 1113 | "libc", 1114 | "log", 1115 | "wepoll-sys", 1116 | "winapi", 1117 | ] 1118 | 1119 | [[package]] 1120 | name = "ppv-lite86" 1121 | version = "0.2.10" 1122 | source = "registry+https://github.com/rust-lang/crates.io-index" 1123 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 1124 | 1125 | [[package]] 1126 | name = "proc-macro-hack" 1127 | version = "0.5.19" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 1130 | 1131 | [[package]] 1132 | name = "proc-macro-nested" 1133 | version = "0.1.7" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" 1136 | 1137 | [[package]] 1138 | name = "proc-macro2" 1139 | version = "1.0.24" 1140 | source = "registry+https://github.com/rust-lang/crates.io-index" 1141 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 1142 | dependencies = [ 1143 | "unicode-xid", 1144 | ] 1145 | 1146 | [[package]] 1147 | name = "quote" 1148 | version = "1.0.9" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 1151 | dependencies = [ 1152 | "proc-macro2", 1153 | ] 1154 | 1155 | [[package]] 1156 | name = "rand" 1157 | version = "0.8.5" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1160 | dependencies = [ 1161 | "libc", 1162 | "rand_chacha", 1163 | "rand_core", 1164 | ] 1165 | 1166 | [[package]] 1167 | name = "rand_chacha" 1168 | version = "0.3.0" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" 1171 | dependencies = [ 1172 | "ppv-lite86", 1173 | "rand_core", 1174 | ] 1175 | 1176 | [[package]] 1177 | name = "rand_core" 1178 | version = "0.6.2" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" 1181 | dependencies = [ 1182 | "getrandom", 1183 | ] 1184 | 1185 | [[package]] 1186 | name = "rayon" 1187 | version = "1.4.1" 1188 | source = "registry+https://github.com/rust-lang/crates.io-index" 1189 | checksum = "dcf6960dc9a5b4ee8d3e4c5787b4a112a8818e0290a42ff664ad60692fdf2032" 1190 | dependencies = [ 1191 | "autocfg", 1192 | "crossbeam-deque", 1193 | "either", 1194 | "rayon-core", 1195 | ] 1196 | 1197 | [[package]] 1198 | name = "rayon-core" 1199 | version = "1.8.1" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf" 1202 | dependencies = [ 1203 | "crossbeam-channel", 1204 | "crossbeam-deque", 1205 | "crossbeam-utils 0.7.2", 1206 | "lazy_static", 1207 | "num_cpus", 1208 | ] 1209 | 1210 | [[package]] 1211 | name = "redox_syscall" 1212 | version = "0.2.11" 1213 | source = "registry+https://github.com/rust-lang/crates.io-index" 1214 | checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" 1215 | dependencies = [ 1216 | "bitflags", 1217 | ] 1218 | 1219 | [[package]] 1220 | name = "regex" 1221 | version = "1.4.6" 1222 | source = "registry+https://github.com/rust-lang/crates.io-index" 1223 | checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" 1224 | dependencies = [ 1225 | "aho-corasick", 1226 | "memchr", 1227 | "regex-syntax", 1228 | ] 1229 | 1230 | [[package]] 1231 | name = "regex-automata" 1232 | version = "0.1.10" 1233 | source = "registry+https://github.com/rust-lang/crates.io-index" 1234 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1235 | 1236 | [[package]] 1237 | name = "regex-syntax" 1238 | version = "0.6.25" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 1241 | 1242 | [[package]] 1243 | name = "ring" 1244 | version = "0.16.20" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1247 | dependencies = [ 1248 | "cc", 1249 | "libc", 1250 | "once_cell", 1251 | "spin", 1252 | "untrusted", 1253 | "web-sys", 1254 | "winapi", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "rustc_version" 1259 | version = "0.4.0" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1262 | dependencies = [ 1263 | "semver", 1264 | ] 1265 | 1266 | [[package]] 1267 | name = "ryu" 1268 | version = "1.0.5" 1269 | source = "registry+https://github.com/rust-lang/crates.io-index" 1270 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 1271 | 1272 | [[package]] 1273 | name = "same-file" 1274 | version = "1.0.6" 1275 | source = "registry+https://github.com/rust-lang/crates.io-index" 1276 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1277 | dependencies = [ 1278 | "winapi-util", 1279 | ] 1280 | 1281 | [[package]] 1282 | name = "scoped-tls" 1283 | version = "1.0.0" 1284 | source = "registry+https://github.com/rust-lang/crates.io-index" 1285 | checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" 1286 | 1287 | [[package]] 1288 | name = "scopeguard" 1289 | version = "1.1.0" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1292 | 1293 | [[package]] 1294 | name = "semver" 1295 | version = "1.0.6" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" 1298 | 1299 | [[package]] 1300 | name = "serde" 1301 | version = "1.0.124" 1302 | source = "registry+https://github.com/rust-lang/crates.io-index" 1303 | checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" 1304 | dependencies = [ 1305 | "serde_derive", 1306 | ] 1307 | 1308 | [[package]] 1309 | name = "serde-json-wasm" 1310 | version = "0.3.1" 1311 | source = "registry+https://github.com/rust-lang/crates.io-index" 1312 | checksum = "50eef3672ec8fa45f3457fd423ba131117786784a895548021976117c1ded449" 1313 | dependencies = [ 1314 | "serde", 1315 | ] 1316 | 1317 | [[package]] 1318 | name = "serde_cbor" 1319 | version = "0.11.2" 1320 | source = "registry+https://github.com/rust-lang/crates.io-index" 1321 | checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" 1322 | dependencies = [ 1323 | "half", 1324 | "serde", 1325 | ] 1326 | 1327 | [[package]] 1328 | name = "serde_derive" 1329 | version = "1.0.124" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" 1332 | dependencies = [ 1333 | "proc-macro2", 1334 | "quote", 1335 | "syn", 1336 | ] 1337 | 1338 | [[package]] 1339 | name = "serde_json" 1340 | version = "1.0.64" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" 1343 | dependencies = [ 1344 | "itoa", 1345 | "ryu", 1346 | "serde", 1347 | ] 1348 | 1349 | [[package]] 1350 | name = "sha-1" 1351 | version = "0.9.4" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" 1354 | dependencies = [ 1355 | "block-buffer 0.9.0", 1356 | "cfg-if 1.0.0", 1357 | "cpuid-bool", 1358 | "digest 0.9.0", 1359 | "opaque-debug", 1360 | ] 1361 | 1362 | [[package]] 1363 | name = "shared-protocol" 1364 | version = "0.1.0" 1365 | dependencies = [ 1366 | "serde", 1367 | ] 1368 | 1369 | [[package]] 1370 | name = "signal-hook-registry" 1371 | version = "1.4.0" 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" 1373 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1374 | dependencies = [ 1375 | "libc", 1376 | ] 1377 | 1378 | [[package]] 1379 | name = "signalling-server" 1380 | version = "0.1.0" 1381 | dependencies = [ 1382 | "async-std", 1383 | "async-tungstenite", 1384 | "futures", 1385 | "log", 1386 | "rand", 1387 | "serde", 1388 | "serde_json", 1389 | "shared-protocol", 1390 | "simplelog", 1391 | ] 1392 | 1393 | [[package]] 1394 | name = "simplelog" 1395 | version = "0.8.0" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "2b2736f58087298a448859961d3f4a0850b832e72619d75adc69da7993c2cd3c" 1398 | dependencies = [ 1399 | "chrono", 1400 | "log", 1401 | "termcolor", 1402 | ] 1403 | 1404 | [[package]] 1405 | name = "slab" 1406 | version = "0.4.2" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1409 | 1410 | [[package]] 1411 | name = "smallvec" 1412 | version = "1.8.0" 1413 | source = "registry+https://github.com/rust-lang/crates.io-index" 1414 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 1415 | 1416 | [[package]] 1417 | name = "socket2" 1418 | version = "0.3.19" 1419 | source = "registry+https://github.com/rust-lang/crates.io-index" 1420 | checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" 1421 | dependencies = [ 1422 | "cfg-if 1.0.0", 1423 | "libc", 1424 | "winapi", 1425 | ] 1426 | 1427 | [[package]] 1428 | name = "socket2" 1429 | version = "0.4.4" 1430 | source = "registry+https://github.com/rust-lang/crates.io-index" 1431 | checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" 1432 | dependencies = [ 1433 | "libc", 1434 | "winapi", 1435 | ] 1436 | 1437 | [[package]] 1438 | name = "spin" 1439 | version = "0.5.2" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1442 | 1443 | [[package]] 1444 | name = "stun" 1445 | version = "0.4.2" 1446 | source = "registry+https://github.com/rust-lang/crates.io-index" 1447 | checksum = "c7c5e998a0b2bc5fe66e50dff28310f54210155f4d943a6c2b80bbb52fbaf3b0" 1448 | dependencies = [ 1449 | "base64", 1450 | "crc", 1451 | "lazy_static", 1452 | "md-5", 1453 | "rand", 1454 | "ring", 1455 | "subtle", 1456 | "thiserror", 1457 | "tokio", 1458 | "url", 1459 | "webrtc-util", 1460 | ] 1461 | 1462 | [[package]] 1463 | name = "subtle" 1464 | version = "2.4.1" 1465 | source = "registry+https://github.com/rust-lang/crates.io-index" 1466 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1467 | 1468 | [[package]] 1469 | name = "syn" 1470 | version = "1.0.67" 1471 | source = "registry+https://github.com/rust-lang/crates.io-index" 1472 | checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" 1473 | dependencies = [ 1474 | "proc-macro2", 1475 | "quote", 1476 | "unicode-xid", 1477 | ] 1478 | 1479 | [[package]] 1480 | name = "termcolor" 1481 | version = "1.1.2" 1482 | source = "registry+https://github.com/rust-lang/crates.io-index" 1483 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 1484 | dependencies = [ 1485 | "winapi-util", 1486 | ] 1487 | 1488 | [[package]] 1489 | name = "textwrap" 1490 | version = "0.11.0" 1491 | source = "registry+https://github.com/rust-lang/crates.io-index" 1492 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1493 | dependencies = [ 1494 | "unicode-width", 1495 | ] 1496 | 1497 | [[package]] 1498 | name = "thiserror" 1499 | version = "1.0.30" 1500 | source = "registry+https://github.com/rust-lang/crates.io-index" 1501 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 1502 | dependencies = [ 1503 | "thiserror-impl", 1504 | ] 1505 | 1506 | [[package]] 1507 | name = "thiserror-impl" 1508 | version = "1.0.30" 1509 | source = "registry+https://github.com/rust-lang/crates.io-index" 1510 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 1511 | dependencies = [ 1512 | "proc-macro2", 1513 | "quote", 1514 | "syn", 1515 | ] 1516 | 1517 | [[package]] 1518 | name = "time" 1519 | version = "0.1.43" 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" 1521 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 1522 | dependencies = [ 1523 | "libc", 1524 | "winapi", 1525 | ] 1526 | 1527 | [[package]] 1528 | name = "tinytemplate" 1529 | version = "1.2.1" 1530 | source = "registry+https://github.com/rust-lang/crates.io-index" 1531 | checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" 1532 | dependencies = [ 1533 | "serde", 1534 | "serde_json", 1535 | ] 1536 | 1537 | [[package]] 1538 | name = "tinyvec" 1539 | version = "1.1.1" 1540 | source = "registry+https://github.com/rust-lang/crates.io-index" 1541 | checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" 1542 | dependencies = [ 1543 | "tinyvec_macros", 1544 | ] 1545 | 1546 | [[package]] 1547 | name = "tinyvec_macros" 1548 | version = "0.1.0" 1549 | source = "registry+https://github.com/rust-lang/crates.io-index" 1550 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1551 | 1552 | [[package]] 1553 | name = "tokio" 1554 | version = "1.17.0" 1555 | source = "registry+https://github.com/rust-lang/crates.io-index" 1556 | checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" 1557 | dependencies = [ 1558 | "bytes", 1559 | "libc", 1560 | "memchr", 1561 | "mio", 1562 | "num_cpus", 1563 | "once_cell", 1564 | "parking_lot 0.12.0", 1565 | "pin-project-lite", 1566 | "signal-hook-registry", 1567 | "socket2 0.4.4", 1568 | "tokio-macros", 1569 | "winapi", 1570 | ] 1571 | 1572 | [[package]] 1573 | name = "tokio-macros" 1574 | version = "1.7.0" 1575 | source = "registry+https://github.com/rust-lang/crates.io-index" 1576 | checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" 1577 | dependencies = [ 1578 | "proc-macro2", 1579 | "quote", 1580 | "syn", 1581 | ] 1582 | 1583 | [[package]] 1584 | name = "tokio-stream" 1585 | version = "0.1.8" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" 1588 | dependencies = [ 1589 | "futures-core", 1590 | "pin-project-lite", 1591 | "tokio", 1592 | ] 1593 | 1594 | [[package]] 1595 | name = "tokio-test" 1596 | version = "0.4.2" 1597 | source = "registry+https://github.com/rust-lang/crates.io-index" 1598 | checksum = "53474327ae5e166530d17f2d956afcb4f8a004de581b3cae10f12006bc8163e3" 1599 | dependencies = [ 1600 | "async-stream", 1601 | "bytes", 1602 | "futures-core", 1603 | "tokio", 1604 | "tokio-stream", 1605 | ] 1606 | 1607 | [[package]] 1608 | name = "tungstenite" 1609 | version = "0.12.0" 1610 | source = "registry+https://github.com/rust-lang/crates.io-index" 1611 | checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24" 1612 | dependencies = [ 1613 | "base64", 1614 | "byteorder", 1615 | "bytes", 1616 | "http", 1617 | "httparse", 1618 | "input_buffer", 1619 | "log", 1620 | "rand", 1621 | "sha-1", 1622 | "url", 1623 | "utf-8", 1624 | ] 1625 | 1626 | [[package]] 1627 | name = "turn" 1628 | version = "0.5.4" 1629 | source = "registry+https://github.com/rust-lang/crates.io-index" 1630 | checksum = "82674a80a4754ca9f6f5e132698ee3060ff9d3ef8cd690d66589d0f318b71670" 1631 | dependencies = [ 1632 | "async-trait", 1633 | "base64", 1634 | "log", 1635 | "md-5", 1636 | "rand", 1637 | "ring", 1638 | "stun", 1639 | "thiserror", 1640 | "tokio", 1641 | "webrtc-util", 1642 | ] 1643 | 1644 | [[package]] 1645 | name = "turn-server" 1646 | version = "0.1.0" 1647 | dependencies = [ 1648 | "async-trait", 1649 | "base64", 1650 | "chrono", 1651 | "criterion", 1652 | "env_logger", 1653 | "hex", 1654 | "log", 1655 | "md-5", 1656 | "rand", 1657 | "ring", 1658 | "stun", 1659 | "thiserror", 1660 | "tokio", 1661 | "tokio-test", 1662 | "turn", 1663 | "webrtc-util", 1664 | ] 1665 | 1666 | [[package]] 1667 | name = "typenum" 1668 | version = "1.15.0" 1669 | source = "registry+https://github.com/rust-lang/crates.io-index" 1670 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 1671 | 1672 | [[package]] 1673 | name = "unicode-bidi" 1674 | version = "0.3.4" 1675 | source = "registry+https://github.com/rust-lang/crates.io-index" 1676 | checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 1677 | dependencies = [ 1678 | "matches", 1679 | ] 1680 | 1681 | [[package]] 1682 | name = "unicode-normalization" 1683 | version = "0.1.17" 1684 | source = "registry+https://github.com/rust-lang/crates.io-index" 1685 | checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" 1686 | dependencies = [ 1687 | "tinyvec", 1688 | ] 1689 | 1690 | [[package]] 1691 | name = "unicode-width" 1692 | version = "0.1.9" 1693 | source = "registry+https://github.com/rust-lang/crates.io-index" 1694 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 1695 | 1696 | [[package]] 1697 | name = "unicode-xid" 1698 | version = "0.2.1" 1699 | source = "registry+https://github.com/rust-lang/crates.io-index" 1700 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 1701 | 1702 | [[package]] 1703 | name = "untrusted" 1704 | version = "0.7.1" 1705 | source = "registry+https://github.com/rust-lang/crates.io-index" 1706 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1707 | 1708 | [[package]] 1709 | name = "url" 1710 | version = "2.2.2" 1711 | source = "registry+https://github.com/rust-lang/crates.io-index" 1712 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 1713 | dependencies = [ 1714 | "form_urlencoded", 1715 | "idna", 1716 | "matches", 1717 | "percent-encoding", 1718 | ] 1719 | 1720 | [[package]] 1721 | name = "utf-8" 1722 | version = "0.7.5" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" 1725 | 1726 | [[package]] 1727 | name = "value-bag" 1728 | version = "1.0.0-alpha.6" 1729 | source = "registry+https://github.com/rust-lang/crates.io-index" 1730 | checksum = "6b676010e055c99033117c2343b33a40a30b91fecd6c49055ac9cd2d6c305ab1" 1731 | dependencies = [ 1732 | "ctor", 1733 | ] 1734 | 1735 | [[package]] 1736 | name = "vec-arena" 1737 | version = "1.0.0" 1738 | source = "registry+https://github.com/rust-lang/crates.io-index" 1739 | checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" 1740 | 1741 | [[package]] 1742 | name = "version_check" 1743 | version = "0.9.2" 1744 | source = "registry+https://github.com/rust-lang/crates.io-index" 1745 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" 1746 | 1747 | [[package]] 1748 | name = "waker-fn" 1749 | version = "1.1.0" 1750 | source = "registry+https://github.com/rust-lang/crates.io-index" 1751 | checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" 1752 | 1753 | [[package]] 1754 | name = "walkdir" 1755 | version = "2.3.2" 1756 | source = "registry+https://github.com/rust-lang/crates.io-index" 1757 | checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" 1758 | dependencies = [ 1759 | "same-file", 1760 | "winapi", 1761 | "winapi-util", 1762 | ] 1763 | 1764 | [[package]] 1765 | name = "wasi" 1766 | version = "0.10.2+wasi-snapshot-preview1" 1767 | source = "registry+https://github.com/rust-lang/crates.io-index" 1768 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1769 | 1770 | [[package]] 1771 | name = "wasm-bindgen" 1772 | version = "0.2.79" 1773 | source = "registry+https://github.com/rust-lang/crates.io-index" 1774 | checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" 1775 | dependencies = [ 1776 | "cfg-if 1.0.0", 1777 | "serde", 1778 | "serde_json", 1779 | "wasm-bindgen-macro", 1780 | ] 1781 | 1782 | [[package]] 1783 | name = "wasm-bindgen-backend" 1784 | version = "0.2.79" 1785 | source = "registry+https://github.com/rust-lang/crates.io-index" 1786 | checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" 1787 | dependencies = [ 1788 | "bumpalo", 1789 | "lazy_static", 1790 | "log", 1791 | "proc-macro2", 1792 | "quote", 1793 | "syn", 1794 | "wasm-bindgen-shared", 1795 | ] 1796 | 1797 | [[package]] 1798 | name = "wasm-bindgen-futures" 1799 | version = "0.4.21" 1800 | source = "registry+https://github.com/rust-lang/crates.io-index" 1801 | checksum = "8e67a5806118af01f0d9045915676b22aaebecf4178ae7021bc171dab0b897ab" 1802 | dependencies = [ 1803 | "cfg-if 1.0.0", 1804 | "js-sys", 1805 | "wasm-bindgen", 1806 | "web-sys", 1807 | ] 1808 | 1809 | [[package]] 1810 | name = "wasm-bindgen-macro" 1811 | version = "0.2.79" 1812 | source = "registry+https://github.com/rust-lang/crates.io-index" 1813 | checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" 1814 | dependencies = [ 1815 | "quote", 1816 | "wasm-bindgen-macro-support", 1817 | ] 1818 | 1819 | [[package]] 1820 | name = "wasm-bindgen-macro-support" 1821 | version = "0.2.79" 1822 | source = "registry+https://github.com/rust-lang/crates.io-index" 1823 | checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" 1824 | dependencies = [ 1825 | "proc-macro2", 1826 | "quote", 1827 | "syn", 1828 | "wasm-bindgen-backend", 1829 | "wasm-bindgen-shared", 1830 | ] 1831 | 1832 | [[package]] 1833 | name = "wasm-bindgen-shared" 1834 | version = "0.2.79" 1835 | source = "registry+https://github.com/rust-lang/crates.io-index" 1836 | checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" 1837 | 1838 | [[package]] 1839 | name = "wasm-bindgen-test" 1840 | version = "0.3.21" 1841 | source = "registry+https://github.com/rust-lang/crates.io-index" 1842 | checksum = "2ea9e4f0050d5498a160e6b9d278a9699598e445b51dacd05598da55114c801a" 1843 | dependencies = [ 1844 | "console_error_panic_hook", 1845 | "js-sys", 1846 | "scoped-tls", 1847 | "wasm-bindgen", 1848 | "wasm-bindgen-futures", 1849 | "wasm-bindgen-test-macro", 1850 | ] 1851 | 1852 | [[package]] 1853 | name = "wasm-bindgen-test-macro" 1854 | version = "0.3.21" 1855 | source = "registry+https://github.com/rust-lang/crates.io-index" 1856 | checksum = "43f40402f495d92df6cdd0d329e7cc2580c8f99bcd74faff0e468923a764b7d4" 1857 | dependencies = [ 1858 | "proc-macro2", 1859 | "quote", 1860 | ] 1861 | 1862 | [[package]] 1863 | name = "wasm-logger" 1864 | version = "0.2.0" 1865 | source = "registry+https://github.com/rust-lang/crates.io-index" 1866 | checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718" 1867 | dependencies = [ 1868 | "log", 1869 | "wasm-bindgen", 1870 | "web-sys", 1871 | ] 1872 | 1873 | [[package]] 1874 | name = "wasm_client" 1875 | version = "0.1.0" 1876 | dependencies = [ 1877 | "arc-swap", 1878 | "async-std", 1879 | "console_error_panic_hook", 1880 | "js-sys", 1881 | "log", 1882 | "serde", 1883 | "serde-json-wasm", 1884 | "shared-protocol", 1885 | "wasm-bindgen", 1886 | "wasm-bindgen-futures", 1887 | "wasm-bindgen-test", 1888 | "wasm-logger", 1889 | "web-sys", 1890 | ] 1891 | 1892 | [[package]] 1893 | name = "web-sys" 1894 | version = "0.3.56" 1895 | source = "registry+https://github.com/rust-lang/crates.io-index" 1896 | checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" 1897 | dependencies = [ 1898 | "js-sys", 1899 | "wasm-bindgen", 1900 | ] 1901 | 1902 | [[package]] 1903 | name = "webrtc-util" 1904 | version = "0.5.3" 1905 | source = "registry+https://github.com/rust-lang/crates.io-index" 1906 | checksum = "60b69bdea720881eddee50bd969be052ed95f04ccc5a6f684495131afb87e31c" 1907 | dependencies = [ 1908 | "async-trait", 1909 | "bitflags", 1910 | "bytes", 1911 | "cc", 1912 | "ipnet", 1913 | "lazy_static", 1914 | "libc", 1915 | "log", 1916 | "nix", 1917 | "parking_lot 0.11.2", 1918 | "rand", 1919 | "thiserror", 1920 | "tokio", 1921 | "winapi", 1922 | ] 1923 | 1924 | [[package]] 1925 | name = "wepoll-sys" 1926 | version = "3.0.1" 1927 | source = "registry+https://github.com/rust-lang/crates.io-index" 1928 | checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" 1929 | dependencies = [ 1930 | "cc", 1931 | ] 1932 | 1933 | [[package]] 1934 | name = "winapi" 1935 | version = "0.3.9" 1936 | source = "registry+https://github.com/rust-lang/crates.io-index" 1937 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1938 | dependencies = [ 1939 | "winapi-i686-pc-windows-gnu", 1940 | "winapi-x86_64-pc-windows-gnu", 1941 | ] 1942 | 1943 | [[package]] 1944 | name = "winapi-i686-pc-windows-gnu" 1945 | version = "0.4.0" 1946 | source = "registry+https://github.com/rust-lang/crates.io-index" 1947 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1948 | 1949 | [[package]] 1950 | name = "winapi-util" 1951 | version = "0.1.5" 1952 | source = "registry+https://github.com/rust-lang/crates.io-index" 1953 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1954 | dependencies = [ 1955 | "winapi", 1956 | ] 1957 | 1958 | [[package]] 1959 | name = "winapi-x86_64-pc-windows-gnu" 1960 | version = "0.4.0" 1961 | source = "registry+https://github.com/rust-lang/crates.io-index" 1962 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1963 | 1964 | [[package]] 1965 | name = "windows-sys" 1966 | version = "0.32.0" 1967 | source = "registry+https://github.com/rust-lang/crates.io-index" 1968 | checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" 1969 | dependencies = [ 1970 | "windows_aarch64_msvc", 1971 | "windows_i686_gnu", 1972 | "windows_i686_msvc", 1973 | "windows_x86_64_gnu", 1974 | "windows_x86_64_msvc", 1975 | ] 1976 | 1977 | [[package]] 1978 | name = "windows_aarch64_msvc" 1979 | version = "0.32.0" 1980 | source = "registry+https://github.com/rust-lang/crates.io-index" 1981 | checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" 1982 | 1983 | [[package]] 1984 | name = "windows_i686_gnu" 1985 | version = "0.32.0" 1986 | source = "registry+https://github.com/rust-lang/crates.io-index" 1987 | checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" 1988 | 1989 | [[package]] 1990 | name = "windows_i686_msvc" 1991 | version = "0.32.0" 1992 | source = "registry+https://github.com/rust-lang/crates.io-index" 1993 | checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" 1994 | 1995 | [[package]] 1996 | name = "windows_x86_64_gnu" 1997 | version = "0.32.0" 1998 | source = "registry+https://github.com/rust-lang/crates.io-index" 1999 | checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" 2000 | 2001 | [[package]] 2002 | name = "windows_x86_64_msvc" 2003 | version = "0.32.0" 2004 | source = "registry+https://github.com/rust-lang/crates.io-index" 2005 | checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" 2006 | --------------------------------------------------------------------------------