├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── api_user.rs ├── endpoint.rs ├── pubsubclient.rs └── router.rs └── src ├── client.rs ├── error.rs ├── lib.rs ├── messages ├── mod.rs └── types │ ├── error.rs │ ├── mod.rs │ ├── options.rs │ ├── roles.rs │ └── value.rs ├── router ├── handshake.rs ├── messaging.rs ├── mod.rs ├── pubsub │ ├── mod.rs │ └── patterns.rs └── rpc │ ├── mod.rs │ └── patterns.rs └── utils.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wamp" 3 | version = "0.1.0" 4 | authors = ["Daniel Yule "] 5 | license = "MIT" 6 | homepage = "https://github.com/dyule/wamp-rs" 7 | repository = "https://github.com/dyule/wamp-rs" 8 | description = "A WAMP client and router implenting the basic WAMP profile" 9 | keywords = ["rpc", "pubsub", "wamp"] 10 | 11 | [lib] 12 | name = "wamp" 13 | path = "src/lib.rs" 14 | 15 | [dependencies] 16 | serde = "1.0" 17 | serde_json = "1.0" 18 | serde_derive = "1.0" 19 | url = "1.7" 20 | log = "0.4" 21 | ws = "0.7" 22 | rmp = "0.8" 23 | rmp-serde = "0.13" 24 | rand = "0.5.0-pre.1" 25 | eventual = "0.1.7" 26 | itertools = "0.7" 27 | 28 | 29 | [dev-dependencies] 30 | env_logger = "0.5" 31 | 32 | [features] 33 | default-features = [] 34 | ssl = ["ws/ssl"] 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Daniel Yule 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WAMP-RS 2 | ======= 3 | 4 | WAMP-RS is a Rust implementation of the 5 | [Web Application Messaging Protcol (WAMP)](http://wamp-proto.org/). 6 | 7 | At present the entire Basic Profile is supported, as well as pattern based subscriptions and registrations from the Advanced Profile. 8 | 9 | There is currently no support for secure connections. 10 | 11 | For instructions on how to use, please see the [examples](examples) directory. 12 | 13 | To include in your project, place the following in your `Cargo.toml` 14 | 15 | ```toml 16 | [dependencies] 17 | wamp = "0.1" 18 | ``` 19 | 20 | WAMP-RS uses [serde-rs](https://github.com/serde-rs/serde), which requires Rust 1.15 or greater. 21 | -------------------------------------------------------------------------------- /examples/api_user.rs: -------------------------------------------------------------------------------- 1 | extern crate eventual; 2 | extern crate wamp; 3 | use eventual::Async; 4 | use std::io; 5 | use wamp::client::{Client, Connection}; 6 | use wamp::{ArgList, Value, URI}; 7 | 8 | #[macro_use] 9 | extern crate log; 10 | extern crate env_logger; 11 | 12 | enum Command { 13 | Add, 14 | Echo, 15 | Help, 16 | Quit, 17 | NoOp, 18 | Invalid(String), 19 | } 20 | 21 | fn print_prompt() { 22 | println!("Enter a command (or type \"help\")"); 23 | } 24 | 25 | fn get_input_from_user() -> String { 26 | let mut input = String::new(); 27 | io::stdin().read_line(&mut input).unwrap(); 28 | input 29 | } 30 | 31 | fn process_input(input: &str) -> (Command, Vec) { 32 | let mut i_iter = input.splitn(2, ' '); 33 | let command = match i_iter.next() { 34 | Some(command) => command.trim().to_lowercase(), 35 | None => return (Command::NoOp, Vec::new()), 36 | }; 37 | let command = match command.as_str() { 38 | "add" => Command::Add, 39 | "echo" => Command::Echo, 40 | "help" => Command::Help, 41 | "quit" => Command::Quit, 42 | "" => Command::NoOp, 43 | x => Command::Invalid(x.to_string()), 44 | }; 45 | let args = match i_iter.next() { 46 | Some(args_string) => args_string 47 | .split(',') 48 | .map(|s| s.trim().to_string()) 49 | .collect(), 50 | None => Vec::new(), 51 | }; 52 | (command, args) 53 | } 54 | 55 | fn add(client: &mut Client, args: &[String]) { 56 | if args.len() > 2 { 57 | println!("Too many arguments to add. Ignoring"); 58 | } else if args.len() < 2 { 59 | println!("Please pass two numbers for adding"); 60 | return; 61 | } 62 | 63 | let a = match str::parse::(&args[0]) { 64 | Ok(i) => i, 65 | Err(_) => { 66 | println!("Please enter an integer (got {})", args[0]); 67 | return; 68 | } 69 | }; 70 | let b = match str::parse::(&args[1]) { 71 | Ok(i) => i, 72 | Err(_) => { 73 | println!("Please enter an integer (got {})", args[0]); 74 | return; 75 | } 76 | }; 77 | match client 78 | .call( 79 | URI::new("ca.test.add"), 80 | Some(vec![Value::Integer(a), Value::Integer(b)]), 81 | None, 82 | ) 83 | .unwrap() 84 | .await() 85 | { 86 | Ok((args, _)) => { 87 | println!("Result: {}", args.get_int(0).unwrap().unwrap()); 88 | } 89 | Err(e) => match e.take() { 90 | Some(e) => { 91 | println!("Error: {:?}", e); 92 | } 93 | None => { 94 | println!("Aborted"); 95 | } 96 | }, 97 | } 98 | } 99 | 100 | fn echo(client: &mut Client, args: Vec) { 101 | let args = args.into_iter().map(|arg| Value::String(arg)).collect(); 102 | let result = client 103 | .call(URI::new("ca.test.echo"), Some(args), None) 104 | .unwrap() 105 | .await(); 106 | println!("Result: {:?}", result); 107 | } 108 | 109 | fn help() { 110 | println!("This client expects the 'endpoint' and 'router' examples to also be running",); 111 | println!("The following commands are supported:"); 112 | println!(" add , "); 113 | println!(" Adds the two numbers given by and ",); 114 | println!(" echo *"); 115 | println!(" Echoes any arguments passed back"); 116 | println!(" quit"); 117 | println!(" Sends a goodbye message and quits the program"); 118 | } 119 | 120 | fn event_loop(mut client: Client) { 121 | loop { 122 | print_prompt(); 123 | let input = get_input_from_user(); 124 | let (command, args) = process_input(&input); 125 | match command { 126 | Command::Add => add(&mut client, &args), 127 | Command::Echo => echo(&mut client, args), 128 | Command::Help => help(), 129 | Command::Quit => break, 130 | Command::NoOp => {} 131 | Command::Invalid(bad_command) => print!("Invalid command: {}", bad_command), 132 | } 133 | } 134 | client.shutdown().unwrap().await().unwrap(); 135 | } 136 | 137 | fn main() { 138 | env_logger::init(); 139 | let connection = Connection::new("ws://127.0.0.1:8090/ws", "realm1"); 140 | info!("Connecting"); 141 | let client = connection.connect().unwrap(); 142 | 143 | info!("Connected"); 144 | event_loop(client); 145 | } 146 | -------------------------------------------------------------------------------- /examples/endpoint.rs: -------------------------------------------------------------------------------- 1 | extern crate eventual; 2 | extern crate wamp; 3 | #[macro_use] 4 | extern crate log; 5 | extern crate env_logger; 6 | 7 | use eventual::Async; 8 | use std::io; 9 | use wamp::client::Connection; 10 | use wamp::{ArgList, CallResult, Dict, List, Value, URI}; 11 | 12 | #[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] 13 | fn addition_callback(args: List, _kwargs: Dict) -> CallResult<(Option, Option)> { 14 | info!("Performing addition"); 15 | try!(args.verify_len(2)); 16 | let a = try!(args.get_int(0)).unwrap(); 17 | let b = try!(args.get_int(1)).unwrap(); 18 | Ok((Some(vec![Value::Integer(a + b)]), None)) 19 | } 20 | 21 | #[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] 22 | fn multiplication_callback(args: List, _kwargs: Dict) -> CallResult<(Option, Option)> { 23 | info!("Performing multiplication"); 24 | try!(args.verify_len(2)); 25 | let a = try!(args.get_int(0)).unwrap(); 26 | let b = try!(args.get_int(1)).unwrap(); 27 | Ok((Some(vec![Value::Integer(a * b)]), None)) 28 | } 29 | 30 | fn echo_callback(args: List, kwargs: Dict) -> CallResult<(Option, Option)> { 31 | info!("Performing echo"); 32 | Ok((Some(args), Some(kwargs))) 33 | } 34 | 35 | fn main() { 36 | env_logger::init(); 37 | let connection = Connection::new("ws://127.0.0.1:8090/ws", "realm1"); 38 | info!("Connecting"); 39 | let mut client = connection.connect().unwrap(); 40 | 41 | info!("Connected"); 42 | info!("Registering Addition Procedure"); 43 | client 44 | .register(URI::new("ca.test.add"), Box::new(addition_callback)) 45 | .unwrap() 46 | .await() 47 | .unwrap(); 48 | 49 | info!("Registering Multiplication Procedure"); 50 | let mult_reg = client 51 | .register(URI::new("ca.test.mult"), Box::new(multiplication_callback)) 52 | .unwrap() 53 | .await() 54 | .unwrap(); 55 | 56 | info!("Unregistering Multiplication Procedure"); 57 | client.unregister(mult_reg).unwrap().await().unwrap(); 58 | 59 | info!("Registering Echo Procedure"); 60 | client 61 | .register(URI::new("ca.test.echo"), Box::new(echo_callback)) 62 | .unwrap() 63 | .await() 64 | .unwrap(); 65 | 66 | println!("Press enter to quit"); 67 | let mut input = String::new(); 68 | io::stdin().read_line(&mut input).unwrap(); 69 | client.shutdown().unwrap().await().unwrap(); 70 | } 71 | -------------------------------------------------------------------------------- /examples/pubsubclient.rs: -------------------------------------------------------------------------------- 1 | extern crate eventual; 2 | extern crate wamp; 3 | use eventual::Async; 4 | use std::io; 5 | use std::sync::{Arc, Mutex}; 6 | use wamp::client::{Client, Connection, Subscription}; 7 | use wamp::{MatchingPolicy, Value, URI}; 8 | 9 | #[macro_use] 10 | extern crate log; 11 | extern crate env_logger; 12 | 13 | enum Command { 14 | Sub, 15 | Pub, 16 | Unsub, 17 | List, 18 | Help, 19 | Quit, 20 | NoOp, 21 | Invalid(String), 22 | } 23 | 24 | fn print_prompt() { 25 | println!("Enter a command (or type \"help\")"); 26 | } 27 | 28 | fn get_input_from_user() -> String { 29 | let mut input = String::new(); 30 | io::stdin().read_line(&mut input).unwrap(); 31 | input 32 | } 33 | 34 | fn process_input(input: &str) -> (Command, Vec) { 35 | let mut i_iter = input.splitn(2, ' '); 36 | let command = match i_iter.next() { 37 | Some(command) => command.trim().to_lowercase(), 38 | None => return (Command::NoOp, Vec::new()), 39 | }; 40 | let command = match command.as_str() { 41 | "pub" => Command::Pub, 42 | "sub" => Command::Sub, 43 | "unsub" => Command::Unsub, 44 | "list" => Command::List, 45 | "help" => Command::Help, 46 | "quit" => Command::Quit, 47 | "" => Command::NoOp, 48 | x => Command::Invalid(x.to_string()), 49 | }; 50 | let args = match i_iter.next() { 51 | Some(args_string) => args_string 52 | .split(',') 53 | .map(|s| s.trim().to_string()) 54 | .collect(), 55 | None => Vec::new(), 56 | }; 57 | (command, args) 58 | } 59 | 60 | fn subscribe( 61 | client: &mut Client, 62 | subscriptions: &mut Arc>>, 63 | args: &[String], 64 | ) { 65 | if args.len() > 2 { 66 | println!("Too many arguments to subscribe. Ignoring"); 67 | } else if args.is_empty() { 68 | println!("Please specify the topic to subscribe to"); 69 | return; 70 | } 71 | let topic = args[0].clone(); 72 | let policy = if args.len() > 1 { 73 | match args[1].as_str() { 74 | "prefix" => MatchingPolicy::Prefix, 75 | "wild" => MatchingPolicy::Wildcard, 76 | "strict" => MatchingPolicy::Strict, 77 | _ => { 78 | println!("Invalid matching type, should be 'prefix', 'wild' or 'strict'"); 79 | return; 80 | } 81 | } 82 | } else { 83 | MatchingPolicy::Strict 84 | }; 85 | let subscriptions = Arc::clone(subscriptions); 86 | client 87 | .subscribe_with_pattern( 88 | URI::new(&topic), 89 | Box::new(move |args, kwargs| { 90 | println!( 91 | "Received message on topic {} with args {:?} and kwargs {:?}", 92 | topic, args, kwargs 93 | ); 94 | }), 95 | policy, 96 | ) 97 | .unwrap() 98 | .and_then(move |subscription| { 99 | println!("Subscribed to topic {}", subscription.topic.uri); 100 | subscriptions.lock().unwrap().push(subscription); 101 | Ok(()) 102 | }) 103 | .await() 104 | .unwrap(); 105 | } 106 | 107 | fn unsubscribe( 108 | client: &mut Client, 109 | subscriptions: &mut Arc>>, 110 | args: &[String], 111 | ) { 112 | if args.len() > 1 { 113 | println!("Too many arguments to subscribe. Ignoring"); 114 | } else if args.is_empty() { 115 | println!("Please specify the topic to subscribe to"); 116 | return; 117 | } 118 | match args[0].parse::() { 119 | Ok(i) => { 120 | let mut subscriptions = subscriptions.lock().unwrap(); 121 | if i >= subscriptions.len() { 122 | println!("Invalid subscription index: {}", i); 123 | return; 124 | } 125 | let subscription = subscriptions.remove(i); 126 | let topic = subscription.topic.uri.clone(); 127 | client 128 | .unsubscribe(subscription) 129 | .unwrap() 130 | .and_then(move |()| { 131 | println!("Successfully unsubscribed from {}", topic); 132 | Ok(()) 133 | }) 134 | .await() 135 | .unwrap(); 136 | } 137 | Err(_) => { 138 | println!("Invalid subscription index: {}", args[0]); 139 | } 140 | } 141 | } 142 | 143 | fn list(subscriptions: &Arc>>) { 144 | let subscriptions = subscriptions.lock().unwrap(); 145 | for (index, subscription) in subscriptions.iter().enumerate() { 146 | println!("{} {}", index, subscription.topic.uri); 147 | } 148 | } 149 | 150 | fn publish(client: &mut Client, args: &[String]) { 151 | if args.is_empty() { 152 | println!("Please specify a topic to publish to"); 153 | } 154 | let uri = &args[0]; 155 | let args = args[1..] 156 | .iter() 157 | .map(|arg| match arg.parse::() { 158 | Ok(i) => Value::Integer(i), 159 | Err(_) => Value::String(arg.clone()), 160 | }) 161 | .collect(); 162 | client 163 | .publish_and_acknowledge(URI::new(uri), Some(args), None) 164 | .unwrap() 165 | .await() 166 | .unwrap(); 167 | } 168 | 169 | fn help() { 170 | println!("The following commands are supported:"); 171 | println!(" sub , ?",); 172 | println!(" Subscribes to the topic specified by the uri "); 173 | println!(" specifies the type of patten matching used",); 174 | println!( 175 | " should be one of 'strict' (the default), 'wild' or 'prefix'", 176 | ); 177 | println!(" pub , *",); 178 | println!(" Publishes to the topic specified by uri "); 179 | println!(" is an optinal, comma separated list of arguments"); 180 | println!(" list"); 181 | println!(" Lists all of the current subscriptions, along with their index"); 182 | println!(" unsub "); 183 | println!(" Unsubscribes from the topic subscription specified by the given index"); 184 | println!(" quit"); 185 | println!(" Sends a goodbye message and quits the program"); 186 | } 187 | 188 | fn event_loop(mut client: Client) { 189 | let mut subscriptions = Arc::new(Mutex::new(Vec::new())); 190 | loop { 191 | print_prompt(); 192 | let input = get_input_from_user(); 193 | let (command, args) = process_input(&input); 194 | match command { 195 | Command::Sub => subscribe(&mut client, &mut subscriptions, &args), 196 | Command::Pub => publish(&mut client, &args), 197 | Command::Unsub => unsubscribe(&mut client, &mut subscriptions, &args), 198 | Command::List => list(&subscriptions), 199 | Command::Help => help(), 200 | Command::Quit => break, 201 | Command::NoOp => {} 202 | Command::Invalid(bad_command) => print!("Invalid command: {}", bad_command), 203 | } 204 | } 205 | client.shutdown().unwrap().await().unwrap(); 206 | } 207 | 208 | fn main() { 209 | env_logger::init(); 210 | let connection = Connection::new("ws://127.0.0.1:8090/ws", "kitchen_realm"); 211 | info!("Connecting"); 212 | let client = connection.connect().unwrap(); 213 | 214 | info!("Connected"); 215 | event_loop(client); 216 | } 217 | -------------------------------------------------------------------------------- /examples/router.rs: -------------------------------------------------------------------------------- 1 | extern crate wamp; 2 | 3 | use wamp::router::Router; 4 | extern crate env_logger; 5 | #[macro_use] 6 | extern crate log; 7 | 8 | fn main() { 9 | env_logger::init(); 10 | let mut router = Router::new(); 11 | router.add_realm("kitchen_realm"); 12 | info!("Router listening"); 13 | let child = router.listen("127.0.0.1:8090"); 14 | child.join().unwrap(); 15 | } 16 | -------------------------------------------------------------------------------- /src/client.rs: -------------------------------------------------------------------------------- 1 | use ws::{connect, CloseCode, Error as WSError, ErrorKind as WSErrorKind, Handler, Handshake, 2 | Message as WSMessage, Request, Result as WSResult, Sender}; 3 | 4 | use ws::util::Token; 5 | 6 | use eventual::{Complete, Future}; 7 | use messages::{CallOptions, ClientRoles, Dict, ErrorDetails, ErrorType, HelloDetails, 8 | InvocationDetails, List, MatchingPolicy, Message, PublishOptions, Reason, 9 | RegisterOptions, ResultDetails, SubscribeOptions, WelcomeDetails, YieldOptions, URI}; 10 | use rmp_serde::Deserializer as RMPDeserializer; 11 | use rmp_serde::Serializer; 12 | use serde::{Deserialize, Serialize}; 13 | use serde_json; 14 | use std::collections::HashMap; 15 | use std::fmt; 16 | use std::io::Cursor; 17 | use std::sync::mpsc::{channel, Sender as CHSender}; 18 | use std::sync::{Arc, Mutex, MutexGuard}; 19 | use std::thread; 20 | use std::time::Duration; 21 | use url::Url; 22 | use utils::StructMapWriter; 23 | use {CallError, CallResult, Error, ErrorKind, WampResult, ID}; 24 | 25 | const CONNECTION_TIMEOUT: Token = Token(124); 26 | 27 | pub struct Connection { 28 | // sender: Sender, 29 | // receiver: client::Receiver, 30 | realm: URI, 31 | url: String, 32 | } 33 | 34 | pub struct Subscription { 35 | pub topic: URI, 36 | subscription_id: ID, 37 | } 38 | 39 | pub struct Registration { 40 | pub procedure: URI, 41 | registration_id: ID, 42 | } 43 | 44 | struct SubscriptionCallbackWrapper { 45 | callback: Box, 46 | } 47 | 48 | struct RegistrationCallbackWrapper { 49 | callback: Callback, 50 | } 51 | 52 | pub type Callback = Box CallResult<(Option, Option)>>; 53 | 54 | static WAMP_JSON: &'static str = "wamp.2.json"; 55 | static WAMP_MSGPACK: &'static str = "wamp.2.msgpack"; 56 | 57 | #[derive(PartialEq, Debug)] 58 | enum ConnectionState { 59 | Connecting, 60 | Connected, 61 | ShuttingDown, 62 | Disconnected, 63 | } 64 | 65 | type ConnectionResult = Result>, Error>; 66 | 67 | unsafe impl<'a> Send for ConnectionInfo {} 68 | 69 | unsafe impl<'a> Sync for ConnectionInfo {} 70 | 71 | unsafe impl<'a> Send for SubscriptionCallbackWrapper {} 72 | 73 | unsafe impl<'a> Sync for SubscriptionCallbackWrapper {} 74 | 75 | unsafe impl<'a> Send for RegistrationCallbackWrapper {} 76 | 77 | unsafe impl<'a> Sync for RegistrationCallbackWrapper {} 78 | 79 | pub struct Client { 80 | connection_info: Arc>, 81 | max_session_id: ID, 82 | } 83 | 84 | pub struct ConnectionHandler { 85 | connection_info: Arc>, 86 | realm: URI, 87 | state_transmission: CHSender, 88 | } 89 | 90 | struct ConnectionInfo { 91 | connection_state: ConnectionState, 92 | sender: Sender, 93 | subscription_requests: HashMap< 94 | ID, 95 | ( 96 | Complete, 97 | SubscriptionCallbackWrapper, 98 | URI, 99 | ), 100 | >, 101 | unsubscription_requests: HashMap, ID)>, 102 | subscriptions: HashMap, 103 | registrations: HashMap, 104 | call_requests: HashMap>, 105 | registration_requests: HashMap< 106 | ID, 107 | ( 108 | Complete, 109 | RegistrationCallbackWrapper, 110 | URI, 111 | ), 112 | >, 113 | unregistration_requests: HashMap, ID)>, 114 | protocol: String, 115 | publish_requests: HashMap>, 116 | shutdown_complete: Option>, 117 | session_id: ID, 118 | } 119 | 120 | trait MessageSender { 121 | fn send_message(&self, message: Message) -> WampResult<()>; 122 | } 123 | 124 | impl MessageSender for ConnectionInfo { 125 | fn send_message(&self, message: Message) -> WampResult<()> { 126 | debug!("Sending message {:?} via {}", message, self.protocol); 127 | let send_result = if self.protocol == WAMP_JSON { 128 | send_message_json(&self.sender, &message) 129 | } else { 130 | send_message_msgpack(&self.sender, &message) 131 | }; 132 | match send_result { 133 | Ok(()) => Ok(()), 134 | Err(e) => Err(Error::new(ErrorKind::WSError(e))), 135 | } 136 | } 137 | } 138 | 139 | fn send_message_json(sender: &Sender, message: &Message) -> WSResult<()> { 140 | // Send the message 141 | sender.send(WSMessage::Text(serde_json::to_string(message).unwrap())) 142 | } 143 | 144 | fn send_message_msgpack(sender: &Sender, message: &Message) -> WSResult<()> { 145 | // Send the message 146 | let mut buf: Vec = Vec::new(); 147 | message 148 | .serialize(&mut Serializer::with(&mut buf, StructMapWriter)) 149 | .unwrap(); 150 | sender.send(WSMessage::Binary(buf)) 151 | } 152 | 153 | impl Connection { 154 | pub fn new(url: &str, realm: &str) -> Connection { 155 | Connection { 156 | realm: URI::new(realm), 157 | url: url.to_string(), 158 | } 159 | } 160 | 161 | pub fn connect(&self) -> WampResult { 162 | let (tx, rx) = channel(); 163 | let url = self.url.clone(); 164 | let realm = self.realm.clone(); 165 | thread::spawn(move || { 166 | trace!("Beginning Connection"); 167 | let connect_result = connect(url, |out| { 168 | trace!("Got sender"); 169 | // Set up timeout 170 | out.timeout(5000, CONNECTION_TIMEOUT).unwrap(); 171 | let info = Arc::new(Mutex::new(ConnectionInfo { 172 | protocol: String::new(), 173 | subscription_requests: HashMap::new(), 174 | unsubscription_requests: HashMap::new(), 175 | subscriptions: HashMap::new(), 176 | registrations: HashMap::new(), 177 | call_requests: HashMap::new(), 178 | registration_requests: HashMap::new(), 179 | unregistration_requests: HashMap::new(), 180 | sender: out, 181 | connection_state: ConnectionState::Connecting, 182 | publish_requests: HashMap::new(), 183 | shutdown_complete: None, 184 | session_id: 0, 185 | })); 186 | 187 | ConnectionHandler { 188 | state_transmission: tx.clone(), 189 | connection_info: info, 190 | realm: realm.clone(), 191 | } 192 | }).map_err(|e| Error::new(ErrorKind::WSError(e))); 193 | debug!("Result of connection: {:?}", connect_result); 194 | match connect_result { 195 | Ok(_) => (), 196 | Err(e) => { 197 | tx.send(Err(e)).unwrap(); 198 | } 199 | } 200 | }); 201 | let info = try!(rx.recv().unwrap()); 202 | Ok(Client { 203 | connection_info: info, 204 | max_session_id: 0, 205 | }) 206 | } 207 | } 208 | 209 | macro_rules! cancel_future_tuple { 210 | ($dict:expr) => {{ 211 | for (_, future) in $dict.drain() { 212 | future 213 | .0 214 | .fail(CallError::new(Reason::NetworkFailure, None, None)); 215 | } 216 | }}; 217 | } 218 | 219 | macro_rules! cancel_future { 220 | ($dict:expr) => {{ 221 | for (_, future) in $dict.drain() { 222 | future.fail(CallError::new(Reason::NetworkFailure, None, None)); 223 | } 224 | }}; 225 | } 226 | 227 | impl Handler for ConnectionHandler { 228 | fn on_open(&mut self, handshake: Handshake) -> WSResult<()> { 229 | debug!("Connection Opened"); 230 | let mut info = self.connection_info.lock().unwrap(); 231 | info.protocol = match try!(handshake.response.protocol()) { 232 | Some(protocol) => protocol.to_string(), 233 | None => { 234 | warn!("Router did not specify protocol. Defaulting to wamp.2.json"); 235 | WAMP_JSON.to_string() 236 | } 237 | }; 238 | 239 | let hello_message = 240 | Message::Hello(self.realm.clone(), HelloDetails::new(ClientRoles::new())); 241 | debug!("Sending Hello message"); 242 | thread::sleep(Duration::from_millis(200)); 243 | match info.send_message(hello_message) { 244 | Ok(_) => Ok(()), 245 | Err(e) => { 246 | if let ErrorKind::WSError(e) = e.kind { 247 | Err(e) 248 | } else { 249 | Err(WSError::new(WSErrorKind::Internal, "Unknown error")) 250 | } 251 | } 252 | } 253 | } 254 | 255 | fn on_message(&mut self, message: WSMessage) -> WSResult<()> { 256 | debug!("Server sent a message: {:?}", message); 257 | match message { 258 | WSMessage::Text(message) => match serde_json::from_str(&message) { 259 | Ok(message) => { 260 | if !self.handle_message(message) { 261 | return self.connection_info.lock().unwrap().sender.shutdown(); 262 | } 263 | } 264 | Err(_) => { 265 | error!("Received unknown message: {}", message); 266 | return Ok(()); 267 | } 268 | }, 269 | WSMessage::Binary(message) => { 270 | let mut de = RMPDeserializer::new(Cursor::new(&*message)); 271 | match Deserialize::deserialize(&mut de) { 272 | Ok(message) => { 273 | if !self.handle_message(message) { 274 | return self.connection_info.lock().unwrap().sender.shutdown(); 275 | } 276 | } 277 | Err(_) => { 278 | error!("Could not understand MsgPack message"); 279 | } 280 | } 281 | } 282 | } 283 | Ok(()) 284 | } 285 | 286 | fn on_close(&mut self, _code: CloseCode, _reason: &str) { 287 | debug!("Closing connection"); 288 | let mut info = self.connection_info.lock().unwrap(); 289 | info.sender.close(CloseCode::Normal).ok(); 290 | info.connection_state = ConnectionState::Disconnected; 291 | cancel_future_tuple!(info.subscription_requests); 292 | cancel_future_tuple!(info.unsubscription_requests); 293 | cancel_future_tuple!(info.registration_requests); 294 | cancel_future_tuple!(info.unregistration_requests); 295 | cancel_future!(info.publish_requests); 296 | cancel_future!(info.call_requests); 297 | info.sender.shutdown().ok(); 298 | 299 | if let Some(promise) = info.shutdown_complete.take() { 300 | promise.complete(()); 301 | } 302 | } 303 | 304 | fn on_timeout(&mut self, token: Token) -> WSResult<()> { 305 | if token == CONNECTION_TIMEOUT { 306 | let info = self.connection_info.lock().unwrap(); 307 | if info.connection_state == ConnectionState::Connecting { 308 | info.sender.shutdown().unwrap(); 309 | drop(info); 310 | self.state_transmission 311 | .send(Err(Error::new(ErrorKind::Timeout))) 312 | .unwrap(); 313 | } 314 | } 315 | Ok(()) 316 | } 317 | 318 | fn build_request(&mut self, url: &Url) -> WSResult { 319 | trace!("Building request"); 320 | let mut request = try!(Request::from_url(url)); 321 | request.add_protocol(WAMP_MSGPACK); 322 | request.add_protocol(WAMP_JSON); 323 | Ok(request) 324 | } 325 | } 326 | 327 | impl ConnectionHandler { 328 | fn handle_message(&mut self, message: Message) -> bool { 329 | let mut info = self.connection_info.lock().unwrap(); 330 | debug!( 331 | "Processing message from server (state: {:?})", 332 | info.connection_state 333 | ); 334 | match info.connection_state { 335 | ConnectionState::Connecting => match message { 336 | Message::Welcome(session_id, details) => { 337 | self.handle_welcome(info, session_id, details) 338 | } 339 | Message::Abort(_, reason) => { 340 | self.handle_abort(info, reason); 341 | return false; 342 | } 343 | _ => return false, 344 | }, 345 | ConnectionState::Connected => { 346 | debug!("Received a message from the server: {:?}", message); 347 | match message { 348 | Message::Subscribed(request_id, subscription_id) => { 349 | self.handle_subscribed(info, request_id, subscription_id) 350 | } 351 | Message::Unsubscribed(request_id) => self.handle_unsubscribed(info, request_id), 352 | Message::Event(subscription_id, _, _, args, kwargs) => { 353 | self.handle_event(info, subscription_id, args, kwargs) 354 | } 355 | Message::Published(request_id, publication_id) => { 356 | self.handle_published(info, request_id, publication_id) 357 | } 358 | Message::Registered(request_id, registration_id) => { 359 | self.handle_registered(info, request_id, registration_id) 360 | } 361 | Message::Unregistered(request_id) => self.handle_unregistered(info, request_id), 362 | Message::Invocation(request_id, registration_id, details, args, kwargs) => { 363 | self.handle_invocation( 364 | info, 365 | request_id, 366 | registration_id, 367 | details, 368 | args, 369 | kwargs, 370 | ) 371 | } 372 | Message::Result(call_id, details, args, kwargs) => { 373 | self.handle_result(info, call_id, details, args, kwargs) 374 | } 375 | Message::Error(e_type, request_id, details, reason, args, kwargs) => { 376 | self.handle_error(info, e_type, request_id, details, reason, args, kwargs) 377 | } 378 | Message::Goodbye(_, reason) => { 379 | self.handle_goodbye(info, reason); 380 | return false; 381 | } 382 | _ => warn!("Received unknown message. Ignoring. {:?}", message), 383 | } 384 | } 385 | ConnectionState::ShuttingDown => { 386 | if let Message::Goodbye(_, _) = message { 387 | // The router has seen our goodbye message and has responded in kind 388 | info!("Router acknowledged disconnect"); 389 | if let Some(promise) = info.shutdown_complete.take() { 390 | promise.complete(()) 391 | } 392 | return false; 393 | } else { 394 | warn!( 395 | "Received message after shutting down, ignoring: {:?}", 396 | message 397 | ); 398 | return false; 399 | } 400 | } 401 | ConnectionState::Disconnected => { 402 | // Should never happen 403 | return false; 404 | } 405 | } 406 | true 407 | } 408 | 409 | fn handle_subscribed( 410 | &self, 411 | mut info: MutexGuard, 412 | request_id: ID, 413 | subscription_id: ID, 414 | ) { 415 | // TODO handle errors here 416 | info!("Received a subscribed notification"); 417 | match info.subscription_requests.remove(&request_id) { 418 | Some((promise, callback, topic)) => { 419 | debug!("Completing promise"); 420 | let subscription = Subscription { 421 | topic: topic, 422 | subscription_id: subscription_id, 423 | }; 424 | info.subscriptions.insert(subscription_id, callback); 425 | drop(info); 426 | promise.complete(subscription) 427 | } 428 | None => { 429 | warn!( 430 | "Received a subscribed notification for a subscription we don't have. ID: {}", 431 | request_id 432 | ); 433 | } 434 | } 435 | } 436 | 437 | fn handle_subscribe_error( 438 | &self, 439 | mut info: MutexGuard, 440 | request_id: ID, 441 | reason: Reason, 442 | args: Option, 443 | kwargs: Option, 444 | ) { 445 | warn!("Received an error for a subscription"); 446 | match info.subscription_requests.remove(&request_id) { 447 | Some((promise, _, _)) => { 448 | drop(info); 449 | promise.fail(CallError::new(reason, args, kwargs)); 450 | } 451 | None => { 452 | warn!( 453 | "Received a an error notification for a request we didn't make. ID: {}", 454 | request_id 455 | ); 456 | } 457 | } 458 | } 459 | 460 | fn handle_unsubscribed(&self, mut info: MutexGuard, request_id: ID) { 461 | match info.unsubscription_requests.remove(&request_id) { 462 | Some((promise, subscription_id)) => { 463 | info.unsubscription_requests.remove(&subscription_id); 464 | drop(info); 465 | promise.complete(()) 466 | } 467 | None => { 468 | warn!("Received a unsubscribed notification for a subscription we don't have. ID: {}", request_id); 469 | } 470 | } 471 | } 472 | 473 | fn handle_unsubscribe_error( 474 | &self, 475 | mut info: MutexGuard, 476 | request_id: ID, 477 | reason: Reason, 478 | args: Option, 479 | kwargs: Option, 480 | ) { 481 | match info.unsubscription_requests.remove(&request_id) { 482 | Some((promise, subscription_id)) => { 483 | info.unsubscription_requests.remove(&subscription_id); 484 | drop(info); 485 | promise.fail(CallError::new(reason, args, kwargs)) 486 | } 487 | None => { 488 | warn!( 489 | "Received a unsubscribed error for a subscription we don't have. ID: {}", 490 | request_id 491 | ); 492 | } 493 | } 494 | } 495 | 496 | fn handle_registered( 497 | &self, 498 | mut info: MutexGuard, 499 | request_id: ID, 500 | registration_id: ID, 501 | ) { 502 | // TODO handle errors here 503 | info!("Received a registered notification"); 504 | match info.registration_requests.remove(&request_id) { 505 | Some((promise, callback, procedure)) => { 506 | info.registrations.insert(registration_id, callback); 507 | drop(info); 508 | let registration = Registration { 509 | procedure: procedure, 510 | registration_id: registration_id, 511 | }; 512 | promise.complete(registration) 513 | } 514 | None => { 515 | warn!( 516 | "Received a registered notification for a registration we don't have. ID: {}", 517 | request_id 518 | ); 519 | } 520 | } 521 | } 522 | 523 | fn handle_register_error( 524 | &self, 525 | mut info: MutexGuard, 526 | request_id: ID, 527 | reason: Reason, 528 | args: Option, 529 | kwargs: Option, 530 | ) { 531 | info!("Received a registration error"); 532 | match info.registration_requests.remove(&request_id) { 533 | Some((promise, _, _)) => { 534 | drop(info); 535 | promise.fail(CallError::new(reason, args, kwargs)) 536 | } 537 | None => { 538 | warn!( 539 | "Received a registered error for a registration we don't have. ID: {}", 540 | request_id 541 | ); 542 | } 543 | } 544 | } 545 | 546 | fn handle_unregistered(&self, mut info: MutexGuard, request_id: ID) { 547 | match info.unregistration_requests.remove(&request_id) { 548 | Some((promise, registration_id)) => { 549 | info.registrations.remove(®istration_id); 550 | drop(info); 551 | promise.complete(()) 552 | } 553 | None => { 554 | warn!("Received a unregistered notification for a registration we don't have. ID: {}", request_id); 555 | } 556 | } 557 | } 558 | 559 | fn handle_unregister_error( 560 | &self, 561 | mut info: MutexGuard, 562 | request_id: ID, 563 | reason: Reason, 564 | args: Option, 565 | kwargs: Option, 566 | ) { 567 | match info.unregistration_requests.remove(&request_id) { 568 | Some((promise, _)) => { 569 | drop(info); 570 | promise.fail(CallError::new(reason, args, kwargs)) 571 | } 572 | None => { 573 | warn!( 574 | "Received a unregistered error for a registration we don't have. ID: {}", 575 | request_id 576 | ); 577 | } 578 | } 579 | } 580 | 581 | fn handle_published( 582 | &self, 583 | mut info: MutexGuard, 584 | request_id: ID, 585 | publication_id: ID, 586 | ) { 587 | match info.publish_requests.remove(&request_id) { 588 | Some(promise) => { 589 | promise.complete(publication_id); 590 | } 591 | None => warn!( 592 | "Received published notification for a request we weren't tracking: {}", 593 | request_id 594 | ), 595 | } 596 | } 597 | fn handle_publish_error( 598 | &self, 599 | mut info: MutexGuard, 600 | request_id: ID, 601 | reason: Reason, 602 | args: Option, 603 | kwargs: Option, 604 | ) { 605 | match info.publish_requests.remove(&request_id) { 606 | Some(promise) => promise.fail(CallError::new(reason, args, kwargs)), 607 | None => warn!("Received published error for a publication: {}", request_id), 608 | } 609 | } 610 | 611 | fn handle_welcome( 612 | &self, 613 | mut info: MutexGuard, 614 | session_id: ID, 615 | _details: WelcomeDetails, 616 | ) { 617 | info.session_id = session_id; 618 | info.connection_state = ConnectionState::Connected; 619 | drop(info); 620 | self.state_transmission 621 | .send(Ok(Arc::clone(&self.connection_info))) 622 | .unwrap(); 623 | } 624 | 625 | fn handle_abort(&self, mut info: MutexGuard, reason: Reason) { 626 | error!("Router aborted connection. Reason: {:?}", reason); 627 | info.connection_state = ConnectionState::ShuttingDown; 628 | } 629 | 630 | fn handle_event( 631 | &self, 632 | mut info: MutexGuard, 633 | subscription_id: ID, 634 | args: Option, 635 | kwargs: Option, 636 | ) { 637 | let args = args.unwrap_or_default(); 638 | let kwargs = kwargs.unwrap_or_default(); 639 | match info.subscriptions.get_mut(&subscription_id) { 640 | Some(subscription) => { 641 | let callback = &mut subscription.callback; 642 | callback(args, kwargs); 643 | } 644 | None => { 645 | warn!( 646 | "Received an event for a subscription we don't have. ID: {}", 647 | subscription_id 648 | ); 649 | } 650 | } 651 | } 652 | 653 | fn handle_invocation( 654 | &self, 655 | mut info: MutexGuard, 656 | request_id: ID, 657 | registration_id: ID, 658 | _details: InvocationDetails, 659 | args: Option, 660 | kwargs: Option, 661 | ) { 662 | let args = args.unwrap_or_default(); 663 | let kwargs = kwargs.unwrap_or_default(); 664 | let message = match info.registrations.get_mut(®istration_id) { 665 | Some(registration) => { 666 | let callback = &mut registration.callback; 667 | match callback(args, kwargs) { 668 | Ok((rargs, rkwargs)) => { 669 | Message::Yield(request_id, YieldOptions::new(), rargs, rkwargs) 670 | } 671 | Err(error) => { 672 | let (reason, args, kwargs) = error.into_tuple(); 673 | Message::Error( 674 | ErrorType::Invocation, 675 | request_id, 676 | HashMap::new(), 677 | reason, 678 | args, 679 | kwargs, 680 | ) 681 | } 682 | } 683 | } 684 | None => { 685 | warn!( 686 | "Received an invocation for a procedure we don't have. ID: {}", 687 | registration_id 688 | ); 689 | return; 690 | } 691 | }; 692 | info.send_message(message).ok(); 693 | } 694 | 695 | fn handle_result( 696 | &self, 697 | mut info: MutexGuard, 698 | call_id: ID, 699 | _details: ResultDetails, 700 | args: Option, 701 | kwargs: Option, 702 | ) { 703 | let args = args.unwrap_or_default(); 704 | let kwargs = kwargs.unwrap_or_default(); 705 | match info.call_requests.remove(&call_id) { 706 | Some(promise) => { 707 | promise.complete((args, kwargs)); 708 | } 709 | None => { 710 | warn!( 711 | "Received a result for a call we didn't make. ID: {}", 712 | call_id 713 | ); 714 | } 715 | } 716 | } 717 | 718 | fn handle_call_error( 719 | &self, 720 | mut info: MutexGuard, 721 | request_id: ID, 722 | reason: Reason, 723 | args: Option, 724 | kwargs: Option, 725 | ) { 726 | match info.call_requests.remove(&request_id) { 727 | Some(promise) => promise.fail(CallError::new(reason, args, kwargs)), 728 | None => { 729 | warn!( 730 | "Received an error for a call we didn't make. ID: {}", 731 | request_id 732 | ); 733 | } 734 | } 735 | } 736 | 737 | fn handle_goodbye(&self, mut info: MutexGuard, reason: Reason) { 738 | info!("Router said goodbye. Reason: {:?}", reason); 739 | 740 | info.send_message(Message::Goodbye(ErrorDetails::new(), Reason::GoodbyeAndOut)) 741 | .unwrap(); 742 | info.connection_state = ConnectionState::ShuttingDown; 743 | } 744 | 745 | #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] 746 | fn handle_error( 747 | &self, 748 | info: MutexGuard, 749 | e_type: ErrorType, 750 | request_id: ID, 751 | _details: Dict, 752 | reason: Reason, 753 | args: Option, 754 | kwargs: Option, 755 | ) { 756 | match e_type { 757 | ErrorType::Subscribe => { 758 | self.handle_subscribe_error(info, request_id, reason, args, kwargs) 759 | }, 760 | ErrorType::Unsubscribe => { 761 | self.handle_unsubscribe_error(info, request_id, reason, args, kwargs) 762 | }, 763 | ErrorType::Publish => { 764 | self.handle_publish_error(info, request_id, reason, args, kwargs) 765 | }, 766 | ErrorType::Register => { 767 | self.handle_register_error(info, request_id, reason, args, kwargs) 768 | }, 769 | ErrorType::Unregister => { 770 | self.handle_unregister_error(info, request_id, reason, args, kwargs) 771 | }, 772 | ErrorType::Invocation => { 773 | warn!("Received an error for an invocation message, which we did not (and could not) send") 774 | }, 775 | ErrorType::Call => { 776 | self.handle_call_error(info, request_id, reason, args, kwargs) 777 | } 778 | } 779 | } 780 | } 781 | 782 | impl Client { 783 | fn get_next_session_id(&mut self) -> ID { 784 | self.max_session_id += 1; 785 | self.max_session_id 786 | } 787 | 788 | pub fn subscribe_with_pattern( 789 | &mut self, 790 | topic_pattern: URI, 791 | callback: Box, 792 | policy: MatchingPolicy, 793 | ) -> WampResult> { 794 | // Send a subscribe messages 795 | let request_id = self.get_next_session_id(); 796 | let (complete, future) = Future::::pair(); 797 | let callback = SubscriptionCallbackWrapper { callback: callback }; 798 | let mut options = SubscribeOptions::new(); 799 | if policy != MatchingPolicy::Strict { 800 | options.pattern_match = policy 801 | } 802 | let mut info = self.connection_info.lock().unwrap(); 803 | info.subscription_requests 804 | .insert(request_id, (complete, callback, topic_pattern.clone())); 805 | try!(info.send_message(Message::Subscribe(request_id, options, topic_pattern))); 806 | Ok(future) 807 | } 808 | 809 | pub fn subscribe( 810 | &mut self, 811 | topic: URI, 812 | callback: Box, 813 | ) -> WampResult> { 814 | self.subscribe_with_pattern(topic, callback, MatchingPolicy::Strict) 815 | } 816 | 817 | pub fn register_with_pattern( 818 | &mut self, 819 | procedure_pattern: URI, 820 | callback: Callback, 821 | policy: MatchingPolicy, 822 | ) -> WampResult> { 823 | // Send a register message 824 | let request_id = self.get_next_session_id(); 825 | let (complete, future) = Future::::pair(); 826 | let callback = RegistrationCallbackWrapper { callback: callback }; 827 | let mut options = RegisterOptions::new(); 828 | if policy != MatchingPolicy::Strict { 829 | options.pattern_match = policy 830 | } 831 | debug!("Acquiring lock on connection info"); 832 | let mut info = self.connection_info.lock().unwrap(); 833 | debug!("Lock on connection info acquired"); 834 | info.registration_requests 835 | .insert(request_id, (complete, callback, procedure_pattern.clone())); 836 | try!(info.send_message(Message::Register(request_id, options, procedure_pattern))); 837 | Ok(future) 838 | } 839 | 840 | pub fn register( 841 | &mut self, 842 | procedure: URI, 843 | callback: Callback, 844 | ) -> WampResult> { 845 | self.register_with_pattern(procedure, callback, MatchingPolicy::Strict) 846 | } 847 | 848 | pub fn unsubscribe(&mut self, subscription: Subscription) -> WampResult> { 849 | let request_id = self.get_next_session_id(); 850 | let mut info = self.connection_info.lock().unwrap(); 851 | try!(info.send_message(Message::Unsubscribe( 852 | request_id, 853 | subscription.subscription_id 854 | ))); 855 | let (complete, future) = Future::<(), CallError>::pair(); 856 | info.unsubscription_requests 857 | .insert(request_id, (complete, subscription.subscription_id)); 858 | Ok(future) 859 | } 860 | 861 | pub fn unregister(&mut self, registration: Registration) -> WampResult> { 862 | let request_id = self.get_next_session_id(); 863 | let mut info = self.connection_info.lock().unwrap(); 864 | try!(info.send_message(Message::Unregister( 865 | request_id, 866 | registration.registration_id 867 | ))); 868 | let (complete, future) = Future::<(), CallError>::pair(); 869 | 870 | info.unregistration_requests 871 | .insert(request_id, (complete, registration.registration_id)); 872 | Ok(future) 873 | } 874 | 875 | pub fn publish( 876 | &mut self, 877 | topic: URI, 878 | args: Option, 879 | kwargs: Option, 880 | ) -> WampResult<()> { 881 | info!("Publishing to {:?} with {:?} | {:?}", topic, args, kwargs); 882 | let request_id = self.get_next_session_id(); 883 | self.connection_info 884 | .lock() 885 | .unwrap() 886 | .send_message(Message::Publish( 887 | request_id, 888 | PublishOptions::new(false), 889 | topic, 890 | args, 891 | kwargs, 892 | )) 893 | } 894 | 895 | pub fn call( 896 | &mut self, 897 | procedure: URI, 898 | args: Option, 899 | kwargs: Option, 900 | ) -> WampResult> { 901 | info!("Calling {:?} with {:?} | {:?}", procedure, args, kwargs); 902 | let request_id = self.get_next_session_id(); 903 | let (complete, future) = Future::<(List, Dict), CallError>::pair(); 904 | let mut info = self.connection_info.lock().unwrap(); 905 | info.call_requests.insert(request_id, complete); 906 | try!(info.send_message(Message::Call( 907 | request_id, 908 | CallOptions::new(), 909 | procedure, 910 | args, 911 | kwargs 912 | ))); 913 | Ok(future) 914 | } 915 | 916 | pub fn publish_and_acknowledge( 917 | &mut self, 918 | topic: URI, 919 | args: Option, 920 | kwargs: Option, 921 | ) -> WampResult> { 922 | info!("Publishing to {:?} with {:?} | {:?}", topic, args, kwargs); 923 | let request_id = self.get_next_session_id(); 924 | let (complete, future) = Future::::pair(); 925 | let mut info = self.connection_info.lock().unwrap(); 926 | info.publish_requests.insert(request_id, complete); 927 | try!(info.send_message(Message::Publish( 928 | request_id, 929 | PublishOptions::new(true), 930 | topic, 931 | args, 932 | kwargs 933 | ))); 934 | Ok(future) 935 | } 936 | 937 | pub fn shutdown(&mut self) -> WampResult> { 938 | let mut info = self.connection_info.lock().unwrap(); 939 | if info.connection_state == ConnectionState::Connected { 940 | info.connection_state = ConnectionState::ShuttingDown; 941 | let (complete, future) = Future::pair(); 942 | info.shutdown_complete = Some(complete); 943 | // TODO add timeout in case server doesn't respond. 944 | try!(info.send_message(Message::Goodbye( 945 | ErrorDetails::new(), 946 | Reason::SystemShutdown 947 | ))); 948 | Ok(future) 949 | } else { 950 | Err(Error::new(ErrorKind::InvalidState( 951 | "Tried to shut down a client that was already shutting down", 952 | ))) 953 | } 954 | } 955 | } 956 | 957 | impl fmt::Debug for ConnectionHandler { 958 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 959 | write!( 960 | f, 961 | "{{Connection id: {}}}", 962 | self.connection_info.lock().unwrap().session_id 963 | ) 964 | } 965 | } 966 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use super::{ErrorType, Message, ID}; 2 | use messages::{self, Reason}; 3 | use rmp_serde::decode::Error as MsgPackError; 4 | use serde_json::Error as JSONError; 5 | use std::fmt; 6 | use std::sync::mpsc::SendError; 7 | use url::ParseError; 8 | use ws::Error as WSError; 9 | 10 | #[derive(Debug)] 11 | pub struct Error { 12 | pub kind: ErrorKind, 13 | } 14 | 15 | #[derive(Debug)] 16 | pub enum ErrorKind { 17 | WSError(WSError), 18 | URLError(ParseError), 19 | HandshakeError(Reason), 20 | UnexpectedMessage(&'static str), // Used when a peer receives another message before Welcome or Hello 21 | ThreadError(SendError), 22 | ConnectionLost, 23 | Closing(String), 24 | JSONError(JSONError), 25 | MsgPackError(MsgPackError), 26 | MalformedData, 27 | InvalidMessageType(Message), 28 | InvalidState(&'static str), 29 | Timeout, 30 | ErrorReason(ErrorType, ID, Reason), 31 | } 32 | impl Error { 33 | pub fn new(kind: ErrorKind) -> Error { 34 | Error { kind: kind } 35 | } 36 | 37 | fn get_description(&self) -> String { 38 | format!("WAMP Error: {}", self.kind.description()) 39 | } 40 | 41 | #[inline] 42 | pub fn get_kind(self) -> ErrorKind { 43 | self.kind 44 | } 45 | } 46 | 47 | impl fmt::Display for Error { 48 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 49 | write!(f, "{}", self.get_description()) 50 | } 51 | } 52 | 53 | impl ErrorKind { 54 | pub fn description(&self) -> String { 55 | match *self { 56 | ErrorKind::WSError(ref e) => e.to_string(), 57 | ErrorKind::URLError(ref e) => e.to_string(), 58 | ErrorKind::HandshakeError(ref r) => r.to_string(), 59 | ErrorKind::ThreadError(ref e) => e.to_string(), 60 | ErrorKind::JSONError(ref e) => e.to_string(), 61 | ErrorKind::MsgPackError(ref e) => e.to_string(), 62 | ErrorKind::ErrorReason(_, _, ref s) => s.to_string(), 63 | ErrorKind::Closing(ref s) => s.clone(), 64 | ErrorKind::UnexpectedMessage(s) | ErrorKind::InvalidState(s) => s.to_string(), 65 | ErrorKind::ConnectionLost => "Connection Lost".to_string(), 66 | ErrorKind::MalformedData => "Malformed Data".to_string(), 67 | ErrorKind::Timeout => "Connection timed out".to_string(), 68 | ErrorKind::InvalidMessageType(ref t) => format!("Invalid Message Type: {:?}", t), 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(feature = "cargo-clippy", allow(match_same_arms))] 2 | extern crate serde; 3 | extern crate serde_json; 4 | #[macro_use] 5 | extern crate serde_derive; 6 | extern crate eventual; 7 | extern crate itertools; 8 | extern crate rand; 9 | extern crate rmp; 10 | extern crate rmp_serde; 11 | extern crate url; 12 | extern crate ws; 13 | 14 | #[macro_use] 15 | extern crate log; 16 | 17 | pub mod client; 18 | mod error; 19 | mod messages; 20 | pub mod router; 21 | mod utils; 22 | 23 | use self::error::*; 24 | 25 | pub use client::{Client, Connection}; 26 | pub use messages::{ArgDict, ArgList, CallError, Dict, InvocationPolicy, List, MatchingPolicy, 27 | Reason, Value, URI}; 28 | use messages::{ErrorType, Message}; 29 | pub use router::Router; 30 | 31 | pub type CallResult = Result; 32 | pub type WampResult = Result; 33 | pub type ID = u64; 34 | -------------------------------------------------------------------------------- /src/messages/mod.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | pub use messages::types::*; 4 | use serde; 5 | use ID; 6 | mod types; 7 | 8 | macro_rules! try_or { 9 | ($e:expr, $msg:expr) => { 10 | match try!($e) { 11 | Some(val) => val, 12 | None => return Err(serde::de::Error::custom($msg)), 13 | } 14 | }; 15 | } 16 | 17 | #[derive(Debug, PartialEq)] 18 | pub enum Message { 19 | Hello(URI, HelloDetails), 20 | Welcome(ID, WelcomeDetails), 21 | Abort(ErrorDetails, Reason), 22 | Goodbye(ErrorDetails, Reason), 23 | Error(ErrorType, ID, Dict, Reason, Option, Option), 24 | Subscribe(ID, SubscribeOptions, URI), 25 | Subscribed(ID, ID), 26 | Unsubscribe(ID, ID), 27 | Unsubscribed(ID), 28 | Publish(ID, PublishOptions, URI, Option, Option), 29 | Published(ID, ID), 30 | Event(ID, ID, EventDetails, Option, Option), 31 | Register(ID, RegisterOptions, URI), 32 | Registered(ID, ID), 33 | Unregister(ID, ID), 34 | Unregistered(ID), 35 | Call(ID, CallOptions, URI, Option, Option), 36 | Invocation(ID, ID, InvocationDetails, Option, Option), 37 | Yield(ID, YieldOptions, Option, Option), 38 | Result(ID, ResultDetails, Option, Option), 39 | } 40 | 41 | macro_rules! serialize_with_args { 42 | ($args:expr, $kwargs:expr, $serializer:expr, $($item: expr),*) => ( 43 | if let Some(ref kwargs) = *$kwargs { 44 | if let Some(ref args) = *$args { 45 | ( $($item,)* args, kwargs).serialize($serializer) 46 | } else { 47 | ( $($item,)* Vec::::new(), kwargs).serialize($serializer) 48 | } 49 | } else { 50 | if let Some(ref args) = *$args { 51 | ( $($item,)* args).serialize($serializer) 52 | } else { 53 | ( $($item,)*).serialize($serializer) 54 | } 55 | 56 | } 57 | ); 58 | } 59 | 60 | impl serde::Serialize for Message { 61 | fn serialize(&self, serializer: S) -> Result 62 | where 63 | S: serde::Serializer, 64 | { 65 | match *self { 66 | Message::Hello(ref realm, ref details) => (1, &realm, details).serialize(serializer), 67 | Message::Welcome(ref session, ref details) => { 68 | (2, session, details).serialize(serializer) 69 | } 70 | Message::Abort(ref details, ref reason) => (3, details, reason).serialize(serializer), 71 | Message::Goodbye(ref details, ref reason) => (6, details, reason).serialize(serializer), 72 | Message::Error(ref ty, id, ref details, ref reason, ref args, ref kwargs) => { 73 | serialize_with_args!(args, kwargs, serializer, 8, ty, id, details, reason) 74 | } 75 | Message::Subscribe(request_id, ref options, ref topic) => { 76 | (32, request_id, options, topic).serialize(serializer) 77 | } 78 | Message::Subscribed(request_id, subscription_id) => { 79 | (33, request_id, subscription_id).serialize(serializer) 80 | } 81 | Message::Unsubscribe(request_id, subscription_id) => { 82 | (34, request_id, subscription_id).serialize(serializer) 83 | } 84 | Message::Unsubscribed(request_id) => (35, request_id).serialize(serializer), 85 | Message::Publish(id, ref details, ref topic, ref args, ref kwargs) => { 86 | serialize_with_args!(args, kwargs, serializer, 16, id, details, topic) 87 | } 88 | Message::Published(request_id, publication_id) => { 89 | (17, request_id, publication_id).serialize(serializer) 90 | } 91 | Message::Event(subscription_id, publication_id, ref details, ref args, ref kwargs) => { 92 | serialize_with_args!( 93 | args, 94 | kwargs, 95 | serializer, 96 | 36, 97 | subscription_id, 98 | publication_id, 99 | details 100 | ) 101 | } 102 | Message::Register(request_id, ref options, ref procedure) => { 103 | (64, request_id, options, procedure).serialize(serializer) 104 | } 105 | Message::Registered(request_id, registration_id) => { 106 | (65, request_id, registration_id).serialize(serializer) 107 | } 108 | Message::Unregister(request_id, registration_id) => { 109 | (66, request_id, registration_id).serialize(serializer) 110 | } 111 | Message::Unregistered(request_id) => (67, request_id).serialize(serializer), 112 | Message::Call(id, ref options, ref topic, ref args, ref kwargs) => { 113 | serialize_with_args!(args, kwargs, serializer, 48, id, options, topic) 114 | } 115 | Message::Invocation(id, registration_id, ref details, ref args, ref kwargs) => { 116 | serialize_with_args!(args, kwargs, serializer, 68, id, registration_id, details) 117 | } 118 | Message::Yield(id, ref options, ref args, ref kwargs) => { 119 | serialize_with_args!(args, kwargs, serializer, 70, id, options) 120 | } 121 | Message::Result(id, ref details, ref args, ref kwargs) => { 122 | serialize_with_args!(args, kwargs, serializer, 50, id, details) 123 | } 124 | } 125 | } 126 | } 127 | 128 | impl<'de> serde::Deserialize<'de> for Message { 129 | fn deserialize(deserializer: D) -> Result 130 | where 131 | D: serde::Deserializer<'de>, 132 | { 133 | deserializer.deserialize_any(MessageVisitor) 134 | } 135 | } 136 | 137 | struct MessageVisitor; 138 | 139 | impl MessageVisitor { 140 | fn visit_hello<'de, V>(&self, mut visitor: V) -> Result 141 | where 142 | V: serde::de::SeqAccess<'de>, 143 | { 144 | let uri = try_or!( 145 | visitor.next_element(), 146 | "Hello message ended before realm uri" 147 | ); 148 | let details = try_or!( 149 | visitor.next_element(), 150 | "Hello message ended before details dict" 151 | ); 152 | Ok(Message::Hello(uri, details)) 153 | } 154 | 155 | fn visit_welcome<'de, V>(&self, mut visitor: V) -> Result 156 | where 157 | V: serde::de::SeqAccess<'de>, 158 | { 159 | let session = try_or!( 160 | visitor.next_element(), 161 | "Welcome message ended before session id" 162 | ); 163 | let details = try_or!( 164 | visitor.next_element(), 165 | "Welcome message ended before details dict" 166 | ); 167 | Ok(Message::Welcome(session, details)) 168 | } 169 | 170 | fn visit_abort<'de, V>(&self, mut visitor: V) -> Result 171 | where 172 | V: serde::de::SeqAccess<'de>, 173 | { 174 | let details = try_or!( 175 | visitor.next_element(), 176 | "Abort message ended before details dict" 177 | ); 178 | let reason = try_or!( 179 | visitor.next_element(), 180 | "Abort message ended before reason uri" 181 | ); 182 | Ok(Message::Abort(details, reason)) 183 | } 184 | 185 | fn visit_goodbye<'de, V>(&self, mut visitor: V) -> Result 186 | where 187 | V: serde::de::SeqAccess<'de>, 188 | { 189 | let details = try_or!( 190 | visitor.next_element(), 191 | "Goodbye message ended before details dict" 192 | ); 193 | let reason = try_or!( 194 | visitor.next_element(), 195 | "Goodbye message ended before reason uri" 196 | ); 197 | Ok(Message::Goodbye(details, reason)) 198 | } 199 | 200 | fn visit_error<'de, V>(&self, mut visitor: V) -> Result 201 | where 202 | V: serde::de::SeqAccess<'de>, 203 | { 204 | let message_type = try_or!( 205 | visitor.next_element(), 206 | "Error message ended before message type" 207 | ); 208 | let id = try_or!( 209 | visitor.next_element(), 210 | "Error message ended before session id" 211 | ); 212 | let details = try_or!( 213 | visitor.next_element(), 214 | "Error message ended before details dict" 215 | ); 216 | let reason = try_or!( 217 | visitor.next_element(), 218 | "Error message ended before reason uri" 219 | ); 220 | let args = try!(visitor.next_element()); 221 | let kwargs = try!(visitor.next_element()); 222 | Ok(Message::Error( 223 | message_type, 224 | id, 225 | details, 226 | reason, 227 | args, 228 | kwargs, 229 | )) 230 | } 231 | 232 | fn visit_subscribe<'de, V>(&self, mut visitor: V) -> Result 233 | where 234 | V: serde::de::SeqAccess<'de>, 235 | { 236 | let request = try_or!( 237 | visitor.next_element(), 238 | "Subscribe message ended before request id" 239 | ); 240 | let options = try_or!( 241 | visitor.next_element(), 242 | "Subscribe message ended before options dict" 243 | ); 244 | let topic = try_or!( 245 | visitor.next_element(), 246 | "Subscribe message ended before topic uri" 247 | ); 248 | Ok(Message::Subscribe(request, options, topic)) 249 | } 250 | 251 | fn visit_subscribed<'de, V>(&self, mut visitor: V) -> Result 252 | where 253 | V: serde::de::SeqAccess<'de>, 254 | { 255 | let request = try_or!( 256 | visitor.next_element(), 257 | "Subscribed message ended before request id" 258 | ); 259 | let subscription = try_or!( 260 | visitor.next_element(), 261 | "Subscribed message ended before subscription id" 262 | ); 263 | Ok(Message::Subscribed(request, subscription)) 264 | } 265 | 266 | fn visit_unsubscribe<'de, V>(&self, mut visitor: V) -> Result 267 | where 268 | V: serde::de::SeqAccess<'de>, 269 | { 270 | let request = try_or!( 271 | visitor.next_element(), 272 | "Unsubscribe message ended before request id" 273 | ); 274 | let subscription = try_or!( 275 | visitor.next_element(), 276 | "Unsubscribe message ended before subscription id" 277 | ); 278 | Ok(Message::Unsubscribe(request, subscription)) 279 | } 280 | 281 | fn visit_unsubscribed<'de, V>(&self, mut visitor: V) -> Result 282 | where 283 | V: serde::de::SeqAccess<'de>, 284 | { 285 | let request = try_or!( 286 | visitor.next_element(), 287 | "Unsubscribed message ended before request id" 288 | ); 289 | Ok(Message::Unsubscribed(request)) 290 | } 291 | 292 | fn visit_publish<'de, V>(&self, mut visitor: V) -> Result 293 | where 294 | V: serde::de::SeqAccess<'de>, 295 | { 296 | let id = try_or!( 297 | visitor.next_element(), 298 | "Publish message ended before session id" 299 | ); 300 | let details = try_or!( 301 | visitor.next_element(), 302 | "Publish message ended before details dict" 303 | ); 304 | let topic = try_or!( 305 | visitor.next_element(), 306 | "Publish message ended before topic uri" 307 | ); 308 | let args = try!(visitor.next_element()); 309 | let kwargs = try!(visitor.next_element()); 310 | Ok(Message::Publish(id, details, topic, args, kwargs)) 311 | } 312 | 313 | fn visit_published<'de, V>(&self, mut visitor: V) -> Result 314 | where 315 | V: serde::de::SeqAccess<'de>, 316 | { 317 | let request = try_or!( 318 | visitor.next_element(), 319 | "Published message ended before request id" 320 | ); 321 | let publication = try_or!( 322 | visitor.next_element(), 323 | "Published message ended before publication id" 324 | ); 325 | Ok(Message::Published(request, publication)) 326 | } 327 | 328 | fn visit_event<'de, V>(&self, mut visitor: V) -> Result 329 | where 330 | V: serde::de::SeqAccess<'de>, 331 | { 332 | let subscription_id = try_or!( 333 | visitor.next_element(), 334 | "Event message ended before session subscription id" 335 | ); 336 | let publication_id = try_or!( 337 | visitor.next_element(), 338 | "Event message ended before publication id" 339 | ); 340 | let details = try_or!( 341 | visitor.next_element(), 342 | "Event message ended before details dict" 343 | ); 344 | let args = try!(visitor.next_element()); 345 | let kwargs = try!(visitor.next_element()); 346 | Ok(Message::Event( 347 | subscription_id, 348 | publication_id, 349 | details, 350 | args, 351 | kwargs, 352 | )) 353 | } 354 | 355 | fn visit_register<'de, V>(&self, mut visitor: V) -> Result 356 | where 357 | V: serde::de::SeqAccess<'de>, 358 | { 359 | let request = try_or!( 360 | visitor.next_element(), 361 | "Register message ended before request id" 362 | ); 363 | let options = try_or!( 364 | visitor.next_element(), 365 | "Register message ended before request options" 366 | ); 367 | let procedure = try_or!( 368 | visitor.next_element(), 369 | "Register message ended before procedure" 370 | ); 371 | Ok(Message::Register(request, options, procedure)) 372 | } 373 | 374 | fn visit_registered<'de, V>(&self, mut visitor: V) -> Result 375 | where 376 | V: serde::de::SeqAccess<'de>, 377 | { 378 | let request = try_or!( 379 | visitor.next_element(), 380 | "Registered message ended before request id" 381 | ); 382 | let registration_id = try_or!( 383 | visitor.next_element(), 384 | "Registered message ended before registration id" 385 | ); 386 | Ok(Message::Registered(request, registration_id)) 387 | } 388 | 389 | fn visit_unregister<'de, V>(&self, mut visitor: V) -> Result 390 | where 391 | V: serde::de::SeqAccess<'de>, 392 | { 393 | let request = try_or!( 394 | visitor.next_element(), 395 | "Registered message ended before request id" 396 | ); 397 | let registration_id = try_or!( 398 | visitor.next_element(), 399 | "Registered message ended before registration id" 400 | ); 401 | Ok(Message::Unregister(request, registration_id)) 402 | } 403 | 404 | fn visit_unregistered<'de, V>(&self, mut visitor: V) -> Result 405 | where 406 | V: serde::de::SeqAccess<'de>, 407 | { 408 | let request = try_or!( 409 | visitor.next_element(), 410 | "Registered message ended before request id" 411 | ); 412 | Ok(Message::Unregistered(request)) 413 | } 414 | 415 | fn visit_call<'de, V>(&self, mut visitor: V) -> Result 416 | where 417 | V: serde::de::SeqAccess<'de>, 418 | { 419 | let id = try_or!( 420 | visitor.next_element(), 421 | "Call message ended before session id" 422 | ); 423 | let options = try_or!( 424 | visitor.next_element(), 425 | "Call message ended before options dict" 426 | ); 427 | let topic = try_or!( 428 | visitor.next_element(), 429 | "Call message ended before procedure uri" 430 | ); 431 | let args = try!(visitor.next_element()); 432 | let kwargs = try!(visitor.next_element()); 433 | Ok(Message::Call(id, options, topic, args, kwargs)) 434 | } 435 | 436 | fn visit_invocation<'de, V>(&self, mut visitor: V) -> Result 437 | where 438 | V: serde::de::SeqAccess<'de>, 439 | { 440 | let id = try_or!( 441 | visitor.next_element(), 442 | "Invocation message ended before session id" 443 | ); 444 | let registration_id = try_or!( 445 | visitor.next_element(), 446 | "Invocation message ended before registration id" 447 | ); 448 | let details = try_or!( 449 | visitor.next_element(), 450 | "Invocation message ended before details dict" 451 | ); 452 | let args = try!(visitor.next_element()); 453 | let kwargs = try!(visitor.next_element()); 454 | Ok(Message::Invocation( 455 | id, 456 | registration_id, 457 | details, 458 | args, 459 | kwargs, 460 | )) 461 | } 462 | 463 | fn visit_yield<'de, V>(&self, mut visitor: V) -> Result 464 | where 465 | V: serde::de::SeqAccess<'de>, 466 | { 467 | let id = try_or!( 468 | visitor.next_element(), 469 | "Yield message ended before session id" 470 | ); 471 | let options = try_or!( 472 | visitor.next_element(), 473 | "Yield message ended before options dict" 474 | ); 475 | let args = try!(visitor.next_element()); 476 | let kwargs = try!(visitor.next_element()); 477 | Ok(Message::Yield(id, options, args, kwargs)) 478 | } 479 | 480 | fn visit_result<'de, V>(&self, mut visitor: V) -> Result 481 | where 482 | V: serde::de::SeqAccess<'de>, 483 | { 484 | let id = try_or!( 485 | visitor.next_element(), 486 | "Result message ended before session id" 487 | ); 488 | let details = try_or!( 489 | visitor.next_element(), 490 | "Result message ended before details dict" 491 | ); 492 | let args = try!(visitor.next_element()); 493 | let kwargs = try!(visitor.next_element()); 494 | Ok(Message::Result(id, details, args, kwargs)) 495 | } 496 | } 497 | 498 | impl<'de> serde::de::Visitor<'de> for MessageVisitor { 499 | type Value = Message; 500 | 501 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 502 | formatter.write_str("a message") 503 | } 504 | 505 | fn visit_seq(self, mut visitor: V) -> Result 506 | where 507 | V: serde::de::SeqAccess<'de>, 508 | { 509 | let message_type: u64 = try_or!(visitor.next_element(), "No message type found"); 510 | match message_type { 511 | 1 => self.visit_hello(visitor), 512 | 2 => self.visit_welcome(visitor), 513 | 3 => self.visit_abort(visitor), 514 | 6 => self.visit_goodbye(visitor), 515 | 8 => self.visit_error(visitor), 516 | 32 => self.visit_subscribe(visitor), 517 | 33 => self.visit_subscribed(visitor), 518 | 34 => self.visit_unsubscribe(visitor), 519 | 35 => self.visit_unsubscribed(visitor), 520 | 16 => self.visit_publish(visitor), 521 | 17 => self.visit_published(visitor), 522 | 36 => self.visit_event(visitor), 523 | 64 => self.visit_register(visitor), 524 | 65 => self.visit_registered(visitor), 525 | 66 => self.visit_unregister(visitor), 526 | 67 => self.visit_unregistered(visitor), 527 | 48 => self.visit_call(visitor), 528 | 68 => self.visit_invocation(visitor), 529 | 70 => self.visit_yield(visitor), 530 | 50 => self.visit_result(visitor), 531 | _ => Err(serde::de::Error::custom("Unknown message type")), 532 | } 533 | } 534 | } 535 | 536 | #[cfg(test)] 537 | mod test { 538 | use super::types::{CallOptions, ClientRoles, ErrorDetails, ErrorType, EventDetails, 539 | HelloDetails, InvocationDetails, PublishOptions, Reason, RegisterOptions, 540 | ResultDetails, RouterRoles, SubscribeOptions, Value, WelcomeDetails, 541 | YieldOptions, URI}; 542 | use super::Message; 543 | use rmp_serde::Deserializer as RMPDeserializer; 544 | use rmp_serde::Serializer; 545 | use serde::{Deserialize, Serialize}; 546 | use serde_json; 547 | use std::collections::HashMap; 548 | use utils::StructMapWriter; 549 | 550 | macro_rules! two_way_test { 551 | ($message:expr, $s:expr) => {{ 552 | let message = $message; 553 | assert_eq!(serde_json::to_string(&message).unwrap(), $s); 554 | assert_eq!(serde_json::from_str::($s).unwrap(), message); 555 | let mut buf: Vec = Vec::new(); 556 | message 557 | .serialize(&mut Serializer::with(&mut buf, StructMapWriter)) 558 | .unwrap(); 559 | let mut de = RMPDeserializer::new(&buf[..]); 560 | let new_message: Message = Deserialize::deserialize(&mut de).unwrap(); 561 | assert_eq!(new_message, message); 562 | }}; 563 | } 564 | 565 | #[test] 566 | fn serialize_hello() { 567 | two_way_test!( 568 | Message::Hello(URI::new("ca.dal.wamp.test"), HelloDetails::new(ClientRoles::new_basic())), 569 | "[1,\"ca.dal.wamp.test\",{\"roles\":{\"publisher\":{\"features\":{}},\"subscriber\":{\"features\":{}},\"caller\":{\"features\":{}},\"callee\":{\"features\":{}}}}]" 570 | ); 571 | two_way_test!( 572 | Message::Hello(URI::new("ca.dal.wamp.test"), HelloDetails::new_with_agent(ClientRoles::new(), "dal_wamp")), 573 | "[1,\"ca.dal.wamp.test\",{\"agent\":\"dal_wamp\",\"roles\":{\"publisher\":{\"features\":{}},\"subscriber\":{\"features\":{\"pattern_based_subscription\":true}},\"caller\":{\"features\":{}},\"callee\":{\"features\":{}}}}]" 574 | ) 575 | } 576 | 577 | #[test] 578 | fn serialize_welcome() { 579 | two_way_test!( 580 | Message::Welcome(493782, WelcomeDetails::new(RouterRoles::new_basic())), 581 | "[2,493782,{\"roles\":{\"dealer\":{},\"broker\":{}}}]" 582 | ); 583 | two_way_test!( 584 | Message::Welcome(493782, WelcomeDetails::new_with_agent(RouterRoles::new(), "dal_wamp")), 585 | "[2,493782,{\"agent\":\"dal_wamp\",\"roles\":{\"dealer\":{\"features\":{\"pattern_based_registration\":true}},\"broker\":{\"features\":{\"pattern_based_subscription\":true}}}}]" 586 | ); 587 | } 588 | 589 | #[test] 590 | fn serialize_abort() { 591 | two_way_test!( 592 | Message::Abort(ErrorDetails::new(), Reason::NoSuchRealm), 593 | "[3,{},\"wamp.error.no_such_realm\"]" 594 | ); 595 | two_way_test!( 596 | Message::Abort( 597 | ErrorDetails::new_with_message("The realm does not exist"), 598 | Reason::NoSuchRealm 599 | ), 600 | "[3,{\"message\":\"The realm does not exist\"},\"wamp.error.no_such_realm\"]" 601 | ); 602 | } 603 | 604 | #[test] 605 | fn serialize_goodbye() { 606 | two_way_test!( 607 | Message::Goodbye(ErrorDetails::new(), Reason::GoodbyeAndOut), 608 | "[6,{},\"wamp.error.goodbye_and_out\"]" 609 | ); 610 | two_way_test!( 611 | Message::Goodbye( 612 | ErrorDetails::new_with_message("The host is shutting down now"), 613 | Reason::SystemShutdown 614 | ), 615 | "[6,{\"message\":\"The host is shutting down now\"},\"wamp.error.system_shutdown\"]" 616 | ); 617 | } 618 | 619 | #[test] 620 | fn serialize_error() { 621 | two_way_test!( 622 | Message::Error( 623 | ErrorType::Subscribe, 624 | 713845233, 625 | HashMap::new(), 626 | Reason::NotAuthorized, 627 | None, 628 | None 629 | ), 630 | "[8,32,713845233,{},\"wamp.error.not_authorized\"]" 631 | ); 632 | 633 | two_way_test!( 634 | Message::Error( 635 | ErrorType::Unsubscribe, 636 | 3746383, 637 | HashMap::new(), 638 | Reason::InvalidURI, 639 | Some(Vec::new()), 640 | None 641 | ), 642 | "[8,34,3746383,{},\"wamp.error.invalid_uri\",[]]" 643 | ); 644 | 645 | two_way_test!( 646 | Message::Error( 647 | ErrorType::Register, 648 | 8534533, 649 | HashMap::new(), 650 | Reason::InvalidArgument, 651 | Some(Vec::new()), 652 | Some(HashMap::new()) 653 | ), 654 | "[8,64,8534533,{},\"wamp.error.invalid_argument\",[],{}]" 655 | ); 656 | } 657 | 658 | #[test] 659 | fn serialize_subscribe() { 660 | two_way_test!( 661 | Message::Subscribe( 662 | 58944, 663 | SubscribeOptions::new(), 664 | URI::new("ca.dal.test.the_sub") 665 | ), 666 | "[32,58944,{},\"ca.dal.test.the_sub\"]" 667 | ) 668 | } 669 | 670 | #[test] 671 | fn serialize_subscribed() { 672 | two_way_test!(Message::Subscribed(47853, 48975938), "[33,47853,48975938]") 673 | } 674 | 675 | #[test] 676 | fn serialize_unsubscribe() { 677 | two_way_test!(Message::Unsubscribe(754, 8763), "[34,754,8763]") 678 | } 679 | 680 | #[test] 681 | fn serialize_unsubscribed() { 682 | two_way_test!(Message::Unsubscribed(675343), "[35,675343]") 683 | } 684 | 685 | #[test] 686 | fn serialize_publish() { 687 | two_way_test!( 688 | Message::Publish( 689 | 453453, 690 | PublishOptions::new(false), 691 | URI::new("ca.dal.test.topic1"), 692 | None, 693 | None 694 | ), 695 | "[16,453453,{},\"ca.dal.test.topic1\"]" 696 | ); 697 | 698 | two_way_test!( 699 | Message::Publish( 700 | 23934583, 701 | PublishOptions::new(true), 702 | URI::new("ca.dal.test.topic2"), 703 | Some(vec![Value::String("a value".to_string())]), 704 | None 705 | ), 706 | "[16,23934583,{\"acknowledge\":true},\"ca.dal.test.topic2\",[\"a value\"]]" 707 | ); 708 | let mut kwargs = HashMap::new(); 709 | kwargs.insert("key1".to_string(), Value::List(vec![Value::Integer(-5)])); 710 | two_way_test!( 711 | Message::Publish( 712 | 3243542, 713 | PublishOptions::new(true), 714 | URI::new("ca.dal.test.topic3"), 715 | Some(Vec::new()), 716 | Some(kwargs) 717 | ), 718 | "[16,3243542,{\"acknowledge\":true},\"ca.dal.test.topic3\",[],{\"key1\":[-5]}]" 719 | ) 720 | } 721 | 722 | #[test] 723 | fn serialize_published() { 724 | two_way_test!(Message::Published(23443, 564564), "[17,23443,564564]") 725 | } 726 | 727 | #[test] 728 | fn serialize_event() { 729 | two_way_test!( 730 | Message::Event(4353453, 298173, EventDetails::new(), None, None), 731 | "[36,4353453,298173,{}]" 732 | ); 733 | 734 | two_way_test!( 735 | Message::Event( 736 | 764346, 737 | 3895494, 738 | EventDetails::new(), 739 | Some(vec![Value::String("a value".to_string())]), 740 | None 741 | ), 742 | "[36,764346,3895494,{},[\"a value\"]]" 743 | ); 744 | let mut kwargs = HashMap::new(); 745 | kwargs.insert("key1".to_string(), Value::List(vec![Value::Integer(-5)])); 746 | two_way_test!( 747 | Message::Event( 748 | 65675, 749 | 587495, 750 | EventDetails::new(), 751 | Some(Vec::new()), 752 | Some(kwargs) 753 | ), 754 | "[36,65675,587495,{},[],{\"key1\":[-5]}]" 755 | ) 756 | } 757 | 758 | #[test] 759 | fn serialize_register() { 760 | two_way_test!( 761 | Message::Register(25349185, RegisterOptions::new(), URI::new("ca.test.proc")), 762 | "[64,25349185,{},\"ca.test.proc\"]" 763 | ); 764 | } 765 | 766 | #[test] 767 | fn serialize_registered() { 768 | two_way_test!( 769 | Message::Registered(25349185, 2103333224), 770 | "[65,25349185,2103333224]" 771 | ); 772 | } 773 | 774 | #[test] 775 | fn serialize_unregister() { 776 | two_way_test!( 777 | Message::Unregister(788923562, 2103333224), 778 | "[66,788923562,2103333224]" 779 | ); 780 | } 781 | 782 | #[test] 783 | fn serialize_unregistered() { 784 | two_way_test!(Message::Unregistered(788923562), "[67,788923562]"); 785 | } 786 | 787 | #[test] 788 | fn serialize_call() { 789 | two_way_test!( 790 | Message::Call( 791 | 7814135, 792 | CallOptions::new(), 793 | URI::new("com.myapp.ping"), 794 | None, 795 | None 796 | ), 797 | "[48,7814135,{},\"com.myapp.ping\"]" 798 | ); 799 | 800 | two_way_test!( 801 | Message::Call( 802 | 764346, 803 | CallOptions::new(), 804 | URI::new("com.myapp.echo"), 805 | Some(vec![Value::String("a value".to_string())]), 806 | None 807 | ), 808 | "[48,764346,{},\"com.myapp.echo\",[\"a value\"]]" 809 | ); 810 | let mut kwargs = HashMap::new(); 811 | kwargs.insert( 812 | "key1".to_string(), 813 | Value::List(vec![Value::UnsignedInteger(5)]), 814 | ); 815 | two_way_test!( 816 | Message::Call( 817 | 764346, 818 | CallOptions::new(), 819 | URI::new("com.myapp.compute"), 820 | Some(Vec::new()), 821 | Some(kwargs) 822 | ), 823 | "[48,764346,{},\"com.myapp.compute\",[],{\"key1\":[5]}]" 824 | ) 825 | } 826 | 827 | #[test] 828 | fn serialize_invocation() { 829 | // two_way_test!( 830 | // Message::Invocation(7814135, 9823526, InvocationDetails::new(), None, None), 831 | // "[68,7814135,9823526,{}]" 832 | // ); 833 | 834 | two_way_test!( 835 | Message::Invocation( 836 | 764346, 837 | 9823526, 838 | InvocationDetails::new(), 839 | Some(vec![Value::String("a value".to_string())]), 840 | None 841 | ), 842 | "[68,764346,9823526,{},[\"a value\"]]" 843 | ); 844 | let mut kwargs = HashMap::new(); 845 | kwargs.insert( 846 | "key1".to_string(), 847 | Value::List(vec![Value::UnsignedInteger(5)]), 848 | ); 849 | two_way_test!( 850 | Message::Invocation( 851 | 764346, 852 | 9823526, 853 | InvocationDetails::new(), 854 | Some(Vec::new()), 855 | Some(kwargs) 856 | ), 857 | "[68,764346,9823526,{},[],{\"key1\":[5]}]" 858 | ) 859 | } 860 | 861 | #[test] 862 | fn serialize_yield() { 863 | two_way_test!( 864 | Message::Yield(6131533, YieldOptions::new(), None, None), 865 | "[70,6131533,{}]" 866 | ); 867 | 868 | two_way_test!( 869 | Message::Yield( 870 | 6131533, 871 | YieldOptions::new(), 872 | Some(vec![Value::String("a value".to_string())]), 873 | None 874 | ), 875 | "[70,6131533,{},[\"a value\"]]" 876 | ); 877 | let mut kwargs = HashMap::new(); 878 | kwargs.insert( 879 | "key1".to_string(), 880 | Value::List(vec![Value::UnsignedInteger(5)]), 881 | ); 882 | two_way_test!( 883 | Message::Yield(6131533, YieldOptions::new(), Some(Vec::new()), Some(kwargs)), 884 | "[70,6131533,{},[],{\"key1\":[5]}]" 885 | ) 886 | } 887 | 888 | #[test] 889 | fn serialize_result() { 890 | two_way_test!( 891 | Message::Result(7814135, ResultDetails::new(), None, None), 892 | "[50,7814135,{}]" 893 | ); 894 | 895 | two_way_test!( 896 | Message::Result( 897 | 764346, 898 | ResultDetails::new(), 899 | Some(vec![Value::String("a value".to_string())]), 900 | None 901 | ), 902 | "[50,764346,{},[\"a value\"]]" 903 | ); 904 | let mut kwargs = HashMap::new(); 905 | kwargs.insert("key1".to_string(), Value::List(vec![Value::Float(8.6)])); 906 | two_way_test!( 907 | Message::Result(764346, ResultDetails::new(), Some(Vec::new()), Some(kwargs)), 908 | "[50,764346,{},[],{\"key1\":[8.6]}]" 909 | ) 910 | } 911 | 912 | } 913 | -------------------------------------------------------------------------------- /src/messages/types/error.rs: -------------------------------------------------------------------------------- 1 | use super::{Dict, List}; 2 | use serde; 3 | use std::fmt; 4 | use URI; 5 | 6 | #[derive(Hash, Eq, PartialEq, Debug)] 7 | pub enum Reason { 8 | InvalidURI, 9 | NoSuchProcedure, 10 | ProcedureAlreadyExists, 11 | NoSuchRegistration, 12 | NoSuchSubscription, 13 | InvalidArgument, 14 | SystemShutdown, 15 | CloseRealm, 16 | GoodbyeAndOut, 17 | NotAuthorized, 18 | AuthorizationFailed, 19 | NoSuchRealm, 20 | NoSuchRole, 21 | Cancelled, 22 | OptionNotAllowed, 23 | NoEligibleCallee, 24 | OptionDisallowedDiscloseMe, 25 | NetworkFailure, 26 | NormalClose, 27 | CustomReason(URI), 28 | } 29 | 30 | #[derive(Debug)] 31 | pub struct CallError { 32 | reason: Reason, 33 | args: Option, 34 | kwargs: Option, 35 | } 36 | 37 | #[derive(Hash, Eq, PartialEq, Debug)] 38 | pub enum ErrorType { 39 | Subscribe, 40 | Unsubscribe, 41 | Publish, 42 | Register, 43 | Unregister, 44 | Invocation, 45 | Call, 46 | } 47 | 48 | impl CallError { 49 | #[inline] 50 | pub fn new(reason: Reason, args: Option, kwargs: Option) -> CallError { 51 | CallError { 52 | reason: reason, 53 | args: args, 54 | kwargs: kwargs, 55 | } 56 | } 57 | 58 | pub fn into_tuple(self) -> (Reason, Option, Option) { 59 | (self.reason, self.args, self.kwargs) 60 | } 61 | 62 | #[inline] 63 | pub fn get_reason(&self) -> &Reason { 64 | &self.reason 65 | } 66 | 67 | #[inline] 68 | pub fn get_args(&self) -> &Option { 69 | &self.args 70 | } 71 | 72 | #[inline] 73 | pub fn get_kwargs(&self) -> &Option { 74 | &self.kwargs 75 | } 76 | } 77 | 78 | struct ErrorTypeVisitor; 79 | struct ReasonVisitor; 80 | 81 | impl Reason { 82 | #[inline] 83 | fn get_string(&self) -> &str { 84 | match *self { 85 | Reason::InvalidURI => "wamp.error.invalid_uri", 86 | Reason::NoSuchProcedure => "wamp.error.no_such_procedure", 87 | Reason::ProcedureAlreadyExists => "wamp.error.procedure_already_exists", 88 | Reason::NoSuchRegistration => "wamp.error.no_such_registration", 89 | Reason::NoSuchSubscription => "wamp.error.no_such_subscription", 90 | Reason::InvalidArgument => "wamp.error.invalid_argument", 91 | Reason::SystemShutdown => "wamp.error.system_shutdown", 92 | Reason::CloseRealm => "wamp.error.close_realm", 93 | Reason::GoodbyeAndOut => "wamp.error.goodbye_and_out", 94 | Reason::NotAuthorized => "wamp.error.not_authorized", 95 | Reason::AuthorizationFailed => "wamp.error.authorization_failed", 96 | Reason::NoSuchRealm => "wamp.error.no_such_realm", 97 | Reason::NoSuchRole => "wamp.error.no_such_role", 98 | Reason::Cancelled => "wamp.error.cancelled", 99 | Reason::OptionNotAllowed => "wamp.error.option_not_allowed", 100 | Reason::NoEligibleCallee => "wamp.error.no_eligible_callee", 101 | Reason::OptionDisallowedDiscloseMe => "wamp.error.option-disallowed.disclose_me", 102 | Reason::NetworkFailure => "wamp.error.network_failure", 103 | Reason::NormalClose => "wamp.close.normal", 104 | Reason::CustomReason(ref reason) => &reason.uri, 105 | } 106 | } 107 | } 108 | 109 | impl fmt::Display for Reason { 110 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 111 | write!(f, "{}", self.get_string()) 112 | } 113 | } 114 | 115 | /*------------------------- 116 | Reason 117 | -------------------------*/ 118 | 119 | impl serde::Serialize for Reason { 120 | fn serialize(&self, serializer: S) -> Result 121 | where 122 | S: serde::Serializer, 123 | { 124 | serializer.serialize_str(self.get_string()) 125 | } 126 | } 127 | 128 | impl<'de> serde::Deserialize<'de> for Reason { 129 | fn deserialize(deserializer: D) -> Result 130 | where 131 | D: serde::Deserializer<'de>, 132 | { 133 | deserializer.deserialize_str(ReasonVisitor) 134 | } 135 | } 136 | 137 | impl<'de> serde::de::Visitor<'de> for ReasonVisitor { 138 | type Value = Reason; 139 | 140 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 141 | formatter.write_str("error reason uri") 142 | } 143 | 144 | #[inline] 145 | fn visit_str(self, value: &str) -> Result 146 | where 147 | E: serde::de::Error, 148 | { 149 | match value { 150 | "wamp.error.invalid_uri" => Ok(Reason::InvalidURI), 151 | "wamp.error.no_such_procedure" => Ok(Reason::NoSuchProcedure), 152 | "wamp.error.procedure_already_exists" => Ok(Reason::ProcedureAlreadyExists), 153 | "wamp.error.no_such_registration" => Ok(Reason::NoSuchRegistration), 154 | "wamp.error.no_such_subscription" => Ok(Reason::NoSuchSubscription), 155 | "wamp.error.invalid_argument" => Ok(Reason::InvalidArgument), 156 | "wamp.error.system_shutdown" => Ok(Reason::SystemShutdown), 157 | "wamp.error.close_realm" => Ok(Reason::CloseRealm), 158 | "wamp.error.goodbye_and_out" => Ok(Reason::GoodbyeAndOut), 159 | "wamp.error.not_authorized" => Ok(Reason::NotAuthorized), 160 | "wamp.error.authorization_failed" => Ok(Reason::AuthorizationFailed), 161 | "wamp.error.no_such_realm" => Ok(Reason::NoSuchRealm), 162 | "wamp.error.no_such_role" => Ok(Reason::NoSuchRole), 163 | "wamp.error.cancelled" => Ok(Reason::Cancelled), 164 | "wamp.error.option_not_allowed" => Ok(Reason::OptionNotAllowed), 165 | "wamp.error.no_eligible_callee" => Ok(Reason::NoEligibleCallee), 166 | "wamp.error.option-disallowed.disclose_me" => Ok(Reason::OptionDisallowedDiscloseMe), 167 | "wamp.error.network_failure" => Ok(Reason::NetworkFailure), 168 | "wamp.close.normal" => Ok(Reason::NormalClose), 169 | x => Ok(Reason::CustomReason(URI::new(x))), 170 | } 171 | } 172 | } 173 | 174 | /*------------------------- 175 | ErrorType 176 | -------------------------*/ 177 | 178 | impl serde::Serialize for ErrorType { 179 | fn serialize(&self, serializer: S) -> Result 180 | where 181 | S: serde::Serializer, 182 | { 183 | let ser_int = match *self { 184 | ErrorType::Subscribe => 32, 185 | ErrorType::Unsubscribe => 34, 186 | ErrorType::Publish => 16, 187 | ErrorType::Register => 64, 188 | ErrorType::Unregister => 66, 189 | ErrorType::Invocation => 68, 190 | ErrorType::Call => 48, 191 | }; 192 | serializer.serialize_u64(ser_int) 193 | } 194 | } 195 | 196 | impl<'de> serde::Deserialize<'de> for ErrorType { 197 | fn deserialize(deserializer: D) -> Result 198 | where 199 | D: serde::Deserializer<'de>, 200 | { 201 | deserializer.deserialize_u64(ErrorTypeVisitor) 202 | } 203 | } 204 | 205 | impl<'de> serde::de::Visitor<'de> for ErrorTypeVisitor { 206 | type Value = ErrorType; 207 | 208 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 209 | formatter.write_str("Integer representing an error type") 210 | } 211 | 212 | #[inline] 213 | fn visit_u64(self, value: u64) -> Result 214 | where 215 | E: serde::de::Error, 216 | { 217 | match value { 218 | 32 => Ok(ErrorType::Subscribe), 219 | 34 => Ok(ErrorType::Unsubscribe), 220 | 16 => Ok(ErrorType::Publish), 221 | 64 => Ok(ErrorType::Register), 222 | 66 => Ok(ErrorType::Unregister), 223 | 68 => Ok(ErrorType::Invocation), 224 | 48 => Ok(ErrorType::Call), 225 | x => Err(serde::de::Error::custom(format!( 226 | "Invalid message error type: {}", 227 | x 228 | ))), 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/messages/types/mod.rs: -------------------------------------------------------------------------------- 1 | mod error; 2 | mod options; 3 | mod roles; 4 | mod value; 5 | 6 | use serde; 7 | use std::fmt; 8 | 9 | pub use messages::types::error::*; 10 | pub use messages::types::options::*; 11 | pub use messages::types::roles::*; 12 | pub use messages::types::value::*; 13 | 14 | fn is_not(b: &bool) -> bool { 15 | !*b 16 | } 17 | 18 | /************************** 19 | Structs 20 | **************************/ 21 | 22 | /// The policies that can be used for matching a uri pattern. 23 | #[derive(PartialEq, Debug, Clone, Copy)] 24 | pub enum MatchingPolicy { 25 | /// The given pattern matches any URI that has it as a prefix 26 | Prefix, 27 | /// The given pattern contains at least one 'wildcard' segment which can match any segment at the same location 28 | Wildcard, 29 | /// The given pattern only matches URIs that are identical. 30 | Strict, 31 | } 32 | 33 | /// The policies that dictate how invocations are distributed amongst shared registrations 34 | #[derive(PartialEq, Debug, Clone, Copy)] 35 | pub enum InvocationPolicy { 36 | // Only one reigistration per uri (the default) 37 | Single, 38 | // Callee selcted sequentially from the list of registrants 39 | RoundRobin, 40 | // Callee selcted randomly from the list of registrants 41 | Random, 42 | // First callee (in orer of registration) is called 43 | First, 44 | // Last callee (in order of registration( is called 45 | Last, 46 | } 47 | 48 | /************************** 49 | Visitors 50 | **************************/ 51 | 52 | struct MatchingPolicyVisitor; 53 | struct InvocationPolicyVisitor; 54 | 55 | impl MatchingPolicy { 56 | #[inline] 57 | fn is_strict(&self) -> bool { 58 | self == &MatchingPolicy::Strict 59 | } 60 | } 61 | 62 | impl InvocationPolicy { 63 | #[inline] 64 | fn is_single(&self) -> bool { 65 | self == &InvocationPolicy::Single 66 | } 67 | } 68 | 69 | impl Default for MatchingPolicy { 70 | #[inline] 71 | fn default() -> MatchingPolicy { 72 | MatchingPolicy::Strict 73 | } 74 | } 75 | 76 | impl Default for InvocationPolicy { 77 | #[inline] 78 | fn default() -> InvocationPolicy { 79 | InvocationPolicy::Single 80 | } 81 | } 82 | 83 | /*------------------------- 84 | MatchingPolicy 85 | -------------------------*/ 86 | 87 | impl serde::Serialize for MatchingPolicy { 88 | fn serialize(&self, serializer: S) -> Result 89 | where 90 | S: serde::Serializer, 91 | { 92 | let ser_str = match *self { 93 | MatchingPolicy::Prefix => "prefix", 94 | MatchingPolicy::Wildcard => "wildcard", 95 | MatchingPolicy::Strict => "", 96 | }; 97 | serializer.serialize_str(ser_str) 98 | } 99 | } 100 | 101 | impl<'de> serde::Deserialize<'de> for MatchingPolicy { 102 | fn deserialize(deserializer: D) -> Result 103 | where 104 | D: serde::Deserializer<'de>, 105 | { 106 | deserializer.deserialize_str(MatchingPolicyVisitor) 107 | } 108 | } 109 | 110 | impl<'de> serde::de::Visitor<'de> for MatchingPolicyVisitor { 111 | type Value = MatchingPolicy; 112 | 113 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 114 | formatter.write_str("matching policy for registration") 115 | } 116 | 117 | #[inline] 118 | fn visit_str(self, value: &str) -> Result 119 | where 120 | E: serde::de::Error, 121 | { 122 | match value { 123 | "prefix" => Ok(MatchingPolicy::Prefix), 124 | "wildcard" => Ok(MatchingPolicy::Wildcard), 125 | x => Err(serde::de::Error::custom(format!( 126 | "Invalid matching policy: {}", 127 | x 128 | ))), 129 | } 130 | } 131 | } 132 | 133 | impl serde::Serialize for InvocationPolicy { 134 | fn serialize(&self, serializer: S) -> Result 135 | where 136 | S: serde::Serializer, 137 | { 138 | let ser_str = match *self { 139 | InvocationPolicy::Single => "single", 140 | InvocationPolicy::RoundRobin => "roundrobin", 141 | InvocationPolicy::Random => "random", 142 | InvocationPolicy::First => "first", 143 | InvocationPolicy::Last => "last", 144 | }; 145 | serializer.serialize_str(ser_str) 146 | } 147 | } 148 | 149 | impl<'de> serde::Deserialize<'de> for InvocationPolicy { 150 | fn deserialize(deserializer: D) -> Result 151 | where 152 | D: serde::Deserializer<'de>, 153 | { 154 | deserializer.deserialize_str(InvocationPolicyVisitor) 155 | } 156 | } 157 | 158 | impl<'de> serde::de::Visitor<'de> for InvocationPolicyVisitor { 159 | type Value = InvocationPolicy; 160 | 161 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 162 | formatter.write_str("invocation policy for a procedure") 163 | } 164 | 165 | #[inline] 166 | fn visit_str(self, value: &str) -> Result 167 | where 168 | E: serde::de::Error, 169 | { 170 | match value { 171 | "single" => Ok(InvocationPolicy::Single), 172 | "roundrobin" => Ok(InvocationPolicy::RoundRobin), 173 | "random" => Ok(InvocationPolicy::Random), 174 | "first" => Ok(InvocationPolicy::First), 175 | "last" => Ok(InvocationPolicy::Last), 176 | x => Err(serde::de::Error::custom(format!( 177 | "Invalid invocation policy: {}", 178 | x 179 | ))), 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/messages/types/options.rs: -------------------------------------------------------------------------------- 1 | use super::{is_not, ClientRoles, InvocationPolicy, MatchingPolicy, RouterRoles, URI}; 2 | 3 | #[derive(Serialize, Deserialize, PartialEq, Debug, Default)] 4 | pub struct HelloDetails { 5 | #[serde(default, skip_serializing_if = "Option::is_none")] 6 | agent: Option, 7 | roles: ClientRoles, 8 | } 9 | 10 | #[derive(Serialize, Deserialize, PartialEq, Debug, Default)] 11 | pub struct WelcomeDetails { 12 | #[serde(default, skip_serializing_if = "Option::is_none")] 13 | agent: Option, 14 | roles: RouterRoles, 15 | } 16 | 17 | #[derive(Serialize, Deserialize, PartialEq, Debug, Default)] 18 | pub struct ErrorDetails { 19 | #[serde(default, skip_serializing_if = "Option::is_none")] 20 | message: Option, 21 | } 22 | 23 | #[derive(Serialize, Deserialize, PartialEq, Debug, Default)] 24 | pub struct SubscribeOptions { 25 | #[serde(default, rename = "match", skip_serializing_if = "MatchingPolicy::is_strict")] 26 | pub pattern_match: MatchingPolicy, 27 | } 28 | 29 | #[derive(Serialize, Deserialize, PartialEq, Debug, Default)] 30 | pub struct PublishOptions { 31 | #[serde(default, skip_serializing_if = "is_not")] 32 | acknowledge: bool, 33 | } 34 | 35 | #[derive(Serialize, Deserialize, PartialEq, Debug, Default)] 36 | pub struct RegisterOptions { 37 | #[serde(default, rename = "match", skip_serializing_if = "MatchingPolicy::is_strict")] 38 | pub pattern_match: MatchingPolicy, 39 | 40 | #[serde(default, rename = "invoke", skip_serializing_if = "InvocationPolicy::is_single")] 41 | pub invocation_policy: InvocationPolicy, 42 | } 43 | 44 | #[derive(PartialEq, Debug, Default, Serialize, Deserialize)] 45 | pub struct CallOptions {} 46 | 47 | #[derive(PartialEq, Debug, Default, Serialize, Deserialize)] 48 | pub struct YieldOptions {} 49 | 50 | #[derive(Serialize, Deserialize, PartialEq, Debug, Default)] 51 | pub struct EventDetails { 52 | #[serde(default, skip_serializing_if = "Option::is_none")] 53 | publisher: Option, 54 | 55 | #[serde(default, skip_serializing_if = "Option::is_none")] 56 | trustlevel: Option, 57 | 58 | #[serde(default, skip_serializing_if = "Option::is_none")] 59 | pub topic: Option, 60 | } 61 | 62 | #[derive(Serialize, Deserialize, PartialEq, Debug, Default)] 63 | pub struct InvocationDetails { 64 | #[serde(default, skip_serializing_if = "Option::is_none")] 65 | pub procedure: Option, 66 | } 67 | 68 | #[derive(PartialEq, Debug, Default, Serialize, Deserialize)] 69 | pub struct ResultDetails {} 70 | 71 | impl HelloDetails { 72 | pub fn new(roles: ClientRoles) -> HelloDetails { 73 | HelloDetails { 74 | roles: roles, 75 | agent: None, 76 | } 77 | } 78 | 79 | pub fn new_with_agent(roles: ClientRoles, agent: &str) -> HelloDetails { 80 | HelloDetails { 81 | roles: roles, 82 | agent: Some(agent.to_string()), 83 | } 84 | } 85 | } 86 | 87 | impl WelcomeDetails { 88 | pub fn new(roles: RouterRoles) -> WelcomeDetails { 89 | WelcomeDetails { 90 | roles: roles, 91 | agent: None, 92 | } 93 | } 94 | 95 | pub fn new_with_agent(roles: RouterRoles, agent: &str) -> WelcomeDetails { 96 | WelcomeDetails { 97 | roles: roles, 98 | agent: Some(agent.to_string()), 99 | } 100 | } 101 | } 102 | 103 | impl ErrorDetails { 104 | pub fn new() -> ErrorDetails { 105 | ErrorDetails { message: None } 106 | } 107 | 108 | pub fn new_with_message(message: &str) -> ErrorDetails { 109 | ErrorDetails { 110 | message: Some(message.to_string()), 111 | } 112 | } 113 | } 114 | 115 | impl SubscribeOptions { 116 | pub fn new() -> SubscribeOptions { 117 | SubscribeOptions { 118 | pattern_match: MatchingPolicy::Strict, 119 | } 120 | } 121 | } 122 | 123 | impl PublishOptions { 124 | pub fn new(acknowledge: bool) -> PublishOptions { 125 | PublishOptions { 126 | acknowledge: acknowledge, 127 | } 128 | } 129 | 130 | pub fn should_acknowledge(&self) -> bool { 131 | self.acknowledge 132 | } 133 | } 134 | 135 | impl RegisterOptions { 136 | pub fn new() -> RegisterOptions { 137 | RegisterOptions { 138 | pattern_match: MatchingPolicy::Strict, 139 | invocation_policy: InvocationPolicy::Single, 140 | } 141 | } 142 | } 143 | 144 | impl CallOptions { 145 | pub fn new() -> CallOptions { 146 | CallOptions {} 147 | } 148 | } 149 | 150 | impl YieldOptions { 151 | pub fn new() -> YieldOptions { 152 | YieldOptions {} 153 | } 154 | } 155 | 156 | impl EventDetails { 157 | pub fn new() -> EventDetails { 158 | EventDetails { 159 | publisher: None, 160 | trustlevel: None, 161 | topic: None, 162 | } 163 | } 164 | 165 | pub fn new_with_topic(topic: URI) -> EventDetails { 166 | EventDetails { 167 | publisher: None, 168 | trustlevel: None, 169 | topic: Some(topic), 170 | } 171 | } 172 | } 173 | 174 | impl InvocationDetails { 175 | pub fn new() -> InvocationDetails { 176 | InvocationDetails { procedure: None } 177 | } 178 | } 179 | 180 | impl ResultDetails { 181 | pub fn new() -> ResultDetails { 182 | ResultDetails {} 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/messages/types/roles.rs: -------------------------------------------------------------------------------- 1 | use super::is_not; 2 | use std::collections::HashMap; 3 | 4 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 5 | pub struct ClientRoles { 6 | pub publisher: PublisherRole, 7 | pub subscriber: SubscriberRole, 8 | pub caller: CallerRole, 9 | pub callee: CalleeRole, 10 | } 11 | 12 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 13 | pub struct RouterRoles { 14 | pub dealer: DealerRole, 15 | pub broker: BrokerRole, 16 | } 17 | 18 | /************************** 19 | Roles 20 | **************************/ 21 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 22 | pub struct PublisherRole { 23 | #[serde(default, skip_serializing_if = "Option::is_none")] 24 | features: Option>, 25 | } 26 | 27 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 28 | pub struct CallerRole { 29 | #[serde(default, skip_serializing_if = "Option::is_none")] 30 | features: Option>, 31 | } 32 | 33 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 34 | pub struct CalleeRole { 35 | #[serde(default, skip_serializing_if = "Option::is_none")] 36 | features: Option>, 37 | } 38 | 39 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 40 | pub struct SubscriberRole { 41 | #[serde(default, skip_serializing_if = "Option::is_none")] 42 | features: Option, 43 | } 44 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 45 | pub struct SubscriberFeatures { 46 | #[serde(skip_serializing_if = "is_not", default)] 47 | pattern_based_subscription: bool, 48 | } 49 | 50 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 51 | pub struct DealerRole { 52 | #[serde(default, skip_serializing_if = "Option::is_none")] 53 | features: Option, 54 | } 55 | 56 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 57 | pub struct BrokerRole { 58 | #[serde(default, skip_serializing_if = "Option::is_none")] 59 | features: Option, 60 | } 61 | 62 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 63 | pub struct DealerFeatures { 64 | #[serde(skip_serializing_if = "is_not", default)] 65 | pattern_based_registration: bool, 66 | } 67 | 68 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 69 | pub struct BrokerFeatures { 70 | #[serde(skip_serializing_if = "is_not", default)] 71 | pattern_based_subscription: bool, 72 | } 73 | 74 | /************************** 75 | Implementations 76 | **************************/ 77 | 78 | impl RouterRoles { 79 | #[inline] 80 | pub fn new() -> RouterRoles { 81 | RouterRoles { 82 | broker: BrokerRole { 83 | features: Some(BrokerFeatures { 84 | pattern_based_subscription: true, 85 | }), 86 | }, 87 | dealer: DealerRole { 88 | features: Some(DealerFeatures { 89 | pattern_based_registration: true, 90 | }), 91 | }, 92 | } 93 | } 94 | 95 | #[inline] 96 | pub fn new_basic() -> RouterRoles { 97 | RouterRoles { 98 | broker: BrokerRole { features: None }, 99 | dealer: DealerRole { features: None }, 100 | } 101 | } 102 | } 103 | 104 | impl ClientRoles { 105 | #[inline] 106 | pub fn new() -> ClientRoles { 107 | ClientRoles { 108 | publisher: PublisherRole { 109 | features: Some(HashMap::new()), 110 | }, 111 | subscriber: SubscriberRole { 112 | features: Some(SubscriberFeatures { 113 | pattern_based_subscription: true, 114 | }), 115 | }, 116 | caller: CallerRole { 117 | features: Some(HashMap::new()), 118 | }, 119 | callee: CalleeRole { 120 | features: Some(HashMap::new()), 121 | }, 122 | } 123 | } 124 | 125 | #[inline] 126 | pub fn new_basic() -> ClientRoles { 127 | ClientRoles { 128 | publisher: PublisherRole { 129 | features: Some(HashMap::new()), 130 | }, 131 | subscriber: SubscriberRole { 132 | features: Some(SubscriberFeatures { 133 | pattern_based_subscription: false, 134 | }), 135 | }, 136 | caller: CallerRole { 137 | features: Some(HashMap::new()), 138 | }, 139 | callee: CalleeRole { 140 | features: Some(HashMap::new()), 141 | }, 142 | } 143 | } 144 | } 145 | 146 | impl Default for RouterRoles { 147 | fn default() -> RouterRoles { 148 | RouterRoles::new() 149 | } 150 | } 151 | 152 | impl Default for ClientRoles { 153 | fn default() -> ClientRoles { 154 | ClientRoles::new() 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/messages/types/value.rs: -------------------------------------------------------------------------------- 1 | use super::{CallError, Reason}; 2 | use itertools::Itertools; 3 | use serde; 4 | use std::collections::HashMap; 5 | use std::fmt; 6 | use CallResult; 7 | 8 | pub type Dict = HashMap; 9 | pub type List = Vec; 10 | 11 | // TODO properly implement Hash and Eq 12 | #[derive(Debug, PartialEq, Clone, Hash, Eq)] 13 | pub struct URI { 14 | pub uri: String, 15 | } 16 | 17 | impl URI { 18 | pub fn new(uri: &str) -> URI { 19 | URI { 20 | uri: uri.to_string(), 21 | } 22 | } 23 | } 24 | 25 | #[derive(Debug, PartialEq, Clone)] 26 | pub enum Value { 27 | // The ID and URI types cannot be distinguished from string and integer types respectively. 28 | // So, we just ignore them here 29 | Dict(Dict), 30 | Integer(i64), 31 | UnsignedInteger(u64), 32 | Float(f64), 33 | String(String), 34 | List(List), 35 | Boolean(bool), 36 | } 37 | 38 | struct URIVisitor; 39 | struct ValueVisitor; 40 | 41 | pub trait ArgList { 42 | fn get_int(&self, index: usize) -> CallResult>; 43 | fn get_string(&self, index: usize) -> CallResult>; 44 | fn verify_len(&self, expected_len: usize) -> CallResult<()>; 45 | } 46 | 47 | pub trait ArgDict { 48 | fn get_int(&self, key: &str) -> CallResult>; 49 | fn get_string<'a>(&'a self, key: &str) -> CallResult>; 50 | } 51 | 52 | impl ArgList for List { 53 | fn get_int(&self, index: usize) -> CallResult> { 54 | let value = self.get(index); 55 | match value { 56 | Some(value) => { 57 | if let Value::Integer(value) = *value { 58 | Ok(Some(value)) 59 | } else { 60 | Err(CallError::new( 61 | Reason::InvalidArgument, 62 | Some(vec![Value::String(format!( 63 | "Expected integer, got {}", 64 | value.summarize() 65 | ))]), 66 | None, 67 | )) 68 | } 69 | } 70 | None => Ok(None), 71 | } 72 | } 73 | 74 | fn get_string(&self, index: usize) -> CallResult> { 75 | let value = self.get(index); 76 | match value { 77 | Some(value) => { 78 | if let Value::String(ref value) = *value { 79 | Ok(Some(value)) 80 | } else { 81 | Err(CallError::new( 82 | Reason::InvalidArgument, 83 | Some(vec![Value::String(format!( 84 | "Expected string, got {}", 85 | value.summarize() 86 | ))]), 87 | None, 88 | )) 89 | } 90 | } 91 | None => Ok(None), 92 | } 93 | } 94 | 95 | fn verify_len(&self, expected_len: usize) -> CallResult<()> { 96 | if self.len() >= expected_len { 97 | Ok(()) 98 | } else { 99 | Err(CallError::new( 100 | Reason::InvalidArgument, 101 | Some(vec![Value::String(format!( 102 | "Expected {} arguments, got {}", 103 | expected_len, 104 | self.len() 105 | ))]), 106 | None, 107 | )) 108 | } 109 | } 110 | } 111 | 112 | impl ArgDict for Dict { 113 | fn get_int(&self, key: &str) -> CallResult> { 114 | let value = self.get(key); 115 | match value { 116 | Some(value) => { 117 | if let Value::Integer(value) = *value { 118 | Ok(Some(value)) 119 | } else { 120 | Err(CallError::new( 121 | Reason::InvalidArgument, 122 | Some(vec![Value::String(format!( 123 | "Expected integer, got {}", 124 | value.summarize() 125 | ))]), 126 | None, 127 | )) 128 | } 129 | } 130 | None => Ok(None), 131 | } 132 | } 133 | fn get_string<'a>(&'a self, key: &str) -> CallResult> { 134 | let value = self.get(key); 135 | match value { 136 | Some(value) => { 137 | if let Value::String(ref value) = *value { 138 | Ok(Some(value)) 139 | } else { 140 | Err(CallError::new( 141 | Reason::InvalidArgument, 142 | Some(vec![Value::String(format!( 143 | "Expected string, got {}", 144 | value.summarize() 145 | ))]), 146 | None, 147 | )) 148 | } 149 | } 150 | None => Ok(None), 151 | } 152 | } 153 | } 154 | 155 | impl Value { 156 | pub fn summarize(&self) -> String { 157 | match *self { 158 | Value::Dict(ref d) => { 159 | let mut result = String::new(); 160 | result.push('{'); 161 | result.push_str(&d.iter() 162 | .take(50) 163 | .map(|(key, value)| format!("{}:{}", key, value.summarize())) 164 | .join(",")); 165 | result.push('}'); 166 | result 167 | } 168 | Value::Integer(i) => i.to_string(), 169 | Value::UnsignedInteger(u) => u.to_string(), 170 | Value::Float(f) => f.to_string(), 171 | Value::String(ref s) => { 172 | if s.len() > 50 { 173 | s[..50].to_string() 174 | } else { 175 | s.clone() 176 | } 177 | } 178 | Value::List(ref l) => { 179 | let mut result = String::new(); 180 | result.push('['); 181 | result.push_str(&l.iter() 182 | .take(50) 183 | .map(|element| element.summarize()) 184 | .join(",")); 185 | result.push(']'); 186 | result 187 | } 188 | Value::Boolean(b) => b.to_string(), 189 | } 190 | } 191 | } 192 | 193 | // XXX Right now there is no way to tell the difference between a URI and a string, or an ID and an Integer 194 | impl<'de> serde::de::Visitor<'de> for ValueVisitor { 195 | type Value = Value; 196 | 197 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 198 | formatter.write_str("JSON value") 199 | } 200 | 201 | #[inline] 202 | fn visit_str(self, value: &str) -> Result 203 | where 204 | E: serde::de::Error, 205 | { 206 | Ok(Value::String(value.to_string())) 207 | } 208 | 209 | #[inline] 210 | fn visit_i64(self, value: i64) -> Result 211 | where 212 | E: serde::de::Error, 213 | { 214 | Ok(Value::Integer(value)) 215 | } 216 | 217 | #[inline] 218 | fn visit_u64(self, value: u64) -> Result 219 | where 220 | E: serde::de::Error, 221 | { 222 | Ok(Value::UnsignedInteger(value)) 223 | } 224 | 225 | fn visit_f64(self, value: f64) -> Result 226 | where 227 | E: serde::de::Error, 228 | { 229 | Ok(Value::Float(value)) 230 | } 231 | 232 | #[inline] 233 | fn visit_bool(self, value: bool) -> Result 234 | where 235 | E: serde::de::Error, 236 | { 237 | Ok(Value::Boolean(value)) 238 | } 239 | 240 | #[inline] 241 | fn visit_map(self, mut visitor: Visitor) -> Result 242 | where 243 | Visitor: serde::de::MapAccess<'de>, 244 | { 245 | let mut values = HashMap::new(); 246 | if let Some(size) = visitor.size_hint() { 247 | values.reserve(size); 248 | } 249 | 250 | while let Some((key, value)) = visitor.next_entry()? { 251 | values.insert(key, value); 252 | } 253 | 254 | Ok(Value::Dict(values)) 255 | } 256 | 257 | #[inline] 258 | fn visit_seq(self, mut visitor: Visitor) -> Result 259 | where 260 | Visitor: serde::de::SeqAccess<'de>, 261 | { 262 | let mut values = Vec::new(); 263 | if let Some(size) = visitor.size_hint() { 264 | values.reserve(size); 265 | } 266 | 267 | while let Some(value) = visitor.next_element()? { 268 | values.push(value); 269 | } 270 | 271 | Ok(Value::List(values)) 272 | } 273 | } 274 | 275 | /*------------------------- 276 | Value 277 | -------------------------*/ 278 | impl serde::Serialize for Value { 279 | fn serialize(&self, serializer: S) -> Result 280 | where 281 | S: serde::ser::Serializer, 282 | { 283 | match *self { 284 | Value::Dict(ref dict) => dict.serialize(serializer), 285 | Value::String(ref s) => serializer.serialize_str(s), 286 | Value::Integer(i) => serializer.serialize_i64(i), 287 | Value::UnsignedInteger(u) => serializer.serialize_u64(u), 288 | Value::Float(f) => serializer.serialize_f64(f), 289 | Value::List(ref list) => list.serialize(serializer), 290 | Value::Boolean(b) => serializer.serialize_bool(b), 291 | } 292 | } 293 | } 294 | 295 | impl<'de> serde::Deserialize<'de> for Value { 296 | fn deserialize(deserializer: D) -> Result 297 | where 298 | D: serde::Deserializer<'de>, 299 | { 300 | deserializer.deserialize_any(ValueVisitor) 301 | } 302 | } 303 | 304 | /*------------------------- 305 | URI 306 | -------------------------*/ 307 | 308 | impl serde::Serialize for URI { 309 | fn serialize(&self, serializer: S) -> Result 310 | where 311 | S: serde::ser::Serializer, 312 | { 313 | serializer.serialize_str(&self.uri) 314 | } 315 | } 316 | 317 | impl<'de> serde::Deserialize<'de> for URI { 318 | fn deserialize(deserializer: D) -> Result 319 | where 320 | D: serde::Deserializer<'de>, 321 | { 322 | deserializer.deserialize_str(URIVisitor) 323 | } 324 | } 325 | 326 | impl<'de> serde::de::Visitor<'de> for URIVisitor { 327 | type Value = URI; 328 | 329 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 330 | formatter.write_str("URI") 331 | } 332 | #[inline] 333 | fn visit_str(self, value: &str) -> Result 334 | where 335 | E: serde::de::Error, 336 | { 337 | Ok(URI { 338 | uri: value.to_string(), 339 | }) 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /src/router/handshake.rs: -------------------------------------------------------------------------------- 1 | use super::{ConnectionHandler, ConnectionState, WAMP_JSON, WAMP_MSGPACK}; 2 | use std::sync::Arc; 3 | 4 | use router::messaging::send_message; 5 | use ws::{CloseCode, Error as WSError, ErrorKind as WSErrorKind, Request, Response, 6 | Result as WSResult}; 7 | 8 | use messages::{ErrorDetails, HelloDetails, Message, Reason, RouterRoles, WelcomeDetails, URI}; 9 | use {Error, ErrorKind, WampResult}; 10 | 11 | impl ConnectionHandler { 12 | pub fn handle_hello(&mut self, realm: URI, _details: HelloDetails) -> WampResult<()> { 13 | debug!("Responding to hello message (realm: {:?})", realm); 14 | let id = { 15 | let mut info = self.info.lock().unwrap(); 16 | info.state = ConnectionState::Connected; 17 | info.id 18 | }; 19 | 20 | try!(self.set_realm(realm.uri)); 21 | send_message( 22 | &self.info, 23 | &Message::Welcome(id, WelcomeDetails::new(RouterRoles::new())), 24 | ) 25 | } 26 | 27 | pub fn handle_goodbye(&mut self, _details: ErrorDetails, reason: Reason) -> WampResult<()> { 28 | let state = self.info.lock().unwrap().state.clone(); 29 | match state { 30 | ConnectionState::Initializing => { 31 | // TODO check specification for how this ought to work. 32 | Err(Error::new(ErrorKind::InvalidState( 33 | "Received a goodbye message before handshake complete", 34 | ))) 35 | } 36 | ConnectionState::Connected => { 37 | info!("Received goodbye message with reason: {:?}", reason); 38 | self.remove(); 39 | send_message( 40 | &self.info, 41 | &Message::Goodbye(ErrorDetails::new(), Reason::GoodbyeAndOut), 42 | ).ok(); 43 | let mut info = self.info.lock().unwrap(); 44 | info.state = ConnectionState::Disconnected; 45 | match info.sender.close(CloseCode::Normal) { 46 | Err(e) => Err(Error::new(ErrorKind::WSError(e))), 47 | _ => Ok(()), 48 | } 49 | } 50 | ConnectionState::ShuttingDown => { 51 | info!( 52 | "Received goodbye message in response to our goodbye message with reason: {:?}", 53 | reason 54 | ); 55 | let mut info = self.info.lock().unwrap(); 56 | info.state = ConnectionState::Disconnected; 57 | match info.sender.close(CloseCode::Normal) { 58 | Err(e) => Err(Error::new(ErrorKind::WSError(e))), 59 | _ => Ok(()), 60 | } 61 | } 62 | ConnectionState::Disconnected => { 63 | warn!("Received goodbye message after closing connection"); 64 | Ok(()) 65 | } 66 | } 67 | } 68 | 69 | fn set_realm(&mut self, realm: String) -> WampResult<()> { 70 | debug!("Setting realm to {}", realm); 71 | if let Some(realm) = self.router.realms.lock().unwrap().get(&realm) { 72 | { 73 | realm 74 | .lock() 75 | .unwrap() 76 | .connections 77 | .push(Arc::clone(&self.info)); 78 | } 79 | self.realm = Some(Arc::clone(realm)); 80 | } else { 81 | return Err(Error::new(ErrorKind::HandshakeError(Reason::NoSuchRealm))); 82 | } 83 | Ok(()) 84 | } 85 | 86 | pub fn process_protocol(&mut self, request: &Request, response: &mut Response) -> WSResult<()> { 87 | debug!("Checking protocol"); 88 | let protocols = try!(request.protocols()); 89 | for protocol in protocols { 90 | if protocol == WAMP_JSON || protocol == WAMP_MSGPACK { 91 | response.set_protocol(protocol); 92 | let mut info = self.info.lock().unwrap(); 93 | info.protocol = protocol.to_string(); 94 | return Ok(()); 95 | } 96 | } 97 | Err(WSError::new( 98 | WSErrorKind::Protocol, 99 | format!( 100 | "Neither {} nor {} were selected as Websocket sub-protocols", 101 | WAMP_JSON, WAMP_MSGPACK 102 | ), 103 | )) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/router/messaging.rs: -------------------------------------------------------------------------------- 1 | use super::{ConnectionHandler, ConnectionInfo, ConnectionState, WAMP_JSON}; 2 | use std::sync::{Arc, Mutex}; 3 | use ws::{CloseCode, Error as WSError, ErrorKind as WSErrorKind, Handler, Message as WSMessage, 4 | Request, Response, Result as WSResult, Sender}; 5 | 6 | use messages::{ErrorDetails, ErrorType, Message, Reason}; 7 | use rmp_serde::Deserializer as RMPDeserializer; 8 | use rmp_serde::Serializer; 9 | use serde::{Deserialize, Serialize}; 10 | use serde_json; 11 | use std::collections::HashMap; 12 | use std::io::Cursor; 13 | use utils::StructMapWriter; 14 | use {Dict, Error, ErrorKind, List, WampResult, ID}; 15 | 16 | pub fn send_message(info: &Arc>, message: &Message) -> WampResult<()> { 17 | let info = info.lock().unwrap(); 18 | 19 | debug!("Sending message {:?} via {}", message, info.protocol); 20 | let send_result = if info.protocol == WAMP_JSON { 21 | send_message_json(&info.sender, message) 22 | } else { 23 | send_message_msgpack(&info.sender, message) 24 | }; 25 | match send_result { 26 | Ok(()) => Ok(()), 27 | Err(e) => Err(Error::new(ErrorKind::WSError(e))), 28 | } 29 | } 30 | 31 | fn send_message_json(sender: &Sender, message: &Message) -> WSResult<()> { 32 | // Send the message 33 | sender.send(WSMessage::Text(serde_json::to_string(message).unwrap())) 34 | } 35 | 36 | fn send_message_msgpack(sender: &Sender, message: &Message) -> WSResult<()> { 37 | // Send the message 38 | let mut buf: Vec = Vec::new(); 39 | message 40 | .serialize(&mut Serializer::with(&mut buf, StructMapWriter)) 41 | .unwrap(); 42 | sender.send(WSMessage::Binary(buf)) 43 | } 44 | 45 | impl ConnectionHandler { 46 | fn handle_message(&mut self, message: Message) -> WampResult<()> { 47 | debug!("Received message {:?}", message); 48 | match message { 49 | Message::Hello(realm, details) => self.handle_hello(realm, details), 50 | Message::Subscribe(request_id, options, topic) => { 51 | self.handle_subscribe(request_id, options, topic) 52 | } 53 | Message::Publish(request_id, options, topic, args, kwargs) => { 54 | self.handle_publish(request_id, options, topic, args, kwargs) 55 | } 56 | Message::Unsubscribe(request_id, topic_id) => { 57 | self.handle_unsubscribe(request_id, topic_id) 58 | } 59 | Message::Goodbye(details, reason) => self.handle_goodbye(details, reason), 60 | Message::Register(request_id, options, procedure) => { 61 | self.handle_register(request_id, options, procedure) 62 | } 63 | Message::Unregister(request_id, procedure_id) => { 64 | self.handle_unregister(request_id, procedure_id) 65 | } 66 | Message::Call(request_id, options, procedure, args, kwargs) => { 67 | self.handle_call(request_id, options, procedure, args, kwargs) 68 | } 69 | Message::Yield(invocation_id, options, args, kwargs) => { 70 | self.handle_yield(invocation_id, options, args, kwargs) 71 | } 72 | Message::Error(e_type, request_id, details, reason, args, kwargs) => { 73 | self.handle_error(e_type, request_id, details, reason, args, kwargs) 74 | } 75 | t => Err(Error::new(ErrorKind::InvalidMessageType(t))), 76 | } 77 | } 78 | 79 | fn handle_error( 80 | &mut self, 81 | e_type: ErrorType, 82 | request_id: ID, 83 | details: Dict, 84 | reason: Reason, 85 | args: Option, 86 | kwargs: Option, 87 | ) -> WampResult<()> { 88 | if e_type == ErrorType::Invocation { 89 | debug!( 90 | "Responding to error message for invocation (id: {})", 91 | request_id 92 | ); 93 | match self.realm { 94 | Some(ref realm) => { 95 | let mut realm = realm.lock().unwrap(); 96 | let manager = &mut realm.registration_manager; 97 | if let Some((call_id, callee)) = manager.active_calls.remove(&request_id) { 98 | let error_message = 99 | Message::Error(ErrorType::Call, call_id, details, reason, args, kwargs); 100 | send_message(&callee, &error_message) 101 | } else { 102 | Err(Error::new(ErrorKind::InvalidState( 103 | "Received an error message for a call that wasn't sent", 104 | ))) 105 | } 106 | } 107 | None => Err(Error::new(ErrorKind::InvalidState( 108 | "Received a message while not attached to a realm", 109 | ))), 110 | } 111 | } else { 112 | Err(Error::new(ErrorKind::InvalidState( 113 | "Got an error message that was not for a call message", 114 | ))) 115 | } 116 | } 117 | 118 | fn parse_message(&self, msg: WSMessage) -> WampResult { 119 | match msg { 120 | WSMessage::Text(payload) => match serde_json::from_str(&payload) { 121 | Ok(message) => Ok(message), 122 | Err(e) => Err(Error::new(ErrorKind::JSONError(e))), 123 | }, 124 | WSMessage::Binary(payload) => { 125 | let mut de = RMPDeserializer::new(Cursor::new(payload)); 126 | match Deserialize::deserialize(&mut de) { 127 | Ok(message) => Ok(message), 128 | Err(e) => Err(Error::new(ErrorKind::MsgPackError(e))), 129 | } 130 | } 131 | } 132 | } 133 | 134 | fn send_error(&self, err_type: ErrorType, request_id: ID, reason: Reason) -> WSResult<()> { 135 | send_message( 136 | &self.info, 137 | &Message::Error(err_type, request_id, HashMap::new(), reason, None, None), 138 | ).map_err(|e| { 139 | let kind = e.get_kind(); 140 | if let ErrorKind::WSError(e) = kind { 141 | e 142 | } else { 143 | WSError::new(WSErrorKind::Internal, kind.description()) 144 | } 145 | }) 146 | } 147 | 148 | fn send_abort(&self, reason: Reason) -> WSResult<()> { 149 | send_message(&self.info, &Message::Abort(ErrorDetails::new(), reason)).map_err(|e| { 150 | let kind = e.get_kind(); 151 | if let ErrorKind::WSError(e) = kind { 152 | e 153 | } else { 154 | WSError::new(WSErrorKind::Internal, kind.description()) 155 | } 156 | }) 157 | } 158 | 159 | fn on_message_error(&mut self, error: Error) -> WSResult<()> { 160 | use std::error::Error as StdError; 161 | match error.get_kind() { 162 | ErrorKind::WSError(e) => Err(e), 163 | ErrorKind::URLError(_) => unimplemented!(), 164 | ErrorKind::HandshakeError(r) => { 165 | error!("Handshake error: {}", r); 166 | try!(self.send_abort(r)); 167 | self.terminate_connection() 168 | } 169 | ErrorKind::UnexpectedMessage(msg) => { 170 | error!("Unexpected Message: {}", msg); 171 | self.terminate_connection() 172 | } 173 | ErrorKind::ThreadError(_) => unimplemented!(), 174 | ErrorKind::ConnectionLost => unimplemented!(), 175 | ErrorKind::Closing(_) => { 176 | unimplemented!{} 177 | } 178 | ErrorKind::JSONError(e) => { 179 | error!("Could not parse JSON: {}", e); 180 | self.terminate_connection() 181 | } 182 | ErrorKind::MsgPackError(e) => { 183 | error!("Could not parse MsgPack: {}", e.description()); 184 | self.terminate_connection() 185 | } 186 | ErrorKind::MalformedData => unimplemented!(), 187 | ErrorKind::InvalidMessageType(msg) => { 188 | error!("Router unable to handle message {:?}", msg); 189 | self.terminate_connection() 190 | } 191 | ErrorKind::InvalidState(s) => { 192 | error!("Invalid State: {}", s); 193 | self.terminate_connection() 194 | } 195 | ErrorKind::Timeout => { 196 | error!("Connection timeout"); 197 | self.terminate_connection() 198 | } 199 | ErrorKind::ErrorReason(err_type, id, reason) => self.send_error(err_type, id, reason), 200 | } 201 | } 202 | } 203 | 204 | impl Handler for ConnectionHandler { 205 | fn on_request(&mut self, request: &Request) -> WSResult { 206 | info!("New request"); 207 | let mut response = match Response::from_request(request) { 208 | Ok(response) => response, 209 | Err(e) => { 210 | error!("Could not create response: {}", e); 211 | return Err(e); 212 | } 213 | }; 214 | try!(self.process_protocol(request, &mut response)); 215 | debug!("Sending response"); 216 | Ok(response) 217 | } 218 | 219 | fn on_message(&mut self, msg: WSMessage) -> WSResult<()> { 220 | debug!("Receveied message: {:?}", msg); 221 | let message = match self.parse_message(msg) { 222 | Err(e) => return self.on_message_error(e), 223 | Ok(m) => m, 224 | }; 225 | match self.handle_message(message) { 226 | Err(e) => self.on_message_error(e), 227 | _ => Ok(()), 228 | } 229 | } 230 | 231 | fn on_close(&mut self, _code: CloseCode, _reason: &str) { 232 | let state = self.info.lock().unwrap().state.clone(); 233 | if state != ConnectionState::Disconnected { 234 | trace!("Client disconnected. Closing connection"); 235 | self.terminate_connection().ok(); 236 | } 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/router/mod.rs: -------------------------------------------------------------------------------- 1 | mod handshake; 2 | mod messaging; 3 | mod pubsub; 4 | mod rpc; 5 | 6 | use super::ID; 7 | use messages::{ErrorDetails, Message, Reason}; 8 | use rand::distributions::{Distribution, Range}; 9 | use rand::thread_rng; 10 | use router::messaging::send_message; 11 | use router::pubsub::SubscriptionPatternNode; 12 | use router::rpc::RegistrationPatternNode; 13 | use std::collections::HashMap; 14 | use std::marker::Sync; 15 | use std::sync::{Arc, Mutex}; 16 | use std::thread::{self, JoinHandle}; 17 | use std::time::Duration; 18 | use ws::{listen as ws_listen, Result as WSResult, Sender}; 19 | 20 | struct SubscriptionManager { 21 | subscriptions: SubscriptionPatternNode>>, 22 | subscription_ids_to_uris: HashMap, 23 | } 24 | 25 | struct RegistrationManager { 26 | registrations: RegistrationPatternNode>>, 27 | registration_ids_to_uris: HashMap, 28 | active_calls: HashMap>)>, 29 | } 30 | 31 | struct Realm { 32 | subscription_manager: SubscriptionManager, 33 | registration_manager: RegistrationManager, 34 | connections: Vec>>, 35 | } 36 | 37 | pub struct Router { 38 | info: Arc, 39 | } 40 | 41 | struct RouterInfo { 42 | realms: Mutex>>>, 43 | } 44 | 45 | struct ConnectionHandler { 46 | info: Arc>, 47 | router: Arc, 48 | realm: Option>>, 49 | subscribed_topics: Vec, 50 | registered_procedures: Vec, 51 | } 52 | 53 | pub struct ConnectionInfo { 54 | state: ConnectionState, 55 | sender: Sender, 56 | protocol: String, 57 | id: u64, 58 | } 59 | 60 | #[derive(Clone, PartialEq)] 61 | enum ConnectionState { 62 | Initializing, 63 | Connected, 64 | ShuttingDown, 65 | Disconnected, 66 | } 67 | 68 | static WAMP_JSON: &'static str = "wamp.2.json"; 69 | static WAMP_MSGPACK: &'static str = "wamp.2.msgpack"; 70 | 71 | fn random_id() -> u64 { 72 | let mut rng = thread_rng(); 73 | // TODO make this a constant 74 | let between = Range::new(0, 1u64.rotate_left(56) - 1); 75 | between.sample(&mut rng) 76 | } 77 | 78 | unsafe impl Sync for Router {} 79 | 80 | impl Default for Router { 81 | fn default() -> Self { 82 | Self::new() 83 | } 84 | } 85 | 86 | impl Router { 87 | #[inline] 88 | pub fn new() -> Router { 89 | Router { 90 | info: Arc::new(RouterInfo { 91 | realms: Mutex::new(HashMap::new()), 92 | }), 93 | } 94 | } 95 | 96 | pub fn listen(&self, url: &str) -> JoinHandle<()> { 97 | let router_info = Arc::clone(&self.info); 98 | let url = url.to_string(); 99 | thread::spawn(move || { 100 | ws_listen(&url[..], |sender| ConnectionHandler { 101 | info: Arc::new(Mutex::new(ConnectionInfo { 102 | state: ConnectionState::Initializing, 103 | sender: sender, 104 | protocol: String::new(), 105 | id: random_id(), 106 | })), 107 | subscribed_topics: Vec::new(), 108 | registered_procedures: Vec::new(), 109 | realm: None, 110 | router: Arc::clone(&router_info), 111 | }).unwrap(); 112 | }) 113 | } 114 | 115 | pub fn add_realm(&mut self, realm: &str) { 116 | let mut realms = self.info.realms.lock().unwrap(); 117 | if realms.contains_key(realm) { 118 | return; 119 | } 120 | realms.insert( 121 | realm.to_string(), 122 | Arc::new(Mutex::new(Realm { 123 | connections: Vec::new(), 124 | subscription_manager: SubscriptionManager { 125 | subscriptions: SubscriptionPatternNode::new(), 126 | subscription_ids_to_uris: HashMap::new(), 127 | }, 128 | registration_manager: RegistrationManager { 129 | registrations: RegistrationPatternNode::new(), 130 | registration_ids_to_uris: HashMap::new(), 131 | active_calls: HashMap::new(), 132 | }, 133 | })), 134 | ); 135 | debug!("Added realm {}", realm); 136 | } 137 | 138 | pub fn shutdown(&self) { 139 | for realm in self.info.realms.lock().unwrap().values() { 140 | for connection in &realm.lock().unwrap().connections { 141 | send_message( 142 | connection, 143 | &Message::Goodbye(ErrorDetails::new(), Reason::SystemShutdown), 144 | ).ok(); 145 | let mut connection = connection.lock().unwrap(); 146 | connection.state = ConnectionState::ShuttingDown; 147 | } 148 | } 149 | info!("Goodbye messages sent. Waiting 5 seconds for response"); 150 | thread::sleep(Duration::from_secs(5)); 151 | for realm in self.info.realms.lock().unwrap().values() { 152 | for connection in &realm.lock().unwrap().connections { 153 | let connection = connection.lock().unwrap(); 154 | connection.sender.shutdown().ok(); 155 | } 156 | } 157 | } 158 | } 159 | 160 | impl ConnectionHandler { 161 | fn remove(&mut self) { 162 | if let Some(ref realm) = self.realm { 163 | let mut realm = realm.lock().unwrap(); 164 | { 165 | trace!( 166 | "Removing subscriptions for client {}", 167 | self.info.lock().unwrap().id 168 | ); 169 | let manager = &mut realm.subscription_manager; 170 | for subscription_id in &self.subscribed_topics { 171 | trace!("Looking for subscription {}", subscription_id); 172 | if let Some(&(ref topic_uri, is_prefix)) = 173 | manager.subscription_ids_to_uris.get(subscription_id) 174 | { 175 | trace!("Removing subscription to {:?}", topic_uri); 176 | manager 177 | .subscriptions 178 | .unsubscribe_with(topic_uri, &self.info, is_prefix) 179 | .ok(); 180 | trace!("Subscription tree: {:?}", manager.subscriptions); 181 | } 182 | } 183 | } 184 | { 185 | let manager = &mut realm.registration_manager; 186 | for registration_id in &self.registered_procedures { 187 | if let Some(&(ref topic_uri, is_prefix)) = 188 | manager.registration_ids_to_uris.get(registration_id) 189 | { 190 | manager 191 | .registrations 192 | .unregister_with(topic_uri, &self.info, is_prefix) 193 | .ok(); 194 | } 195 | } 196 | } 197 | let my_id = self.info.lock().unwrap().id; 198 | realm 199 | .connections 200 | .retain(|connection| connection.lock().unwrap().id != my_id); 201 | } 202 | } 203 | 204 | fn terminate_connection(&mut self) -> WSResult<()> { 205 | self.remove(); 206 | Ok(()) 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/router/pubsub/mod.rs: -------------------------------------------------------------------------------- 1 | mod patterns; 2 | use super::{random_id, ConnectionHandler}; 3 | use std::sync::Arc; 4 | 5 | use messages::{ErrorType, EventDetails, Message, PublishOptions, Reason, SubscribeOptions, URI}; 6 | use router::messaging::send_message; 7 | pub use router::pubsub::patterns::SubscriptionPatternNode; 8 | use {Dict, Error, ErrorKind, List, MatchingPolicy, WampResult}; 9 | 10 | impl ConnectionHandler { 11 | pub fn handle_subscribe( 12 | &mut self, 13 | request_id: u64, 14 | options: SubscribeOptions, 15 | topic: URI, 16 | ) -> WampResult<()> { 17 | debug!( 18 | "Responding to subscribe message (id: {}, topic: {})", 19 | request_id, topic.uri 20 | ); 21 | match self.realm { 22 | Some(ref realm) => { 23 | let mut realm = realm.lock().unwrap(); 24 | let manager = &mut realm.subscription_manager; 25 | let topic_id = { 26 | let topic_id = match manager.subscriptions.subscribe_with( 27 | &topic, 28 | Arc::clone(&self.info), 29 | options.pattern_match, 30 | ) { 31 | Ok(topic_id) => topic_id, 32 | Err(e) => { 33 | return Err(Error::new(ErrorKind::ErrorReason( 34 | ErrorType::Subscribe, 35 | request_id, 36 | e.reason(), 37 | ))) 38 | } 39 | }; 40 | self.subscribed_topics.push(topic_id); 41 | topic_id 42 | }; 43 | manager.subscription_ids_to_uris.insert( 44 | topic_id, 45 | (topic.uri, options.pattern_match == MatchingPolicy::Prefix), 46 | ); 47 | send_message(&self.info, &Message::Subscribed(request_id, topic_id)) 48 | } 49 | None => Err(Error::new(ErrorKind::InvalidState( 50 | "Received a message while not attached to a realm", 51 | ))), 52 | } 53 | } 54 | 55 | pub fn handle_unsubscribe(&mut self, request_id: u64, topic_id: u64) -> WampResult<()> { 56 | match self.realm { 57 | Some(ref realm) => { 58 | let mut realm = realm.lock().unwrap(); 59 | let manager = &mut realm.subscription_manager; 60 | let (topic_uri, is_prefix) = match manager.subscription_ids_to_uris.get(&topic_id) { 61 | Some(&(ref uri, ref is_prefix)) => (uri.clone(), *is_prefix), 62 | None => { 63 | return Err(Error::new(ErrorKind::ErrorReason( 64 | ErrorType::Unsubscribe, 65 | request_id, 66 | Reason::NoSuchSubscription, 67 | ))) 68 | } 69 | }; 70 | 71 | let topic_id = match manager 72 | .subscriptions 73 | .unsubscribe_with(&topic_uri, &self.info, is_prefix) 74 | { 75 | Ok(topic_id) => topic_id, 76 | Err(e) => { 77 | return Err(Error::new(ErrorKind::ErrorReason( 78 | ErrorType::Unsubscribe, 79 | request_id, 80 | e.reason(), 81 | ))) 82 | } 83 | }; 84 | self.subscribed_topics.retain(|id| *id != topic_id); 85 | send_message(&self.info, &Message::Unsubscribed(request_id)) 86 | } 87 | None => Err(Error::new(ErrorKind::InvalidState( 88 | "Received a message while not attached to a realm", 89 | ))), 90 | } 91 | } 92 | 93 | pub fn handle_publish( 94 | &mut self, 95 | request_id: u64, 96 | options: PublishOptions, 97 | topic: URI, 98 | args: Option, 99 | kwargs: Option, 100 | ) -> WampResult<()> { 101 | debug!( 102 | "Responding to publish message (id: {}, topic: {})", 103 | request_id, topic.uri 104 | ); 105 | match self.realm { 106 | Some(ref realm) => { 107 | let realm = realm.lock().unwrap(); 108 | let manager = &realm.subscription_manager; 109 | let publication_id = random_id(); 110 | let mut event_message = Message::Event( 111 | 1, 112 | publication_id, 113 | EventDetails::new(), 114 | args.clone(), 115 | kwargs.clone(), 116 | ); 117 | let my_id = { self.info.lock().unwrap().id }; 118 | info!("Current topic tree: {:?}", manager.subscriptions); 119 | for (subscriber, topic_id, policy) in manager.subscriptions.filter(topic.clone()) { 120 | if subscriber.lock().unwrap().id != my_id { 121 | if let Message::Event( 122 | ref mut old_topic, 123 | ref _publish_id, 124 | ref mut details, 125 | ref _args, 126 | ref _kwargs, 127 | ) = event_message 128 | { 129 | *old_topic = topic_id; 130 | details.topic = if policy == MatchingPolicy::Strict { 131 | None 132 | } else { 133 | Some(topic.clone()) 134 | }; 135 | } 136 | try!(send_message(subscriber, &event_message)); 137 | } 138 | } 139 | if options.should_acknowledge() { 140 | try!(send_message( 141 | &self.info, 142 | &Message::Published(request_id, publication_id) 143 | )); 144 | } 145 | Ok(()) 146 | } 147 | None => Err(Error::new(ErrorKind::InvalidState( 148 | "Received a message while not attached to a realm", 149 | ))), 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/router/pubsub/patterns.rs: -------------------------------------------------------------------------------- 1 | //! Contains the `SubscriptionPatternNode` struct, which is used for constructing a trie corresponding 2 | //! to pattern based subscription 3 | use super::super::{random_id, ConnectionInfo}; 4 | use itertools::Itertools; 5 | use messages::Reason; 6 | use std::collections::HashMap; 7 | use std::fmt::{self, Debug, Formatter}; 8 | use std::mem; 9 | use std::slice::Iter; 10 | use std::sync::{Arc, Mutex}; 11 | use {MatchingPolicy, ID, URI}; 12 | 13 | /// Contains a trie corresponding to the subscription patterns that connections have requested. 14 | /// 15 | /// Each level of the trie corresponds to a fragment of a uri between the '.' character. 16 | /// Thus each subscription that starts with 'com' for example will be grouped together. 17 | /// Subscriptions can be added and removed, and the connections that match a particular URI 18 | /// can be found using the `get_registrant_for()` method. 19 | /// 20 | 21 | pub struct SubscriptionPatternNode { 22 | edges: HashMap>, 23 | connections: Vec>, 24 | prefix_connections: Vec>, 25 | id: ID, 26 | prefix_id: ID, 27 | } 28 | 29 | /// Represents data that a pattern trie will hold 30 | pub trait PatternData { 31 | fn get_id(&self) -> ID; 32 | } 33 | 34 | struct DataWrapper { 35 | subscriber: P, 36 | policy: MatchingPolicy, 37 | } 38 | 39 | /// A lazy iterator that traverses the pattern trie. See `SubscriptionPatternNode` for more. 40 | pub struct MatchIterator<'a, P> 41 | where 42 | P: PatternData, 43 | P: 'a, 44 | { 45 | uri: Vec, 46 | current: Box>, 47 | } 48 | 49 | struct StackFrame<'a, P> 50 | where 51 | P: PatternData, 52 | P: 'a, 53 | { 54 | node: &'a SubscriptionPatternNode

, 55 | state: IterState<'a, P>, 56 | depth: usize, 57 | parent: Option>>, 58 | } 59 | 60 | /// Represents an error caused during adding or removing patterns 61 | #[derive(Debug)] 62 | pub struct PatternError { 63 | reason: Reason, 64 | } 65 | 66 | #[derive(Clone)] 67 | enum IterState<'a, P: PatternData> 68 | where 69 | P: PatternData, 70 | P: 'a, 71 | { 72 | None, 73 | Wildcard, 74 | Strict, 75 | Prefix(Iter<'a, DataWrapper

>), 76 | PrefixComplete, 77 | Subs(Iter<'a, DataWrapper

>), 78 | AllComplete, 79 | } 80 | 81 | impl PatternError { 82 | #[inline] 83 | pub fn new(reason: Reason) -> PatternError { 84 | PatternError { reason: reason } 85 | } 86 | 87 | pub fn reason(self) -> Reason { 88 | self.reason 89 | } 90 | } 91 | 92 | impl PatternData for Arc> { 93 | fn get_id(&self) -> ID { 94 | self.lock().unwrap().id 95 | } 96 | } 97 | 98 | impl<'a, P: PatternData> Debug for IterState<'a, P> { 99 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 100 | write!( 101 | f, 102 | "{}", 103 | match *self { 104 | IterState::None => "None", 105 | IterState::Wildcard => "Wildcard", 106 | IterState::Strict => "Strict", 107 | IterState::Prefix(_) => "Prefix", 108 | IterState::PrefixComplete => "PrefixComplete", 109 | IterState::Subs(_) => "Subs", 110 | IterState::AllComplete => "AllComplete", 111 | } 112 | ) 113 | } 114 | } 115 | 116 | impl Debug for SubscriptionPatternNode

{ 117 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 118 | self.fmt_with_indent(f, 0) 119 | } 120 | } 121 | 122 | impl SubscriptionPatternNode

{ 123 | fn fmt_with_indent(&self, f: &mut Formatter, indent: usize) -> fmt::Result { 124 | try!(writeln!( 125 | f, 126 | "{} pre: {:?} subs: {:?}", 127 | self.id, 128 | self.prefix_connections 129 | .iter() 130 | .map(|sub| sub.subscriber.get_id()) 131 | .join(","), 132 | self.connections 133 | .iter() 134 | .map(|sub| sub.subscriber.get_id()) 135 | .join(","), 136 | )); 137 | for (chunk, node) in &self.edges { 138 | for _ in 0..indent * 2 { 139 | try!(write!(f, " ")); 140 | } 141 | try!(write!(f, "{} - ", chunk)); 142 | try!(node.fmt_with_indent(f, indent + 1)); 143 | } 144 | Ok(()) 145 | } 146 | 147 | /// Add a new subscription to the pattern trie with the given pattern and matching policy. 148 | pub fn subscribe_with( 149 | &mut self, 150 | topic: &URI, 151 | subscriber: P, 152 | matching_policy: MatchingPolicy, 153 | ) -> Result { 154 | let mut uri_bits = topic.uri.split('.'); 155 | let initial = match uri_bits.next() { 156 | Some(initial) => initial, 157 | None => return Err(PatternError::new(Reason::InvalidURI)), 158 | }; 159 | let edge = self.edges 160 | .entry(initial.to_string()) 161 | .or_insert_with(SubscriptionPatternNode::new); 162 | edge.add_subscription(uri_bits, subscriber, matching_policy) 163 | } 164 | 165 | /// Removes a subscription from the pattern trie. 166 | pub fn unsubscribe_with( 167 | &mut self, 168 | topic: &str, 169 | subscriber: &P, 170 | is_prefix: bool, 171 | ) -> Result { 172 | let uri_bits = topic.split('.'); 173 | self.remove_subscription(uri_bits, subscriber.get_id(), is_prefix) 174 | } 175 | 176 | /// Constructs a new SubscriptionPatternNode to be used as the root of the trie 177 | #[inline] 178 | pub fn new() -> SubscriptionPatternNode

{ 179 | SubscriptionPatternNode { 180 | edges: HashMap::new(), 181 | connections: Vec::new(), 182 | prefix_connections: Vec::new(), 183 | id: random_id(), 184 | prefix_id: random_id(), 185 | } 186 | } 187 | 188 | fn add_subscription<'a, I>( 189 | &mut self, 190 | mut uri_bits: I, 191 | subscriber: P, 192 | matching_policy: MatchingPolicy, 193 | ) -> Result 194 | where 195 | I: Iterator, 196 | { 197 | match uri_bits.next() { 198 | Some(uri_bit) => { 199 | if uri_bit.is_empty() && matching_policy != MatchingPolicy::Wildcard { 200 | return Err(PatternError::new(Reason::InvalidURI)); 201 | } 202 | let edge = self.edges 203 | .entry(uri_bit.to_string()) 204 | .or_insert_with(SubscriptionPatternNode::new); 205 | edge.add_subscription(uri_bits, subscriber, matching_policy) 206 | } 207 | None => { 208 | if matching_policy == MatchingPolicy::Prefix { 209 | self.prefix_connections.push(DataWrapper { 210 | subscriber: subscriber, 211 | policy: matching_policy, 212 | }); 213 | Ok(self.prefix_id) 214 | } else { 215 | self.connections.push(DataWrapper { 216 | subscriber: subscriber, 217 | policy: matching_policy, 218 | }); 219 | Ok(self.id) 220 | } 221 | } 222 | } 223 | } 224 | 225 | fn remove_subscription<'a, I>( 226 | &mut self, 227 | mut uri_bits: I, 228 | subscriber_id: u64, 229 | is_prefix: bool, 230 | ) -> Result 231 | where 232 | I: Iterator, 233 | { 234 | // TODO consider deleting nodes in the tree if they are no longer in use. 235 | match uri_bits.next() { 236 | Some(uri_bit) => { 237 | if let Some(edge) = self.edges.get_mut(uri_bit) { 238 | edge.remove_subscription(uri_bits, subscriber_id, is_prefix) 239 | } else { 240 | return Err(PatternError::new(Reason::InvalidURI)); 241 | } 242 | } 243 | None => { 244 | if is_prefix { 245 | self.prefix_connections 246 | .retain(|sub| sub.subscriber.get_id() != subscriber_id); 247 | Ok(self.prefix_id) 248 | } else { 249 | self.connections 250 | .retain(|sub| sub.subscriber.get_id() != subscriber_id); 251 | Ok(self.id) 252 | } 253 | } 254 | } 255 | } 256 | 257 | /// Constructs a lazy iterator over all of the connections whose subscription patterns 258 | /// match the given uri. 259 | /// 260 | /// This iterator returns a triple with the connection info, the id of the subscription and 261 | /// the matching policy used when the subscription was created. 262 | pub fn filter(&self, topic: URI) -> MatchIterator

{ 263 | MatchIterator { 264 | current: Box::new(StackFrame { 265 | node: self, 266 | depth: 0, 267 | state: IterState::None, 268 | parent: None, 269 | }), 270 | uri: topic.uri.split('.').map(|s| s.to_string()).collect(), 271 | } 272 | } 273 | } 274 | 275 | impl<'a, P: PatternData> MatchIterator<'a, P> { 276 | fn push(&mut self, child: &'a SubscriptionPatternNode

) { 277 | let new_node = Box::new(StackFrame { 278 | parent: None, 279 | depth: self.current.depth + 1, 280 | node: child, 281 | state: IterState::None, 282 | }); 283 | let parent = mem::replace(&mut self.current, new_node); 284 | self.current.parent = Some(parent); 285 | } 286 | 287 | /// Moves through the subscription tree, looking for the next set of connections that match the 288 | /// given uri. 289 | fn traverse(&mut self) -> Option<(&'a P, ID, MatchingPolicy)> { 290 | // This method functions as a push down automata. For each node, it starts by iterating 291 | // through the data that match a prefix of the uri 292 | // Then when that's done, it checks if the uri has been fully processed, and if so, iterates 293 | // through the connections that require exact matching 294 | // Otherwise, it pushes the current node on the stack, consumes another chunk of the uri 295 | // and moves on to any children that use wildcard matching. 296 | // Once it is finished traversing that part of the tree, it re-consumes the same chunk 297 | // of the URI, and moves on to any children that match the chunk exactly. 298 | // After all that is exhausted, it will pop the node of the stack and return to its parent 299 | match self.current.state { 300 | IterState::None => { 301 | self.current.state = IterState::Prefix(self.current.node.prefix_connections.iter()) 302 | } 303 | IterState::Prefix(_) => { 304 | self.current.state = IterState::PrefixComplete; 305 | } 306 | IterState::PrefixComplete => { 307 | if self.current.depth == self.uri.len() { 308 | self.current.state = IterState::Subs(self.current.node.connections.iter()); 309 | } else if let Some(child) = self.current.node.edges.get("") { 310 | self.current.state = IterState::Wildcard; 311 | self.push(child); 312 | } else if let Some(child) = 313 | self.current.node.edges.get(&self.uri[self.current.depth]) 314 | { 315 | self.current.state = IterState::Strict; 316 | self.push(child); 317 | } else { 318 | self.current.state = IterState::AllComplete; 319 | } 320 | } 321 | IterState::Wildcard => { 322 | if self.current.depth == self.uri.len() { 323 | self.current.state = IterState::AllComplete; 324 | } else if let Some(child) = 325 | self.current.node.edges.get(&self.uri[self.current.depth]) 326 | { 327 | self.current.state = IterState::Strict; 328 | self.push(child); 329 | } else { 330 | self.current.state = IterState::AllComplete; 331 | } 332 | } 333 | IterState::Strict => { 334 | self.current.state = IterState::AllComplete; 335 | } 336 | IterState::Subs(_) => { 337 | self.current.state = IterState::AllComplete; 338 | } 339 | IterState::AllComplete => { 340 | if self.current.depth == 0 { 341 | return None; 342 | } else { 343 | let parent = self.current.parent.take(); 344 | mem::replace(&mut self.current, parent.unwrap()); 345 | } 346 | } 347 | }; 348 | self.next() 349 | } 350 | } 351 | 352 | impl<'a, P: PatternData> Iterator for MatchIterator<'a, P> { 353 | type Item = (&'a P, ID, MatchingPolicy); 354 | 355 | fn next(&mut self) -> Option<(&'a P, ID, MatchingPolicy)> { 356 | let prefix_id = self.current.node.prefix_id; 357 | let node_id = self.current.node.id; 358 | // If we are currently iterating through connections, continue iterating 359 | match self.current.state { 360 | IterState::Prefix(ref mut prefix_iter) => { 361 | let next = prefix_iter.next(); 362 | if let Some(next) = next { 363 | return Some((&next.subscriber, prefix_id, next.policy)); 364 | } 365 | } 366 | IterState::Subs(ref mut sub_iter) => { 367 | let next = sub_iter.next(); 368 | if let Some(next) = next { 369 | return Some((&next.subscriber, node_id, next.policy)); 370 | } 371 | } 372 | _ => {} 373 | }; 374 | 375 | // Otherwise, it is time to traverse through the tree. 376 | self.traverse() 377 | } 378 | } 379 | 380 | #[cfg(test)] 381 | mod test { 382 | use super::{PatternData, SubscriptionPatternNode}; 383 | use {MatchingPolicy, ID, URI}; 384 | 385 | #[derive(Clone)] 386 | struct MockData { 387 | id: ID, 388 | } 389 | 390 | impl PatternData for MockData { 391 | fn get_id(&self) -> ID { 392 | self.id 393 | } 394 | } 395 | impl MockData { 396 | pub fn new(id: ID) -> MockData { 397 | MockData { id: id } 398 | } 399 | } 400 | 401 | #[test] 402 | fn adding_patterns() { 403 | let connection1 = MockData::new(1); 404 | let connection2 = MockData::new(2); 405 | let connection3 = MockData::new(3); 406 | let connection4 = MockData::new(4); 407 | let mut root = SubscriptionPatternNode::new(); 408 | 409 | let ids = [ 410 | root.subscribe_with( 411 | &URI::new("com.example.test..topic"), 412 | connection1, 413 | MatchingPolicy::Wildcard, 414 | ).unwrap(), 415 | root.subscribe_with( 416 | &URI::new("com.example.test.specific.topic"), 417 | connection2, 418 | MatchingPolicy::Strict, 419 | ).unwrap(), 420 | root.subscribe_with( 421 | &URI::new("com.example"), 422 | connection3, 423 | MatchingPolicy::Prefix, 424 | ).unwrap(), 425 | root.subscribe_with( 426 | &URI::new("com.example.test"), 427 | connection4, 428 | MatchingPolicy::Prefix, 429 | ).unwrap(), 430 | ]; 431 | 432 | assert_eq!( 433 | root.filter(URI::new("com.example.test.specific.topic")) 434 | .map(|(_connection, id, _policy)| id) 435 | .collect::>(), 436 | vec![ids[2], ids[3], ids[0], ids[1]] 437 | ); 438 | } 439 | 440 | #[test] 441 | fn removing_patterns() { 442 | let connection1 = MockData::new(1); 443 | let connection2 = MockData::new(2); 444 | let connection3 = MockData::new(3); 445 | let connection4 = MockData::new(4); 446 | let mut root = SubscriptionPatternNode::new(); 447 | 448 | let ids = [ 449 | root.subscribe_with( 450 | &URI::new("com.example.test..topic"), 451 | connection1.clone(), 452 | MatchingPolicy::Wildcard, 453 | ).unwrap(), 454 | root.subscribe_with( 455 | &URI::new("com.example.test.specific.topic"), 456 | connection2, 457 | MatchingPolicy::Strict, 458 | ).unwrap(), 459 | root.subscribe_with( 460 | &URI::new("com.example"), 461 | connection3, 462 | MatchingPolicy::Prefix, 463 | ).unwrap(), 464 | root.subscribe_with( 465 | &URI::new("com.example.test"), 466 | connection4.clone(), 467 | MatchingPolicy::Prefix, 468 | ).unwrap(), 469 | ]; 470 | 471 | root.unsubscribe_with("com.example.test..topic", &connection1, false) 472 | .unwrap(); 473 | root.unsubscribe_with("com.example.test", &connection4, true) 474 | .unwrap(); 475 | 476 | assert_eq!( 477 | root.filter(URI::new("com.example.test.specific.topic")) 478 | .map(|(_connection, id, _policy)| id) 479 | .collect::>(), 480 | vec![ids[2], ids[1]] 481 | ) 482 | } 483 | } 484 | -------------------------------------------------------------------------------- /src/router/rpc/mod.rs: -------------------------------------------------------------------------------- 1 | mod patterns; 2 | 3 | use std::sync::Arc; 4 | 5 | pub use router::rpc::patterns::RegistrationPatternNode; 6 | 7 | use super::{random_id, ConnectionHandler}; 8 | 9 | use messages::{CallOptions, ErrorType, InvocationDetails, Message, Reason, RegisterOptions, 10 | ResultDetails, YieldOptions, URI}; 11 | use router::messaging::send_message; 12 | use {Dict, Error, ErrorKind, List, MatchingPolicy, WampResult, ID}; 13 | 14 | impl ConnectionHandler { 15 | pub fn handle_register( 16 | &mut self, 17 | request_id: ID, 18 | options: RegisterOptions, 19 | procedure: URI, 20 | ) -> WampResult<()> { 21 | debug!( 22 | "Responding to register message (id: {}, procedure: {})", 23 | request_id, procedure.uri 24 | ); 25 | match self.realm { 26 | Some(ref realm) => { 27 | let mut realm = realm.lock().unwrap(); 28 | let manager = &mut realm.registration_manager; 29 | let procedure_id = { 30 | let procedure_id = match manager.registrations.register_with( 31 | &procedure, 32 | Arc::clone(&self.info), 33 | options.pattern_match, 34 | options.invocation_policy, 35 | ) { 36 | Ok(procedure_id) => procedure_id, 37 | Err(e) => { 38 | return Err(Error::new(ErrorKind::ErrorReason( 39 | ErrorType::Register, 40 | request_id, 41 | e.reason(), 42 | ))) 43 | } 44 | }; 45 | self.registered_procedures.push(procedure_id); 46 | procedure_id 47 | }; 48 | manager.registration_ids_to_uris.insert( 49 | procedure_id, 50 | ( 51 | procedure.uri, 52 | options.pattern_match == MatchingPolicy::Prefix, 53 | ), 54 | ); 55 | send_message(&self.info, &Message::Registered(request_id, procedure_id)) 56 | } 57 | None => Err(Error::new(ErrorKind::InvalidState( 58 | "Received a message while not attached to a realm", 59 | ))), 60 | } 61 | } 62 | 63 | pub fn handle_unregister(&mut self, request_id: ID, procedure_id: ID) -> WampResult<()> { 64 | match self.realm { 65 | Some(ref realm) => { 66 | let mut realm = realm.lock().unwrap(); 67 | let manager = &mut realm.registration_manager; 68 | let (procedure_uri, is_prefix) = 69 | match manager.registration_ids_to_uris.get(&procedure_id) { 70 | Some(&(ref uri, is_prefix)) => (uri.clone(), is_prefix), 71 | None => { 72 | return Err(Error::new(ErrorKind::ErrorReason( 73 | ErrorType::Unregister, 74 | request_id, 75 | Reason::NoSuchProcedure, 76 | ))) 77 | } 78 | }; 79 | 80 | let procedure_id = match manager.registrations.unregister_with( 81 | &procedure_uri, 82 | &self.info, 83 | is_prefix, 84 | ) { 85 | Ok(procedure_id) => procedure_id, 86 | Err(e) => { 87 | return Err(Error::new(ErrorKind::ErrorReason( 88 | ErrorType::Unregister, 89 | request_id, 90 | e.reason(), 91 | ))) 92 | } 93 | }; 94 | self.registered_procedures.retain(|id| *id != procedure_id); 95 | send_message(&self.info, &Message::Unregistered(request_id)) 96 | } 97 | None => Err(Error::new(ErrorKind::InvalidState( 98 | "Received a message while not attached to a realm", 99 | ))), 100 | } 101 | } 102 | 103 | pub fn handle_call( 104 | &mut self, 105 | request_id: ID, 106 | _options: CallOptions, 107 | procedure: URI, 108 | args: Option, 109 | kwargs: Option, 110 | ) -> WampResult<()> { 111 | debug!( 112 | "Responding to call message (id: {}, procedure: {})", 113 | request_id, procedure.uri 114 | ); 115 | match self.realm { 116 | Some(ref realm) => { 117 | let mut realm = realm.lock().unwrap(); 118 | let manager = &mut realm.registration_manager; 119 | let invocation_id = random_id(); 120 | info!("Current procedure tree: {:?}", manager.registrations); 121 | let (registrant, procedure_id, policy) = 122 | match manager.registrations.get_registrant_for(procedure.clone()) { 123 | Ok(registrant) => registrant, 124 | Err(e) => { 125 | return Err(Error::new(ErrorKind::ErrorReason( 126 | ErrorType::Call, 127 | request_id, 128 | e.reason(), 129 | ))) 130 | } 131 | }; 132 | manager 133 | .active_calls 134 | .insert(invocation_id, (request_id, Arc::clone(&self.info))); 135 | let mut details = InvocationDetails::new(); 136 | details.procedure = if policy == MatchingPolicy::Strict { 137 | None 138 | } else { 139 | Some(procedure) 140 | }; 141 | let invocation_message = 142 | Message::Invocation(invocation_id, procedure_id, details, args, kwargs); 143 | try!(send_message(registrant, &invocation_message)); 144 | 145 | Ok(()) 146 | } 147 | None => Err(Error::new(ErrorKind::InvalidState( 148 | "Received a message while not attached to a realm", 149 | ))), 150 | } 151 | } 152 | 153 | pub fn handle_yield( 154 | &mut self, 155 | invocation_id: ID, 156 | _options: YieldOptions, 157 | args: Option, 158 | kwargs: Option, 159 | ) -> WampResult<()> { 160 | debug!("Responding to yield message (id: {})", invocation_id); 161 | match self.realm { 162 | Some(ref realm) => { 163 | let mut realm = realm.lock().unwrap(); 164 | let manager = &mut realm.registration_manager; 165 | if let Some((call_id, callee)) = manager.active_calls.remove(&invocation_id) { 166 | let result_message = 167 | Message::Result(call_id, ResultDetails::new(), args, kwargs); 168 | send_message(&callee, &result_message) 169 | } else { 170 | Err(Error::new(ErrorKind::InvalidState( 171 | "Received a yield message for a call that wasn't sent", 172 | ))) 173 | } 174 | } 175 | None => Err(Error::new(ErrorKind::InvalidState( 176 | "Received a message while not attached to a realm", 177 | ))), 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/router/rpc/patterns.rs: -------------------------------------------------------------------------------- 1 | //! Contains the `RegistrationPatternNode` struct, which is used for constructing a trie corresponding 2 | //! to pattern based registration 3 | use super::super::{random_id, ConnectionInfo}; 4 | use itertools::Itertools; 5 | use messages::Reason; 6 | use rand::thread_rng; 7 | use rand::Rng; 8 | use std::cell::RefCell; 9 | use std::collections::HashMap; 10 | use std::fmt::{self, Debug, Formatter}; 11 | use std::sync::{Arc, Mutex}; 12 | use {InvocationPolicy, MatchingPolicy, ID, URI}; 13 | 14 | /// Contains a trie corresponding to the registration patterns that connections have requested. 15 | /// 16 | /// Each level of the trie corresponds to a fragment of a uri between the '.' character. 17 | /// Thus each registration that starts with 'com' for example will be grouped together. 18 | /// Registrations can be added and removed, and the connections that match a particular URI 19 | /// can be iterated over using the `filter()` method. 20 | 21 | pub struct RegistrationPatternNode { 22 | edges: HashMap>, 23 | connections: ProcdureCollection

, 24 | prefix_connections: ProcdureCollection

, 25 | id: ID, 26 | prefix_id: ID, 27 | } 28 | 29 | /// Represents data that a pattern trie will hold 30 | pub trait PatternData { 31 | fn get_id(&self) -> ID; 32 | } 33 | 34 | struct DataWrapper { 35 | registrant: P, 36 | policy: MatchingPolicy, 37 | } 38 | 39 | struct ProcdureCollection { 40 | invocation_policy: InvocationPolicy, 41 | round_robin_counter: RefCell, 42 | procedures: Vec>, 43 | } 44 | 45 | /// Represents an error caused during adding or removing patterns 46 | #[derive(Debug)] 47 | pub struct PatternError { 48 | reason: Reason, 49 | } 50 | 51 | impl PatternError { 52 | #[inline] 53 | pub fn new(reason: Reason) -> PatternError { 54 | PatternError { reason: reason } 55 | } 56 | 57 | pub fn reason(self) -> Reason { 58 | self.reason 59 | } 60 | } 61 | 62 | impl PatternData for Arc> { 63 | fn get_id(&self) -> ID { 64 | self.lock().unwrap().id 65 | } 66 | } 67 | 68 | impl Debug for RegistrationPatternNode

{ 69 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 70 | self.fmt_with_indent(f, 0) 71 | } 72 | } 73 | 74 | impl Default for RegistrationPatternNode

{ 75 | fn default() -> RegistrationPatternNode

{ 76 | RegistrationPatternNode::new() 77 | } 78 | } 79 | 80 | impl ProcdureCollection

{ 81 | fn add_procedure( 82 | &mut self, 83 | registrant: P, 84 | matching_policy: MatchingPolicy, 85 | invocation_policy: InvocationPolicy, 86 | ) -> Result<(), PatternError> { 87 | if self.procedures.is_empty() 88 | || (invocation_policy == self.invocation_policy 89 | && invocation_policy != InvocationPolicy::Single) 90 | { 91 | self.procedures.push(DataWrapper { 92 | registrant: registrant, 93 | policy: matching_policy, 94 | }); 95 | self.invocation_policy = invocation_policy; 96 | Ok(()) 97 | } else { 98 | Err(PatternError::new(Reason::ProcedureAlreadyExists)) 99 | } 100 | } 101 | 102 | fn remove_procedure(&mut self, registrant_id: ID) { 103 | self.procedures 104 | .retain(|sub| sub.registrant.get_id() != registrant_id); 105 | } 106 | 107 | fn get_entry(&self) -> Option<&DataWrapper

> { 108 | match self.invocation_policy { 109 | InvocationPolicy::Single | InvocationPolicy::First => self.procedures.first(), 110 | InvocationPolicy::Last => self.procedures.last(), 111 | InvocationPolicy::Random => thread_rng().choose(&self.procedures), 112 | InvocationPolicy::RoundRobin => { 113 | let mut counter = self.round_robin_counter.borrow_mut(); 114 | if *counter >= self.procedures.len() { 115 | *counter = 0 116 | } 117 | let result = self.procedures.get(*counter); 118 | *counter += 1; 119 | result 120 | } 121 | } 122 | } 123 | } 124 | 125 | impl RegistrationPatternNode

{ 126 | fn fmt_with_indent(&self, f: &mut Formatter, indent: usize) -> fmt::Result { 127 | try!(writeln!( 128 | f, 129 | "{} pre: {:?} subs: {:?}", 130 | self.id, 131 | self.prefix_connections 132 | .procedures 133 | .iter() 134 | .map(|sub| sub.registrant.get_id()) 135 | .join(","), 136 | self.connections 137 | .procedures 138 | .iter() 139 | .map(|sub| sub.registrant.get_id()) 140 | .join(",") 141 | )); 142 | for (chunk, node) in &self.edges { 143 | for _ in 0..indent * 2 { 144 | try!(write!(f, " ")); 145 | } 146 | try!(write!(f, "{} - ", chunk)); 147 | try!(node.fmt_with_indent(f, indent + 1)); 148 | } 149 | Ok(()) 150 | } 151 | 152 | /// Add a new registration to the pattern trie with the given pattern and matching policy. 153 | pub fn register_with( 154 | &mut self, 155 | topic: &URI, 156 | registrant: P, 157 | matching_policy: MatchingPolicy, 158 | invocation_policy: InvocationPolicy, 159 | ) -> Result { 160 | let mut uri_bits = topic.uri.split('.'); 161 | let initial = match uri_bits.next() { 162 | Some(initial) => initial, 163 | None => return Err(PatternError::new(Reason::InvalidURI)), 164 | }; 165 | let edge = self.edges 166 | .entry(initial.to_string()) 167 | .or_insert_with(RegistrationPatternNode::new); 168 | edge.add_registration(uri_bits, registrant, matching_policy, invocation_policy) 169 | } 170 | 171 | /// Removes a registration from the pattern trie. 172 | pub fn unregister_with( 173 | &mut self, 174 | topic: &str, 175 | registrant: &P, 176 | is_prefix: bool, 177 | ) -> Result { 178 | let uri_bits = topic.split('.'); 179 | self.remove_registration(uri_bits, registrant.get_id(), is_prefix) 180 | } 181 | 182 | /// Gets a registrant that matches the given uri 183 | pub fn get_registrant_for( 184 | &self, 185 | procedure: URI, 186 | ) -> Result<(&P, ID, MatchingPolicy), PatternError> { 187 | let wrapper = self.find_registrant(&procedure.uri.split('.').collect::>(), 0); 188 | match wrapper { 189 | Some((data, id)) => Ok((&data.registrant, id, data.policy)), 190 | None => Err(PatternError::new(Reason::NoSuchProcedure)), 191 | } 192 | } 193 | 194 | /// Constructs a new RegistrationPatternNode to be used as the root of the trie 195 | #[inline] 196 | pub fn new() -> RegistrationPatternNode

{ 197 | RegistrationPatternNode { 198 | edges: HashMap::new(), 199 | connections: ProcdureCollection { 200 | invocation_policy: InvocationPolicy::Single, 201 | round_robin_counter: RefCell::new(0), 202 | procedures: Vec::new(), 203 | }, 204 | prefix_connections: ProcdureCollection { 205 | invocation_policy: InvocationPolicy::Single, 206 | round_robin_counter: RefCell::new(0), 207 | procedures: Vec::new(), 208 | }, 209 | id: random_id(), 210 | prefix_id: random_id(), 211 | } 212 | } 213 | 214 | fn add_registration<'a, I>( 215 | &mut self, 216 | mut uri_bits: I, 217 | registrant: P, 218 | matching_policy: MatchingPolicy, 219 | invocation_policy: InvocationPolicy, 220 | ) -> Result 221 | where 222 | I: Iterator, 223 | { 224 | match uri_bits.next() { 225 | Some(uri_bit) => { 226 | if uri_bit.is_empty() && matching_policy != MatchingPolicy::Wildcard { 227 | return Err(PatternError::new(Reason::InvalidURI)); 228 | } 229 | let edge = self.edges 230 | .entry(uri_bit.to_string()) 231 | .or_insert_with(RegistrationPatternNode::new); 232 | edge.add_registration(uri_bits, registrant, matching_policy, invocation_policy) 233 | } 234 | None => { 235 | if matching_policy == MatchingPolicy::Prefix { 236 | try!(self.prefix_connections.add_procedure( 237 | registrant, 238 | matching_policy, 239 | invocation_policy 240 | )); 241 | Ok(self.prefix_id) 242 | } else { 243 | try!(self.connections.add_procedure( 244 | registrant, 245 | matching_policy, 246 | invocation_policy 247 | )); 248 | Ok(self.id) 249 | } 250 | } 251 | } 252 | } 253 | 254 | fn remove_registration<'a, I>( 255 | &mut self, 256 | mut uri_bits: I, 257 | registrant_id: u64, 258 | is_prefix: bool, 259 | ) -> Result 260 | where 261 | I: Iterator, 262 | { 263 | // TODO consider deleting nodes in the tree if they are no longer in use. 264 | match uri_bits.next() { 265 | Some(uri_bit) => { 266 | if let Some(edge) = self.edges.get_mut(uri_bit) { 267 | edge.remove_registration(uri_bits, registrant_id, is_prefix) 268 | } else { 269 | return Err(PatternError::new(Reason::InvalidURI)); 270 | } 271 | } 272 | None => { 273 | if is_prefix { 274 | self.prefix_connections.remove_procedure(registrant_id); 275 | Ok(self.prefix_id) 276 | } else { 277 | self.connections.remove_procedure(registrant_id); 278 | Ok(self.id) 279 | } 280 | } 281 | } 282 | } 283 | 284 | fn find_registrant(&self, uri_bits: &[&str], depth: usize) -> Option<(&DataWrapper

, ID)> { 285 | if depth == uri_bits.len() { 286 | if let Some(registrant) = self.connections.get_entry() { 287 | Some((registrant, self.id)) 288 | } else if let Some(registrant) = self.prefix_connections.get_entry() { 289 | Some((registrant, self.prefix_id)) 290 | } else { 291 | None 292 | } 293 | } else if let Some((registrant, id)) = self.recurse(uri_bits, depth) { 294 | Some((registrant, id)) 295 | } else if let Some(registrant) = self.prefix_connections.get_entry() { 296 | Some((registrant, self.prefix_id)) 297 | } else { 298 | None 299 | } 300 | } 301 | 302 | fn recurse(&self, uri_bits: &[&str], depth: usize) -> Option<(&DataWrapper

, ID)> { 303 | if let Some(edge) = self.edges.get(uri_bits[depth]) { 304 | if let Some(registrant) = edge.find_registrant(uri_bits, depth + 1) { 305 | return Some(registrant); 306 | } 307 | } 308 | if let Some(edge) = self.edges.get("") { 309 | if let Some(registrant) = edge.find_registrant(uri_bits, depth + 1) { 310 | return Some(registrant); 311 | } 312 | } 313 | None 314 | } 315 | } 316 | 317 | #[cfg(test)] 318 | mod test { 319 | use super::{PatternData, RegistrationPatternNode}; 320 | use {InvocationPolicy, MatchingPolicy, ID, URI}; 321 | 322 | #[derive(Clone)] 323 | struct MockData { 324 | id: ID, 325 | } 326 | 327 | impl PatternData for MockData { 328 | fn get_id(&self) -> ID { 329 | self.id 330 | } 331 | } 332 | impl MockData { 333 | pub fn new(id: ID) -> MockData { 334 | MockData { id: id } 335 | } 336 | } 337 | 338 | #[test] 339 | fn adding_patterns() { 340 | let connection1 = MockData::new(1); 341 | let connection2 = MockData::new(2); 342 | let connection3 = MockData::new(3); 343 | let connection4 = MockData::new(4); 344 | let mut root = RegistrationPatternNode::new(); 345 | 346 | let ids = [ 347 | root.register_with( 348 | &URI::new("com.example.test..topic"), 349 | connection1, 350 | MatchingPolicy::Wildcard, 351 | InvocationPolicy::Single, 352 | ).unwrap(), 353 | root.register_with( 354 | &URI::new("com.example.test.specific.topic"), 355 | connection2, 356 | MatchingPolicy::Strict, 357 | InvocationPolicy::Single, 358 | ).unwrap(), 359 | root.register_with( 360 | &URI::new("com.example"), 361 | connection3, 362 | MatchingPolicy::Prefix, 363 | InvocationPolicy::Single, 364 | ).unwrap(), 365 | root.register_with( 366 | &URI::new("com.example.test"), 367 | connection4, 368 | MatchingPolicy::Prefix, 369 | InvocationPolicy::Single, 370 | ).unwrap(), 371 | ]; 372 | println!("ids: {:?}", ids); 373 | 374 | assert_eq!( 375 | root.get_registrant_for(URI::new("com.example.test.specific.topic")) 376 | .unwrap() 377 | .1, 378 | ids[1] 379 | ); 380 | assert_eq!( 381 | root.get_registrant_for(URI::new("com.example.test.another.topic")) 382 | .unwrap() 383 | .1, 384 | ids[0] 385 | ); 386 | assert_eq!( 387 | root.get_registrant_for(URI::new("com.example.test.another")) 388 | .unwrap() 389 | .1, 390 | ids[3] 391 | ); 392 | assert_eq!( 393 | root.get_registrant_for(URI::new("com.example")).unwrap().1, 394 | ids[2] 395 | ); 396 | } 397 | 398 | #[test] 399 | fn removing_patterns() { 400 | let connection1 = MockData::new(1); 401 | let connection2 = MockData::new(2); 402 | let connection3 = MockData::new(3); 403 | let connection4 = MockData::new(4); 404 | let mut root = RegistrationPatternNode::new(); 405 | 406 | let ids = [ 407 | root.register_with( 408 | &URI::new("com.example.test..topic"), 409 | connection1.clone(), 410 | MatchingPolicy::Wildcard, 411 | InvocationPolicy::Single, 412 | ).unwrap(), 413 | root.register_with( 414 | &URI::new("com.example.test.specific.topic"), 415 | connection2, 416 | MatchingPolicy::Strict, 417 | InvocationPolicy::Single, 418 | ).unwrap(), 419 | root.register_with( 420 | &URI::new("com.example"), 421 | connection3, 422 | MatchingPolicy::Prefix, 423 | InvocationPolicy::Single, 424 | ).unwrap(), 425 | root.register_with( 426 | &URI::new("com.example.test"), 427 | connection4.clone(), 428 | MatchingPolicy::Prefix, 429 | InvocationPolicy::Single, 430 | ).unwrap(), 431 | ]; 432 | 433 | root.unregister_with("com.example.test..topic", &connection1, false) 434 | .unwrap(); 435 | root.unregister_with("com.example.test", &connection4, true) 436 | .unwrap(); 437 | 438 | println!("ids: {:?}", ids); 439 | assert_eq!( 440 | root.get_registrant_for(URI::new("com.example.test.specific.topic")) 441 | .unwrap() 442 | .1, 443 | ids[1] 444 | ); 445 | } 446 | } 447 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use rmp::encode::{write_map_len, write_str, ValueWriteError}; 2 | use rmp::Marker; 3 | use rmp_serde::encode::VariantWriter; 4 | use std::io::Write; 5 | 6 | pub struct StructMapWriter; 7 | 8 | impl VariantWriter for StructMapWriter { 9 | fn write_struct_len(&self, wr: &mut W, len: u32) -> Result 10 | where 11 | W: Write, 12 | { 13 | write_map_len(wr, len) 14 | } 15 | 16 | fn write_field_name(&self, wr: &mut W, _key: &str) -> Result<(), ValueWriteError> 17 | where 18 | W: Write, 19 | { 20 | write_str(wr, _key) 21 | } 22 | } 23 | --------------------------------------------------------------------------------