├── .gitignore ├── examples ├── router.rs ├── endpoint.rs ├── api_user.rs └── pubsubclient.rs ├── src ├── utils.rs ├── lib.rs ├── router │ ├── handshake.rs │ ├── pubsub │ │ ├── mod.rs │ │ └── patterns.rs │ ├── rpc │ │ ├── mod.rs │ │ └── patterns.rs │ ├── mod.rs │ └── messaging.rs ├── messages │ ├── types │ │ ├── roles.rs │ │ ├── options.rs │ │ ├── mod.rs │ │ ├── error.rs │ │ └── value.rs │ └── mod.rs └── client.rs ├── Cargo.toml ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /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().unwrap(); 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/utils.rs: -------------------------------------------------------------------------------- 1 | use rmp::Marker; 2 | use rmp::encode::{ValueWriteError, write_map_len, write_str}; 3 | use rmp_serde::encode::VariantWriter; 4 | use std::io::Write; 5 | 6 | 7 | pub struct StructMapWriter; 8 | 9 | impl VariantWriter for StructMapWriter { 10 | fn write_struct_len(&self, wr: &mut W, len: u32) -> Result 11 | where 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 W: Write 18 | { 19 | write_str(wr, _key) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /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 | 16 | [dependencies] 17 | serde = "1.0" 18 | serde_json = "1.0" 19 | serde_derive = "1.0" 20 | url = "1.4" 21 | log = "0.3" 22 | env_logger = "0.3" 23 | ws = "0.7" 24 | rmp = "0.8" 25 | rmp-serde = "0.13.1" 26 | rand = "0.3" 27 | eventual = "0.1.7" 28 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/endpoint.rs: -------------------------------------------------------------------------------- 1 | extern crate wamp; 2 | extern crate eventual; 3 | #[macro_use] 4 | extern crate log; 5 | extern crate env_logger; 6 | 7 | use wamp::client::Connection; 8 | use wamp::{URI, Value, Dict, List, CallResult, ArgList}; 9 | use std::io; 10 | use eventual::Async; 11 | 12 | fn addition_callback(args: List, _kwargs: Dict) -> CallResult<(Option, Option)> { 13 | info!("Performing addition"); 14 | try!(args.verify_len(2)); 15 | let a = try!(args.get_int(0)).unwrap(); 16 | let b = try!(args.get_int(1)).unwrap(); 17 | Ok((Some(vec![Value::Integer(a + b)]), None)) 18 | } 19 | 20 | fn multiplication_callback(args: List, _kwargs: Dict) -> CallResult<(Option, Option)> { 21 | info!("Performing multiplication"); 22 | try!(args.verify_len(2)); 23 | let a = try!(args.get_int(0)).unwrap(); 24 | let b = try!(args.get_int(1)).unwrap(); 25 | Ok((Some(vec![Value::Integer(a * b)]), None)) 26 | } 27 | 28 | fn echo_callback(args: List, kwargs: Dict) -> CallResult<(Option, Option)> { 29 | info!("Performing echo"); 30 | Ok((Some(args), Some(kwargs))) 31 | } 32 | 33 | fn main() { 34 | env_logger::init().unwrap(); 35 | let connection = Connection::new("ws://127.0.0.1:8090/ws", "realm1"); 36 | info!("Connecting"); 37 | let mut client = connection.connect().unwrap(); 38 | 39 | info!("Connected"); 40 | info!("Registering Addition Procedure"); 41 | client.register(URI::new("ca.test.add"), Box::new(addition_callback)).unwrap().await().unwrap(); 42 | 43 | info!("Registering Multiplication Procedure"); 44 | let mult_reg = client.register(URI::new("ca.test.mult"), Box::new(multiplication_callback)).unwrap().await().unwrap(); 45 | 46 | info!("Unregistering Multiplication Procedure"); 47 | client.unregister(mult_reg).unwrap().await().unwrap(); 48 | 49 | info!("Registering Echo Procedure"); 50 | client.register(URI::new("ca.test.echo"), Box::new(echo_callback)).unwrap().await().unwrap(); 51 | 52 | println!("Press enter to quit"); 53 | let mut input = String::new(); 54 | io::stdin().read_line(&mut input).unwrap(); 55 | client.shutdown().unwrap().await().unwrap(); 56 | } 57 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate serde; 2 | extern crate serde_json; 3 | #[macro_use] 4 | extern crate serde_derive; 5 | extern crate ws; 6 | extern crate url; 7 | extern crate rmp; 8 | extern crate rmp_serde; 9 | extern crate rand; 10 | extern crate eventual; 11 | 12 | #[macro_use] 13 | extern crate log; 14 | 15 | mod messages; 16 | mod utils; 17 | pub mod client; 18 | pub mod router; 19 | 20 | use ws::Error as WSError; 21 | use std::fmt; 22 | use url::ParseError; 23 | use std::sync::mpsc::SendError; 24 | use serde_json::Error as JSONError; 25 | use rmp_serde::decode::Error as MsgPackError; 26 | 27 | pub use messages::{URI, Dict, List, Value, Reason, MatchingPolicy, InvocationPolicy, CallError, ArgList, ArgDict}; 28 | use messages::{ErrorType, Message}; 29 | pub use client::{Client, Connection}; 30 | pub use router::Router; 31 | 32 | pub type CallResult = Result; 33 | pub type WampResult = Result; 34 | pub type ID = u64; 35 | 36 | #[derive(Debug)] 37 | pub struct Error { 38 | kind: ErrorKind 39 | } 40 | 41 | #[derive(Debug)] 42 | pub enum ErrorKind { 43 | WSError(WSError), 44 | URLError(ParseError), 45 | UnexpectedMessage(&'static str), // Used when a peer receives another message before Welcome or Hello 46 | ThreadError(SendError), 47 | ConnectionLost, 48 | Closing(String), 49 | JSONError(JSONError), 50 | MsgPackError(MsgPackError), 51 | MalformedData, 52 | InvalidMessageType(Message), 53 | InvalidState(&'static str), 54 | Timeout, 55 | ErrorReason(ErrorType, ID, Reason), 56 | } 57 | impl Error { 58 | fn new(kind: ErrorKind) -> Error { 59 | Error { 60 | kind: kind 61 | } 62 | } 63 | 64 | fn get_description(&self) -> String { 65 | format!("WAMP Error: {}", self.kind.description()) 66 | } 67 | 68 | #[inline] 69 | fn get_kind(self) -> ErrorKind{ 70 | self.kind 71 | } 72 | } 73 | 74 | 75 | impl fmt::Display for Error { 76 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 77 | write!(f, "{}", self.get_description()) 78 | } 79 | } 80 | 81 | impl ErrorKind { 82 | fn description(&self) -> String { 83 | match self { 84 | &ErrorKind::WSError(ref e) => e.to_string(), 85 | &ErrorKind::UnexpectedMessage(s) => s.to_string(), 86 | &ErrorKind::URLError(ref e) => e.to_string(), 87 | &ErrorKind::ThreadError(ref e) => e.to_string(), 88 | &ErrorKind::ConnectionLost => "Connection Lost".to_string(), 89 | &ErrorKind::Closing(ref s) => s.clone(), 90 | &ErrorKind::JSONError(ref e) => e.to_string(), 91 | &ErrorKind::MsgPackError(ref e) => e.to_string(), 92 | &ErrorKind::MalformedData => "Malformed Data".to_string(), 93 | &ErrorKind::InvalidMessageType(ref t) => format!("Invalid Message Type: {:?}", t), 94 | &ErrorKind::InvalidState(ref s) => s.to_string(), 95 | &ErrorKind::Timeout => "Connection timed out".to_string(), 96 | &ErrorKind::ErrorReason(_, _, ref s) => s.to_string(), 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/router/handshake.rs: -------------------------------------------------------------------------------- 1 | use super::{ConnectionHandler, ConnectionState, WAMP_JSON, WAMP_MSGPACK}; 2 | 3 | use router::messaging::send_message; 4 | use ws::{Error as WSError, ErrorKind as WSErrorKind, Result as WSResult, Request, Response, CloseCode}; 5 | 6 | use messages::{Message, URI, HelloDetails, WelcomeDetails, RouterRoles, ErrorDetails, Reason}; 7 | use ::{WampResult, Error, ErrorKind}; 8 | 9 | impl ConnectionHandler { 10 | pub fn handle_hello(&mut self, realm: URI, _details: HelloDetails) -> WampResult<()> { 11 | debug!("Responding to hello message (realm: {:?})", realm); 12 | let id = { 13 | let mut info = self.info.lock().unwrap(); 14 | info.state = ConnectionState::Connected; 15 | info.id 16 | }; 17 | 18 | try!(self.set_realm(realm.uri)); 19 | send_message(&self.info, &Message::Welcome(id, WelcomeDetails::new(RouterRoles::new()))) 20 | } 21 | 22 | pub fn handle_goodbye(&mut self, _details: ErrorDetails, reason: Reason) -> WampResult<()> { 23 | let state = self.info.lock().unwrap().state.clone(); 24 | match state { 25 | ConnectionState::Initializing => { 26 | // TODO check specification for how this ought to work. 27 | Err(Error::new(ErrorKind::InvalidState("Recieved a goodbye message before handshake complete"))) 28 | }, 29 | ConnectionState::Connected => { 30 | info!("Recieved goobye message with reason: {:?}", reason); 31 | self.remove(); 32 | send_message(&self.info, &Message::Goodbye(ErrorDetails::new(), Reason::GoodbyeAndOut)).ok(); 33 | let mut info = self.info.lock().unwrap(); 34 | info.state = ConnectionState::Disconnected; 35 | match info.sender.close(CloseCode::Normal) { 36 | Err(e) => Err(Error::new(ErrorKind::WSError(e))), 37 | _ => Ok(()) 38 | } 39 | }, 40 | ConnectionState::ShuttingDown => { 41 | info!("Recieved goobye message in response to our goodbye message with reason: {:?}", reason); 42 | let mut info = self.info.lock().unwrap(); 43 | info.state = ConnectionState::Disconnected; 44 | match info.sender.close(CloseCode::Normal) { 45 | Err(e) => Err(Error::new(ErrorKind::WSError(e))), 46 | _ => Ok(()) 47 | } 48 | }, 49 | ConnectionState::Disconnected => { 50 | warn!("Recieved goodbye message after closing connection"); 51 | Ok(()) 52 | } 53 | } 54 | } 55 | 56 | 57 | fn set_realm(&mut self, realm: String) -> WampResult<()> { 58 | debug!("Setting realm to {}", realm); 59 | let realm = self.router.realms.lock().unwrap()[&realm].clone(); 60 | { 61 | realm.lock().unwrap().connections.push(self.info.clone()); 62 | } 63 | self.realm = Some(realm); 64 | Ok(()) 65 | } 66 | 67 | pub fn process_protocol(&mut self, request: &Request, response: &mut Response) -> WSResult<()> { 68 | debug!("Checking protocol"); 69 | let protocols = try!(request.protocols()); 70 | for protocol in protocols { 71 | if protocol == WAMP_JSON || protocol == WAMP_MSGPACK { 72 | response.set_protocol(protocol); 73 | let mut info = self.info.lock().unwrap(); 74 | info.protocol = protocol.to_string(); 75 | return Ok(()) 76 | } 77 | } 78 | Err(WSError::new(WSErrorKind::Protocol, format!("Neither {} nor {} were selected as Websocket sub-protocols", WAMP_JSON, WAMP_MSGPACK))) 79 | } 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /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 | 51 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 52 | pub struct DealerRole { 53 | #[serde(default, skip_serializing_if="Option::is_none")] 54 | features: Option 55 | } 56 | 57 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 58 | pub struct BrokerRole { 59 | #[serde(default, skip_serializing_if="Option::is_none")] 60 | features: Option 61 | } 62 | 63 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 64 | pub struct DealerFeatures { 65 | #[serde(skip_serializing_if="is_not", default)] 66 | pattern_based_registration: bool 67 | } 68 | 69 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 70 | pub struct BrokerFeatures { 71 | #[serde(skip_serializing_if="is_not", default)] 72 | pattern_based_subscription: bool 73 | } 74 | 75 | /************************** 76 | Implementations 77 | **************************/ 78 | 79 | impl RouterRoles { 80 | #[inline] 81 | pub fn new() -> RouterRoles { 82 | RouterRoles { 83 | broker: BrokerRole { 84 | features: Some(BrokerFeatures { 85 | pattern_based_subscription: true 86 | }) 87 | }, 88 | dealer: DealerRole { 89 | features: Some(DealerFeatures { 90 | pattern_based_registration: true 91 | }) 92 | } 93 | } 94 | } 95 | 96 | #[inline] 97 | pub fn new_basic() -> RouterRoles { 98 | RouterRoles { 99 | broker: BrokerRole { 100 | features: None 101 | }, 102 | dealer: DealerRole { 103 | features: None 104 | } 105 | } 106 | } 107 | } 108 | 109 | impl ClientRoles { 110 | #[inline] 111 | pub fn new() -> ClientRoles { 112 | ClientRoles { 113 | publisher: PublisherRole{features: Some(HashMap::new())}, 114 | subscriber: SubscriberRole{features: Some(SubscriberFeatures{pattern_based_subscription: true})}, 115 | caller: CallerRole{features: Some(HashMap::new())}, 116 | callee: CalleeRole{features: Some(HashMap::new())} 117 | } 118 | } 119 | 120 | #[inline] 121 | pub fn new_basic() -> ClientRoles { 122 | ClientRoles { 123 | publisher: PublisherRole{features: Some(HashMap::new())}, 124 | subscriber: SubscriberRole{features: Some(SubscriberFeatures{pattern_based_subscription: false})}, 125 | caller: CallerRole{features: Some(HashMap::new())}, 126 | callee: CalleeRole{features: Some(HashMap::new())} 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /examples/api_user.rs: -------------------------------------------------------------------------------- 1 | extern crate wamp; 2 | extern crate eventual; 3 | use wamp::client::{Connection, Client}; 4 | use wamp::{URI, Value, ArgList}; 5 | use std::io; 6 | use eventual::Async; 7 | 8 | #[macro_use] 9 | extern crate log; 10 | extern crate env_logger; 11 | 12 | 13 | enum Command { 14 | Add, 15 | Echo, 16 | Help, 17 | Quit, 18 | NoOp, 19 | Invalid(String) 20 | } 21 | 22 | fn print_prompt() { 23 | println!("Enter a command (or type \"help\")"); 24 | } 25 | 26 | fn get_input_from_user() -> String { 27 | let mut input = String::new(); 28 | io::stdin().read_line(&mut input).unwrap(); 29 | input 30 | } 31 | 32 | fn process_input(input: String) -> (Command, Vec) { 33 | let mut i_iter = input.splitn(2, ' '); 34 | let command = match i_iter.next() { 35 | Some(command) => command.trim().to_lowercase(), 36 | None => return (Command::NoOp, Vec::new()) 37 | }; 38 | let command = match command.as_str() { 39 | "add" => Command::Add, 40 | "echo" => Command::Echo, 41 | "help" => Command::Help, 42 | "quit" => Command::Quit, 43 | "" => Command::NoOp, 44 | x => Command::Invalid(x.to_string()) 45 | }; 46 | let args = match i_iter.next() { 47 | Some(args_string) => args_string.split(',').map(|s| s.trim().to_string()).collect(), 48 | None => Vec::new() 49 | }; 50 | (command, args) 51 | } 52 | 53 | fn add(client: &mut Client, args: Vec) { 54 | if args.len() > 2 { 55 | println!("Too many arguments to add. Ignoring"); 56 | } else if args.len() < 2 { 57 | println!("Please pass two numbers for adding"); 58 | return; 59 | } 60 | 61 | let a = match str::parse::(&args[0]) { 62 | Ok(i) => i, 63 | Err(_) => { 64 | println!("Please enter an integer (got {})", args[0]); 65 | return 66 | } 67 | }; 68 | let b = match str::parse::(&args[1]) { 69 | Ok(i) => i, 70 | Err(_) => { 71 | println!("Please enter an integer (got {})", args[0]); 72 | return 73 | } 74 | }; 75 | match client.call(URI::new("ca.test.add"), Some(vec![Value::Integer(a), Value::Integer(b)]), None).unwrap().await() { 76 | Ok((args, _)) => { 77 | println!("Result: {}", args.get_int(0).unwrap().unwrap()); 78 | } Err(e) => { 79 | match e.take() { 80 | Some(e) => { 81 | println!("Error: {:?}", e); 82 | } None => { 83 | println!("Aborted"); 84 | } 85 | } 86 | } 87 | } 88 | } 89 | 90 | fn echo(client: &mut Client, args: Vec) { 91 | let args = args.into_iter().map(|arg| {Value::String(arg)}).collect(); 92 | let result = client.call(URI::new("ca.test.echo"), Some(args), None).unwrap().await(); 93 | println!("Result: {:?}", result); 94 | } 95 | 96 | 97 | fn help() { 98 | println!("This client expects the 'endpoint' and 'router' examples to also be running", ); 99 | println!("The following commands are supported:"); 100 | println!(" add , "); 101 | println!(" Adds the two numbers given by and ", ); 102 | println!(" echo *"); 103 | println!(" Echoes any arguments passed back"); 104 | println!(" quit"); 105 | println!(" Sends a goodbye message and quits the program"); 106 | } 107 | 108 | fn event_loop(mut client: Client) { 109 | loop { 110 | print_prompt(); 111 | let input = get_input_from_user(); 112 | let (command, args) = process_input(input); 113 | match command { 114 | Command::Add => add(&mut client, args), 115 | Command::Echo => echo(&mut client, args), 116 | Command::Help => help(), 117 | Command::Quit => break, 118 | Command::NoOp => {}, 119 | Command::Invalid(bad_command) => print!("Invalid command: {}", bad_command) 120 | } 121 | } 122 | client.shutdown().unwrap().await().unwrap(); 123 | 124 | } 125 | 126 | 127 | fn main() { 128 | env_logger::init().unwrap(); 129 | let connection = Connection::new("ws://127.0.0.1:8090/ws", "realm1"); 130 | info!("Connecting"); 131 | let client = connection.connect().unwrap(); 132 | 133 | info!("Connected"); 134 | event_loop(client); 135 | } 136 | -------------------------------------------------------------------------------- /src/router/pubsub/mod.rs: -------------------------------------------------------------------------------- 1 | mod patterns; 2 | use super::{ConnectionHandler, random_id}; 3 | 4 | use router::messaging::send_message; 5 | use messages::{Message, URI, SubscribeOptions, PublishOptions, EventDetails, ErrorType, Reason}; 6 | use ::{List, Dict, MatchingPolicy, WampResult, Error, ErrorKind}; 7 | pub use router::pubsub::patterns::SubscriptionPatternNode; 8 | 9 | impl ConnectionHandler{ 10 | pub fn handle_subscribe(&mut self, request_id: u64, options: SubscribeOptions, topic: URI) -> WampResult<()> { 11 | debug!("Responding to subscribe message (id: {}, topic: {})", request_id, topic.uri); 12 | match self.realm { 13 | Some(ref realm) => { 14 | let mut realm = realm.lock().unwrap(); 15 | let mut manager = &mut realm.subscription_manager; 16 | let topic_id = { 17 | let topic_id = match manager.subscriptions.subscribe_with(&topic, self.info.clone(), options.pattern_match.clone()) { 18 | Ok(topic_id) => topic_id, 19 | Err(e) => return Err(Error::new(ErrorKind::ErrorReason(ErrorType::Subscribe, request_id, e.reason()))) 20 | }; 21 | self.subscribed_topics.push(topic_id); 22 | topic_id 23 | }; 24 | manager.subscription_ids_to_uris.insert(topic_id, (topic.uri, options.pattern_match == MatchingPolicy::Prefix)); 25 | send_message(&self.info, &Message::Subscribed(request_id, topic_id)) 26 | }, 27 | None => { 28 | Err(Error::new(ErrorKind::InvalidState("Recieved a message while not attached to a realm"))) 29 | } 30 | } 31 | } 32 | 33 | pub fn handle_unsubscribe(&mut self, request_id: u64, topic_id: u64) -> WampResult<()> { 34 | match self.realm { 35 | Some(ref realm) => { 36 | let mut realm = realm.lock().unwrap(); 37 | let mut manager = &mut realm.subscription_manager; 38 | let (topic_uri, is_prefix) = match manager.subscription_ids_to_uris.get(&topic_id) { 39 | Some(&(ref uri, ref is_prefix)) => (uri.clone(), is_prefix.clone()), 40 | None => return Err(Error::new(ErrorKind::ErrorReason(ErrorType::Unsubscribe, request_id, Reason::NoSuchSubscription))) 41 | }; 42 | 43 | 44 | let topic_id = match manager.subscriptions.unsubscribe_with(&topic_uri, &self.info, is_prefix) { 45 | Ok(topic_id) => topic_id, 46 | Err(e) => return Err(Error::new(ErrorKind::ErrorReason(ErrorType::Unsubscribe, request_id, e.reason()))) 47 | }; 48 | self.subscribed_topics.retain(|id| { 49 | *id != topic_id 50 | }); 51 | send_message(&self.info, &Message::Unsubscribed(request_id)) 52 | }, 53 | None => { 54 | Err(Error::new(ErrorKind::InvalidState("Recieved a message while not attached to a realm"))) 55 | } 56 | } 57 | } 58 | 59 | pub fn handle_publish(&mut self, request_id: u64, options: PublishOptions, topic: URI, args: Option, kwargs: Option) -> WampResult<()> { 60 | debug!("Responding to publish message (id: {}, topic: {})", request_id, topic.uri); 61 | match self.realm { 62 | Some(ref realm) => { 63 | let realm = realm.lock().unwrap(); 64 | let manager = &realm.subscription_manager; 65 | let publication_id = random_id(); 66 | let mut event_message = Message::Event(1, publication_id, EventDetails::new(), args.clone(), kwargs.clone()); 67 | let my_id = { 68 | self.info.lock().unwrap().id.clone() 69 | }; 70 | info!("Current topic tree: {:?}", manager.subscriptions); 71 | for (subscriber, topic_id, policy) in manager.subscriptions.filter(topic.clone()) { 72 | if subscriber.lock().unwrap().id != my_id { 73 | if let Message::Event(ref mut old_topic, ref _publish_id, ref mut details, ref _args, ref _kwargs) = event_message { 74 | *old_topic = topic_id; 75 | details.topic = if policy == MatchingPolicy::Strict { 76 | None 77 | } else { 78 | Some(topic.clone()) 79 | }; 80 | } 81 | try!(send_message(subscriber, &event_message)); 82 | } 83 | } 84 | if options.should_acknowledge() { 85 | try!(send_message(&self.info, &Message::Published(request_id, publication_id))); 86 | } 87 | Ok(()) 88 | }, 89 | None => { 90 | Err(Error::new(ErrorKind::InvalidState("Recieved a message while not attached to a realm"))) 91 | } 92 | } 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/messages/types/options.rs: -------------------------------------------------------------------------------- 1 | use super::{ClientRoles, RouterRoles, MatchingPolicy, InvocationPolicy, is_not, URI}; 2 | use serde; 3 | use std::fmt; 4 | use serde::ser::SerializeStruct; 5 | 6 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 7 | pub struct HelloDetails { 8 | #[serde(default, skip_serializing_if="Option::is_none")] 9 | agent: Option, 10 | roles: ClientRoles 11 | } 12 | 13 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 14 | pub struct WelcomeDetails { 15 | #[serde(default, skip_serializing_if="Option::is_none")] 16 | agent: Option, 17 | roles: RouterRoles 18 | } 19 | 20 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 21 | pub struct ErrorDetails { 22 | #[serde(default, skip_serializing_if="Option::is_none")] 23 | message: Option, 24 | } 25 | 26 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 27 | pub struct SubscribeOptions { 28 | #[serde(default, rename="match", skip_serializing_if="MatchingPolicy::is_strict")] 29 | pub pattern_match: MatchingPolicy 30 | } 31 | 32 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 33 | pub struct PublishOptions { 34 | #[serde(default, skip_serializing_if="is_not")] 35 | acknowledge: bool 36 | } 37 | 38 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 39 | pub struct RegisterOptions { 40 | #[serde(default, rename="match", skip_serializing_if="MatchingPolicy::is_strict")] 41 | pub pattern_match: MatchingPolicy, 42 | 43 | #[serde(default, rename="invoke", skip_serializing_if="InvocationPolicy::is_single")] 44 | pub invocation_policy: InvocationPolicy 45 | } 46 | 47 | #[derive(PartialEq, Debug)] 48 | pub struct CallOptions; 49 | 50 | #[derive(PartialEq, Debug)] 51 | pub struct YieldOptions; 52 | 53 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 54 | pub struct EventDetails { 55 | #[serde(default, skip_serializing_if="Option::is_none")] 56 | publisher: Option, 57 | 58 | #[serde(default, skip_serializing_if="Option::is_none")] 59 | trustlevel: Option, 60 | 61 | #[serde(default, skip_serializing_if="Option::is_none")] 62 | pub topic: Option, 63 | 64 | } 65 | 66 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 67 | pub struct InvocationDetails { 68 | #[serde(default, skip_serializing_if="Option::is_none")] 69 | pub procedure: Option, 70 | } 71 | 72 | #[derive(PartialEq, Debug)] 73 | pub struct ResultDetails; 74 | 75 | impl HelloDetails { 76 | pub fn new(roles: ClientRoles) -> HelloDetails { 77 | HelloDetails { 78 | roles: roles, 79 | agent: None 80 | } 81 | } 82 | 83 | pub fn new_with_agent(roles: ClientRoles, agent: &str) -> HelloDetails { 84 | HelloDetails { 85 | roles: roles, 86 | agent: Some(agent.to_string()) 87 | } 88 | } 89 | 90 | } 91 | 92 | impl WelcomeDetails { 93 | pub fn new(roles: RouterRoles) -> WelcomeDetails { 94 | WelcomeDetails { 95 | roles: roles, 96 | agent: None 97 | } 98 | } 99 | 100 | pub fn new_with_agent(roles: RouterRoles, agent: &str) -> WelcomeDetails { 101 | WelcomeDetails { 102 | roles: roles, 103 | agent: Some(agent.to_string()) 104 | } 105 | } 106 | 107 | } 108 | 109 | 110 | impl ErrorDetails { 111 | pub fn new() -> ErrorDetails { 112 | ErrorDetails { 113 | message: None 114 | } 115 | } 116 | 117 | 118 | pub fn new_with_message(message: &str) -> ErrorDetails { 119 | ErrorDetails { 120 | message: Some(message.to_string()) 121 | } 122 | } 123 | } 124 | 125 | impl SubscribeOptions { 126 | pub fn new() -> SubscribeOptions { 127 | SubscribeOptions { 128 | pattern_match: MatchingPolicy::Strict 129 | } 130 | } 131 | } 132 | 133 | impl PublishOptions { 134 | pub fn new(acknowledge: bool) -> PublishOptions { 135 | PublishOptions { 136 | acknowledge: acknowledge 137 | } 138 | } 139 | 140 | pub fn should_acknowledge(&self) -> bool { 141 | self.acknowledge 142 | } 143 | } 144 | 145 | impl RegisterOptions { 146 | pub fn new() -> RegisterOptions { 147 | RegisterOptions { 148 | pattern_match: MatchingPolicy::Strict, 149 | invocation_policy: InvocationPolicy::Single 150 | } 151 | } 152 | } 153 | 154 | impl CallOptions { 155 | pub fn new() -> CallOptions { 156 | CallOptions{} 157 | } 158 | } 159 | 160 | impl YieldOptions { 161 | pub fn new() -> YieldOptions { 162 | YieldOptions{} 163 | } 164 | } 165 | 166 | impl EventDetails { 167 | pub fn new() -> EventDetails { 168 | EventDetails { 169 | publisher: None, 170 | trustlevel: None, 171 | topic: None 172 | } 173 | } 174 | 175 | pub fn new_with_topic(topic: URI) -> EventDetails { 176 | EventDetails { 177 | publisher: None, 178 | trustlevel: None, 179 | topic: Some(topic) 180 | } 181 | } 182 | } 183 | 184 | impl InvocationDetails { 185 | pub fn new() -> InvocationDetails { 186 | InvocationDetails{ 187 | procedure: None 188 | } 189 | } 190 | } 191 | 192 | impl ResultDetails { 193 | pub fn new() -> ResultDetails { 194 | ResultDetails{} 195 | } 196 | } 197 | 198 | serialize_empty!(CallOptions); 199 | serialize_empty!(YieldOptions); 200 | serialize_empty!(ResultDetails); 201 | -------------------------------------------------------------------------------- /src/router/rpc/mod.rs: -------------------------------------------------------------------------------- 1 | mod patterns; 2 | pub use router::rpc::patterns::RegistrationPatternNode; 3 | 4 | use super::{ConnectionHandler, random_id}; 5 | 6 | use router::messaging::send_message; 7 | use messages::{Message, URI, RegisterOptions, CallOptions, InvocationDetails, YieldOptions, ResultDetails, ErrorType, Reason}; 8 | use ::{List, Dict, MatchingPolicy, WampResult, Error, ErrorKind, ID}; 9 | 10 | impl ConnectionHandler{ 11 | pub fn handle_register(&mut self, request_id: ID, options: RegisterOptions, procedure: URI) -> WampResult<()> { 12 | debug!("Responding to register message (id: {}, procedure: {})", request_id, procedure.uri); 13 | match self.realm { 14 | Some(ref realm) => { 15 | let mut realm = realm.lock().unwrap(); 16 | let mut manager = &mut realm.registration_manager; 17 | let procedure_id = { 18 | let procedure_id = match manager.registrations.register_with(&procedure, self.info.clone(), options.pattern_match.clone(), options.invocation_policy.clone()) { 19 | Ok(procedure_id) => procedure_id, 20 | Err(e) => return Err(Error::new(ErrorKind::ErrorReason(ErrorType::Register, request_id, e.reason()))) 21 | }; 22 | self.registered_procedures.push(procedure_id); 23 | procedure_id 24 | }; 25 | manager.registration_ids_to_uris.insert(procedure_id, (procedure.uri, options.pattern_match == MatchingPolicy::Prefix)); 26 | send_message(&self.info, &Message::Registered(request_id, procedure_id)) 27 | }, 28 | None => { 29 | Err(Error::new(ErrorKind::InvalidState("Recieved a message while not attached to a realm"))) 30 | } 31 | } 32 | } 33 | 34 | pub fn handle_unregister(&mut self, request_id: ID, procedure_id: ID) -> WampResult<()> { 35 | match self.realm { 36 | Some(ref realm) => { 37 | let mut realm = realm.lock().unwrap(); 38 | let mut manager = &mut realm.registration_manager; 39 | let (procedure_uri, is_prefix) = match manager.registration_ids_to_uris.get(&procedure_id) { 40 | Some(&(ref uri, ref is_prefix)) => (uri.clone(), is_prefix.clone()), 41 | None => return Err(Error::new(ErrorKind::ErrorReason(ErrorType::Unregister, request_id, Reason::NoSuchProcedure))) 42 | }; 43 | 44 | 45 | let procedure_id = match manager.registrations.unregister_with(&procedure_uri, &self.info, is_prefix) { 46 | Ok(procedure_id) => procedure_id, 47 | Err(e) => return Err(Error::new(ErrorKind::ErrorReason(ErrorType::Unregister, request_id, e.reason()))) 48 | }; 49 | self.registered_procedures.retain(|id| { 50 | *id != procedure_id 51 | }); 52 | send_message(&self.info, &Message::Unregistered(request_id)) 53 | }, 54 | None => { 55 | Err(Error::new(ErrorKind::InvalidState("Recieved a message while not attached to a realm"))) 56 | } 57 | } 58 | } 59 | 60 | pub fn handle_call(&mut self, request_id: ID, _options: CallOptions, procedure: URI, args: Option, kwargs: Option) -> WampResult<()> { 61 | debug!("Responding to call message (id: {}, procedure: {})", request_id, procedure.uri); 62 | match self.realm { 63 | Some(ref realm) => { 64 | let mut realm = realm.lock().unwrap(); 65 | let mut manager = &mut realm.registration_manager; 66 | let invocation_id = random_id(); 67 | info!("Current procedure tree: {:?}", manager.registrations); 68 | let (registrant, procedure_id, policy) = match manager.registrations.get_registrant_for(procedure.clone()) { 69 | Ok(registrant) => registrant, 70 | Err(e) => return Err(Error::new(ErrorKind::ErrorReason(ErrorType::Call, request_id, e.reason()))) 71 | }; 72 | manager.active_calls.insert(invocation_id, (request_id, self.info.clone())); 73 | let mut details = InvocationDetails::new(); 74 | details.procedure = if policy == MatchingPolicy::Strict { 75 | None 76 | } else { 77 | Some(procedure) 78 | }; 79 | let invocation_message = Message::Invocation(invocation_id, procedure_id, details, args, kwargs); 80 | try!(send_message(registrant, &invocation_message)); 81 | 82 | 83 | Ok(()) 84 | }, 85 | None => { 86 | Err(Error::new(ErrorKind::InvalidState("Recieved a message while not attached to a realm"))) 87 | } 88 | } 89 | } 90 | 91 | pub fn handle_yield(&mut self, invocation_id: ID, _options: YieldOptions, args: Option, kwargs: Option) -> WampResult<()> { 92 | debug!("Responding to yield message (id: {})", invocation_id); 93 | match self.realm { 94 | Some(ref realm) => { 95 | let mut realm = realm.lock().unwrap(); 96 | let mut manager = &mut realm.registration_manager; 97 | if let Some((call_id, callee)) = manager.active_calls.remove(&invocation_id) { 98 | let result_message = Message::Result(call_id, ResultDetails::new(), args, kwargs); 99 | send_message(&callee, &result_message) 100 | } else { 101 | Err(Error::new(ErrorKind::InvalidState("Recieved a yield message for a call that wasn't sent"))) 102 | } 103 | }, None => { 104 | Err(Error::new(ErrorKind::InvalidState("Recieved a message while not attached to a realm"))) 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /examples/pubsubclient.rs: -------------------------------------------------------------------------------- 1 | extern crate wamp; 2 | extern crate eventual; 3 | use wamp::client::{Connection, Client, Subscription}; 4 | use wamp::{URI, Value, MatchingPolicy}; 5 | use std::io; 6 | use std::sync::{Mutex, Arc}; 7 | use eventual::Async; 8 | 9 | #[macro_use] 10 | extern crate log; 11 | extern crate env_logger; 12 | 13 | 14 | enum Command { 15 | Sub, 16 | Pub, 17 | Unsub, 18 | List, 19 | Help, 20 | Quit, 21 | NoOp, 22 | Invalid(String) 23 | } 24 | 25 | fn print_prompt() { 26 | println!("Enter a command (or type \"help\")"); 27 | } 28 | 29 | fn get_input_from_user() -> String { 30 | let mut input = String::new(); 31 | io::stdin().read_line(&mut input).unwrap(); 32 | input 33 | } 34 | 35 | fn process_input(input: String) -> (Command, Vec) { 36 | let mut i_iter = input.splitn(2, ' '); 37 | let command = match i_iter.next() { 38 | Some(command) => command.trim().to_lowercase(), 39 | None => return (Command::NoOp, Vec::new()) 40 | }; 41 | let command = match command.as_str() { 42 | "pub" => Command::Pub, 43 | "sub" => Command::Sub, 44 | "unsub" => Command::Unsub, 45 | "list" => Command::List, 46 | "help" => Command::Help, 47 | "quit" => Command::Quit, 48 | "" => Command::NoOp, 49 | x => Command::Invalid(x.to_string()) 50 | }; 51 | let args = match i_iter.next() { 52 | Some(args_string) => args_string.split(',').map(|s| s.trim().to_string()).collect(), 53 | None => Vec::new() 54 | }; 55 | (command, args) 56 | } 57 | 58 | fn subscribe(client: &mut Client, subscriptions: &mut Arc>>, args: Vec) { 59 | if args.len() > 2 { 60 | println!("Too many arguments to subscribe. Ignoring"); 61 | } else if args.len() == 0 { 62 | println!("Please specify the topic to subscribe to"); 63 | return; 64 | } 65 | let topic = args[0].clone(); 66 | let policy = if args.len() > 1 { 67 | match args[1].as_str() { 68 | "prefix" => MatchingPolicy::Prefix, 69 | "wild" => MatchingPolicy::Wildcard, 70 | "strict" => MatchingPolicy::Strict, 71 | _ => { 72 | println!("Invalid matching type, should be 'prefix', 'wild' or 'strict'"); 73 | return; 74 | } 75 | } 76 | } else { 77 | MatchingPolicy::Strict 78 | }; 79 | let subscriptions = subscriptions.clone(); 80 | client.subscribe_with_pattern(URI::new(&topic), Box::new(move |args, kwargs|{ 81 | println!("Recieved message on topic {} with args {:?} and kwargs {:?}", topic, args, kwargs); 82 | }), policy).unwrap().and_then(move |subscription|{ 83 | println!("Subscribed to topic {}", subscription.topic.uri); 84 | subscriptions.lock().unwrap().push(subscription); 85 | Ok(()) 86 | }).await().unwrap(); 87 | } 88 | 89 | fn unsubscribe(client: &mut Client, subscriptions: &mut Arc>>, args: Vec) { 90 | if args.len() > 1 { 91 | println!("Too many arguments to subscribe. Ignoring"); 92 | } else if args.len() == 0 { 93 | println!("Please specify the topic to subscribe to"); 94 | return; 95 | } 96 | match args[0].parse::() { 97 | Ok(i) => { 98 | let mut subscriptions = subscriptions.lock().unwrap(); 99 | if i >= subscriptions.len() { 100 | println!("Invalid subscription index: {}", i); 101 | return; 102 | } 103 | let subscription = subscriptions.remove(i); 104 | let topic = subscription.topic.uri.clone(); 105 | client.unsubscribe(subscription).unwrap().and_then(move |()| { 106 | println!("Successfully unsubscribed from {}", topic); 107 | Ok(()) 108 | }).await().unwrap(); 109 | }, 110 | Err(_) => { 111 | println!("Invalid subscription index: {}", args[0]); 112 | } 113 | } 114 | } 115 | 116 | fn list(subscriptions: &Arc>>) { 117 | let subscriptions = subscriptions.lock().unwrap(); 118 | for (index, subscription) in subscriptions.iter().enumerate() { 119 | println!("{} {}", index, subscription.topic.uri); 120 | } 121 | } 122 | 123 | fn publish(client: &mut Client, args: Vec) { 124 | if args.len() == 0 { 125 | println!("Please specify a topic to publish to"); 126 | } 127 | let mut topic_arr = args.clone(); 128 | let args = topic_arr.split_off(1); 129 | let args = args.iter().map(|arg|{ 130 | match arg.parse::() { 131 | Ok(i) => Value::Integer(i), 132 | Err(_) => Value::String(arg.clone()) 133 | } 134 | }).collect(); 135 | client.publish_and_acknowledge(URI::new(&topic_arr[0]), Some(args), None).unwrap().await().unwrap(); 136 | } 137 | 138 | fn help() { 139 | println!("The following commands are supported:"); 140 | println!(" sub , ?", ); 141 | println!(" Subscribes to the topic specified by the uri "); 142 | println!(" specifies the type of patten matching used", ); 143 | println!(" should be one of 'strict' (the default), 'wild' or 'prefix'", ); 144 | println!(" pub , *", ); 145 | println!(" Publishes to the topic specified by uri "); 146 | println!(" is an optinal, comma separated list of arguments"); 147 | println!(" list"); 148 | println!(" Lists all of the current subscriptions, along with their index"); 149 | println!(" unsub "); 150 | println!(" Unsubscribes from the topic subscription specified by the given index"); 151 | println!(" quit"); 152 | println!(" Sends a goodbye message and quits the program"); 153 | } 154 | 155 | fn event_loop(mut client: Client) { 156 | let mut subscriptions = Arc::new(Mutex::new(Vec::new())); 157 | loop { 158 | print_prompt(); 159 | let input = get_input_from_user(); 160 | let (command, args) = process_input(input); 161 | match command { 162 | Command::Sub => subscribe(&mut client, &mut subscriptions, args), 163 | Command::Pub => publish(&mut client, args), 164 | Command::Unsub => unsubscribe(&mut client, &mut subscriptions, args), 165 | Command::List => list(&subscriptions), 166 | Command::Help => help(), 167 | Command::Quit => break, 168 | Command::NoOp => {}, 169 | Command::Invalid(bad_command) => print!("Invalid command: {}", bad_command) 170 | } 171 | } 172 | client.shutdown().unwrap().await().unwrap(); 173 | 174 | } 175 | 176 | 177 | fn main() { 178 | env_logger::init().unwrap(); 179 | let connection = Connection::new("ws://127.0.0.1:8090/ws", "kitchen_realm"); 180 | info!("Connecting"); 181 | let client = connection.connect().unwrap(); 182 | 183 | info!("Connected"); 184 | event_loop(client); 185 | } 186 | -------------------------------------------------------------------------------- /src/router/mod.rs: -------------------------------------------------------------------------------- 1 | mod handshake; 2 | mod messaging; 3 | mod pubsub; 4 | mod rpc; 5 | 6 | 7 | use ws::{listen as ws_listen, Sender, Result as WSResult }; 8 | use std::sync::{Arc, Mutex}; 9 | use std::collections::{HashMap}; 10 | use std::marker::Sync; 11 | use rand::{thread_rng}; 12 | use rand::distributions::{Range, IndependentSample}; 13 | use router::pubsub::SubscriptionPatternNode; 14 | use router::rpc::RegistrationPatternNode; 15 | use super::ID; 16 | use std::thread::{self, JoinHandle}; 17 | use std::time::Duration; 18 | use router::messaging::send_message; 19 | use messages::{ErrorDetails, Reason, Message}; 20 | 21 | 22 | struct SubscriptionManager { 23 | subscriptions : SubscriptionPatternNode>>, 24 | subscription_ids_to_uris: HashMap 25 | } 26 | 27 | struct RegistrationManager { 28 | registrations : RegistrationPatternNode>>, 29 | registration_ids_to_uris: HashMap, 30 | active_calls: HashMap>)> 31 | } 32 | 33 | struct Realm { 34 | subscription_manager: SubscriptionManager, 35 | registration_manager: RegistrationManager, 36 | connections: Vec>> 37 | } 38 | 39 | pub struct Router { 40 | info: Arc 41 | } 42 | 43 | struct RouterInfo { 44 | realms: Mutex>>>, 45 | } 46 | 47 | struct ConnectionHandler { 48 | info: Arc>, 49 | router: Arc, 50 | realm: Option>>, 51 | subscribed_topics: Vec, 52 | registered_procedures: Vec, 53 | } 54 | 55 | pub struct ConnectionInfo { 56 | state: ConnectionState, 57 | sender: Sender, 58 | protocol: String, 59 | id: u64 60 | } 61 | 62 | #[derive(Clone, PartialEq)] 63 | enum ConnectionState { 64 | Initializing, 65 | Connected, 66 | ShuttingDown, 67 | Disconnected 68 | } 69 | 70 | static WAMP_JSON:&'static str = "wamp.2.json"; 71 | static WAMP_MSGPACK:&'static str = "wamp.2.msgpack"; 72 | 73 | fn random_id() -> u64 { 74 | let mut rng = thread_rng(); 75 | // TODO make this a constant 76 | let between = Range::new(0, 1u64.rotate_left(56) - 1); 77 | between.ind_sample(&mut rng) 78 | } 79 | 80 | 81 | unsafe impl Sync for Router {} 82 | 83 | impl Router { 84 | #[inline] 85 | pub fn new() -> Router { 86 | Router{ 87 | info: Arc::new(RouterInfo { 88 | realms: Mutex::new(HashMap::new()), 89 | }) 90 | } 91 | } 92 | 93 | pub fn listen(&self, url: &str) -> JoinHandle<()> { 94 | let router_info = self.info.clone(); 95 | let url = url.to_string(); 96 | thread::spawn(move ||{ 97 | ws_listen(&url[..], |sender| { 98 | ConnectionHandler { 99 | info: Arc::new(Mutex::new(ConnectionInfo{ 100 | state: ConnectionState::Initializing, 101 | sender: sender, 102 | protocol: String::new(), 103 | id: random_id() 104 | })), 105 | subscribed_topics: Vec::new(), 106 | registered_procedures: Vec::new(), 107 | realm: None, 108 | router: router_info.clone() 109 | } 110 | }).unwrap(); 111 | }) 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(realm.to_string(), Arc::new(Mutex::new(Realm { 121 | connections: Vec::new(), 122 | subscription_manager: SubscriptionManager { 123 | subscriptions: SubscriptionPatternNode::new(), 124 | subscription_ids_to_uris: HashMap::new() 125 | }, 126 | registration_manager: RegistrationManager { 127 | registrations: RegistrationPatternNode::new(), 128 | registration_ids_to_uris: HashMap::new(), 129 | active_calls: HashMap::new() 130 | } 131 | }))); 132 | debug!("Added realm {}", realm); 133 | } 134 | 135 | pub fn shutdown(&self) { 136 | for realm in self.info.realms.lock().unwrap().values() { 137 | for connection in realm.lock().unwrap().connections.iter() { 138 | send_message(connection, &Message::Goodbye(ErrorDetails::new(), Reason::SystemShutdown)).ok(); 139 | let mut connection = connection.lock().unwrap(); 140 | connection.state = ConnectionState::ShuttingDown; 141 | } 142 | } 143 | info!("Goodbye messages sent. Waiting 5 seconds for response"); 144 | thread::sleep(Duration::from_secs(5)); 145 | for realm in self.info.realms.lock().unwrap().values() { 146 | for connection in realm.lock().unwrap().connections.iter() { 147 | let connection = connection.lock().unwrap(); 148 | connection.sender.shutdown().ok(); 149 | } 150 | } 151 | } 152 | } 153 | 154 | 155 | 156 | impl ConnectionHandler { 157 | fn remove(&mut self) { 158 | match self.realm { 159 | Some(ref realm) => { 160 | 161 | let mut realm = realm.lock().unwrap(); 162 | { 163 | trace!("Removing subscriptions for client {}", self.info.lock().unwrap().id); 164 | let mut manager = &mut realm.subscription_manager; 165 | for subscription_id in self.subscribed_topics.iter() { 166 | trace!("Looking for subscription {}", subscription_id); 167 | match manager.subscription_ids_to_uris.get(&subscription_id) { 168 | Some(&(ref topic_uri, is_prefix)) => { 169 | trace!("Removing subscription to {:?}", topic_uri); 170 | manager.subscriptions.unsubscribe_with(topic_uri, &self.info, is_prefix).ok(); 171 | trace!("Subscription tree: {:?}", manager.subscriptions); 172 | }, 173 | None => {} 174 | } 175 | } 176 | } 177 | { 178 | let mut manager = &mut realm.registration_manager; 179 | for registration_id in self.registered_procedures.iter() { 180 | match manager.registration_ids_to_uris.get(®istration_id) { 181 | Some(&(ref topic_uri, is_prefix)) => { 182 | manager.registrations.unregister_with(topic_uri, &self.info, is_prefix).ok(); 183 | }, 184 | None => {} 185 | } 186 | } 187 | } 188 | let my_id = self.info.lock().unwrap().id.clone(); 189 | realm.connections.retain(|connection| { 190 | connection.lock().unwrap().id != my_id 191 | }); 192 | }, 193 | None => { 194 | // No need to do anything, since this connection was never added to a realm 195 | } 196 | } 197 | 198 | } 199 | 200 | 201 | fn terminate_connection(&mut self) -> WSResult<()> { 202 | self.remove(); 203 | Ok(()) 204 | } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /src/messages/types/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | // All this is necessary because Serde decided that the best way 3 | // to serialize an empty struct was as a null value, and the best way 4 | // to deserialize it was as an empty list. So instead we serialize it as a map. 5 | macro_rules! serialize_empty { 6 | ($name: tt) => ( 7 | serialize_empty_workaround!($name, $name); 8 | ); 9 | } 10 | 11 | macro_rules! serialize_empty_workaround { 12 | ($name: ty, $obj: expr) => ( 13 | impl serde::Serialize for $name { 14 | fn serialize(&self, serializer: S) -> Result 15 | where S: serde::Serializer, 16 | { 17 | 18 | let struc = try!(serializer.serialize_struct("", 0)); 19 | struc.end() 20 | } 21 | } 22 | 23 | impl <'de> serde::de::Deserialize<'de> for $name { 24 | 25 | 26 | fn deserialize(deserializer: D) -> Result<$name, D::Error> where 27 | D: serde::de::Deserializer<'de> { 28 | { 29 | struct Visitor; 30 | impl <'de> serde::de::Visitor<'de> for Visitor { 31 | type Value = $name; 32 | 33 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 34 | formatter.write_str("empty struct") 35 | } 36 | 37 | #[inline] 38 | fn visit_unit(self) -> Result<$name,E> where 39 | E: serde::de::Error { 40 | Ok($obj) 41 | } 42 | #[inline] 43 | fn visit_map(self, _visitor: A) -> Result<$name,A::Error> 44 | where A: serde::de::MapAccess<'de> { 45 | self.visit_unit() 46 | } 47 | } 48 | deserializer.deserialize_unit_struct("",Visitor) 49 | } 50 | } 51 | } 52 | ); 53 | } 54 | 55 | 56 | 57 | mod options; 58 | mod value; 59 | mod error; 60 | mod roles; 61 | 62 | use serde; 63 | use std::fmt; 64 | 65 | pub use messages::types::options::*; 66 | pub use messages::types::value::*; 67 | pub use messages::types::error::*; 68 | pub use messages::types::roles::*; 69 | 70 | fn is_not(b: &bool) -> bool { 71 | !*b 72 | } 73 | 74 | 75 | /************************** 76 | Structs 77 | **************************/ 78 | 79 | 80 | 81 | 82 | /// The policies that can be used for matching a uri pattern. 83 | #[derive(PartialEq, Debug, Clone, Copy)] 84 | pub enum MatchingPolicy { 85 | /// The given pattern matches any URI that has it as a prefix 86 | Prefix, 87 | /// The given pattern contains at least one 'wildcard' segment which can match any segment at the same location 88 | Wildcard, 89 | /// The given pattern only matches URIs that are identical. 90 | Strict 91 | } 92 | 93 | /// The policies that dictate how invocations are distributed amongst shared registrations 94 | #[derive(PartialEq, Debug, Clone, Copy)] 95 | pub enum InvocationPolicy { 96 | // Only one reigistration per uri (the default) 97 | Single, 98 | // Callee selcted sequentially from the list of registrants 99 | RoundRobin, 100 | // Callee selcted randomly from the list of registrants 101 | Random, 102 | // First callee (in orer of registration) is called 103 | First, 104 | // Last callee (in order of registration( is called 105 | Last 106 | } 107 | 108 | 109 | /************************** 110 | Visitors 111 | **************************/ 112 | 113 | struct MatchingPolicyVisitor; 114 | struct InvocationPolicyVisitor; 115 | 116 | 117 | 118 | 119 | 120 | impl MatchingPolicy { 121 | #[inline] 122 | fn is_strict(&self) -> bool { 123 | self == &MatchingPolicy::Strict 124 | } 125 | } 126 | 127 | impl InvocationPolicy { 128 | #[inline] 129 | fn is_single(&self) -> bool { 130 | self == &InvocationPolicy::Single 131 | } 132 | } 133 | 134 | impl Default for MatchingPolicy { 135 | #[inline] 136 | fn default() -> MatchingPolicy { 137 | MatchingPolicy::Strict 138 | } 139 | } 140 | 141 | impl Default for InvocationPolicy { 142 | #[inline] 143 | fn default() -> InvocationPolicy { 144 | InvocationPolicy::Single 145 | } 146 | } 147 | 148 | 149 | 150 | /*------------------------- 151 | MatchingPolicy 152 | -------------------------*/ 153 | 154 | impl serde::Serialize for MatchingPolicy { 155 | fn serialize(&self, serializer: S) -> Result 156 | where S: serde::Serializer, 157 | { 158 | let ser_str = match *self { 159 | MatchingPolicy::Prefix => "prefix", 160 | MatchingPolicy::Wildcard => "wildcard", 161 | MatchingPolicy::Strict => "" 162 | }; 163 | serializer.serialize_str(ser_str) 164 | } 165 | } 166 | 167 | impl <'de> serde::Deserialize<'de> for MatchingPolicy { 168 | fn deserialize(deserializer: D) -> Result 169 | where D: serde::Deserializer<'de>, 170 | { 171 | deserializer.deserialize_str(MatchingPolicyVisitor) 172 | } 173 | } 174 | 175 | impl <'de> serde::de::Visitor<'de> for MatchingPolicyVisitor { 176 | type Value = MatchingPolicy; 177 | 178 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 179 | formatter.write_str("matching policy for registration") 180 | } 181 | 182 | #[inline] 183 | fn visit_str(self, value: &str) -> Result 184 | where E: serde::de::Error, 185 | { 186 | match value { 187 | "prefix" => Ok(MatchingPolicy::Prefix), 188 | "wildcard" => Ok(MatchingPolicy::Wildcard), 189 | x => Err(serde::de::Error::custom(format!("Invalid matching policy: {}", x))) 190 | } 191 | } 192 | 193 | } 194 | 195 | impl serde::Serialize for InvocationPolicy { 196 | fn serialize(&self, serializer: S) -> Result 197 | where S: serde::Serializer, 198 | { 199 | let ser_str = match *self { 200 | InvocationPolicy::Single => "single", 201 | InvocationPolicy::RoundRobin => "roundrobin", 202 | InvocationPolicy::Random => "random", 203 | InvocationPolicy::First => "first", 204 | InvocationPolicy::Last => "last", 205 | }; 206 | serializer.serialize_str(ser_str) 207 | } 208 | } 209 | 210 | impl <'de> serde::Deserialize<'de> for InvocationPolicy { 211 | fn deserialize(deserializer: D) -> Result 212 | where D: serde::Deserializer<'de>, 213 | { 214 | deserializer.deserialize_str(InvocationPolicyVisitor) 215 | } 216 | } 217 | 218 | impl <'de> serde::de::Visitor<'de> for InvocationPolicyVisitor { 219 | type Value = InvocationPolicy; 220 | 221 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 222 | formatter.write_str("invocation policy for a procedure") 223 | } 224 | 225 | #[inline] 226 | fn visit_str(self, value: &str) -> Result 227 | where E: serde::de::Error, 228 | { 229 | match value { 230 | "single" => Ok(InvocationPolicy::Single), 231 | "roundrobin" => Ok(InvocationPolicy::RoundRobin), 232 | "random" => Ok(InvocationPolicy::Random), 233 | "first" => Ok(InvocationPolicy::First), 234 | "last" => Ok(InvocationPolicy::Last), 235 | x => Err(serde::de::Error::custom(format!("Invalid invocation policy: {}", x))) 236 | } 237 | } 238 | 239 | } 240 | -------------------------------------------------------------------------------- /src/messages/types/error.rs: -------------------------------------------------------------------------------- 1 | use URI; 2 | use std::fmt; 3 | use serde; 4 | use super::{List, Dict}; 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 to_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 S: serde::Serializer, 122 | { 123 | serializer.serialize_str(self.get_string()) 124 | } 125 | } 126 | 127 | impl <'de> serde::Deserialize<'de> for Reason { 128 | fn deserialize(deserializer: D) -> Result 129 | where D: serde::Deserializer<'de>, 130 | { 131 | deserializer.deserialize_str(ReasonVisitor) 132 | } 133 | } 134 | 135 | impl <'de> serde::de::Visitor<'de> for ReasonVisitor { 136 | type Value = Reason; 137 | 138 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 139 | formatter.write_str("error reason uri") 140 | } 141 | 142 | #[inline] 143 | fn visit_str(self, value: &str) -> Result 144 | where E: serde::de::Error, 145 | { 146 | match value { 147 | "wamp.error.invalid_uri" => Ok(Reason::InvalidURI), 148 | "wamp.error.no_such_procedure" => Ok(Reason::NoSuchProcedure), 149 | "wamp.error.procedure_already_exists" => Ok(Reason::ProcedureAlreadyExists), 150 | "wamp.error.no_such_registration" => Ok(Reason::NoSuchRegistration), 151 | "wamp.error.no_such_subscription" => Ok(Reason::NoSuchSubscription), 152 | "wamp.error.invalid_argument" => Ok(Reason::InvalidArgument), 153 | "wamp.error.system_shutdown" => Ok(Reason::SystemShutdown), 154 | "wamp.error.close_realm" => Ok(Reason::CloseRealm), 155 | "wamp.error.goodbye_and_out" => Ok(Reason::GoodbyeAndOut), 156 | "wamp.error.not_authorized" => Ok(Reason::NotAuthorized), 157 | "wamp.error.authorization_failed" => Ok(Reason::AuthorizationFailed), 158 | "wamp.error.no_such_realm" => Ok(Reason::NoSuchRealm), 159 | "wamp.error.no_such_role" => Ok(Reason::NoSuchRole), 160 | "wamp.error.cancelled" => Ok(Reason::Cancelled), 161 | "wamp.error.option_not_allowed" => Ok(Reason::OptionNotAllowed), 162 | "wamp.error.no_eligible_callee" => Ok(Reason::NoEligibleCallee), 163 | "wamp.error.option-disallowed.disclose_me" => Ok(Reason::OptionDisallowedDiscloseMe), 164 | "wamp.error.network_failure" => Ok(Reason::NetworkFailure), 165 | "wamp.close.normal" => Ok(Reason::NormalClose), 166 | x => Ok(Reason::CustomReason(URI::new(x))) 167 | } 168 | } 169 | 170 | } 171 | 172 | 173 | /*------------------------- 174 | ErrorType 175 | -------------------------*/ 176 | 177 | impl serde::Serialize for ErrorType { 178 | fn serialize(&self, serializer: S) -> Result 179 | where S: serde::Serializer, 180 | { 181 | let ser_int = match *self { 182 | ErrorType::Subscribe => 32, 183 | ErrorType::Unsubscribe => 34, 184 | ErrorType::Publish => 16, 185 | ErrorType::Register => 64, 186 | ErrorType::Unregister => 66, 187 | ErrorType::Invocation => 68, 188 | ErrorType::Call => 48, 189 | }; 190 | serializer.serialize_u64(ser_int) 191 | } 192 | } 193 | 194 | impl <'de> serde::Deserialize<'de> for ErrorType { 195 | fn deserialize(deserializer: D) -> Result 196 | where D: serde::Deserializer<'de>, 197 | { 198 | deserializer.deserialize_u64(ErrorTypeVisitor) 199 | } 200 | } 201 | 202 | impl <'de> serde::de::Visitor<'de> for ErrorTypeVisitor { 203 | type Value = ErrorType; 204 | 205 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 206 | formatter.write_str("Integer representing an error type") 207 | } 208 | 209 | #[inline] 210 | fn visit_u64(self, value: u64) -> Result 211 | where E: serde::de::Error, 212 | { 213 | match value { 214 | 32 => Ok(ErrorType::Subscribe), 215 | 34 => Ok(ErrorType::Unsubscribe), 216 | 16 => Ok(ErrorType::Publish), 217 | 64 => Ok(ErrorType::Register), 218 | 66 => Ok(ErrorType::Unregister), 219 | 68 => Ok(ErrorType::Invocation), 220 | 48 => Ok(ErrorType::Call), 221 | x => Err(serde::de::Error::custom(format!("Invalid message error type: {}", x))) 222 | } 223 | } 224 | 225 | } 226 | -------------------------------------------------------------------------------- /src/router/messaging.rs: -------------------------------------------------------------------------------- 1 | use super::{ConnectionHandler, ConnectionInfo, WAMP_JSON, ConnectionState}; 2 | use ws::{Sender, Handler, Message as WSMessage, Error as WSError, ErrorKind as WSErrorKind, Result as WSResult, Request, Response, CloseCode}; 3 | use std::sync::{Arc, Mutex}; 4 | 5 | use std::collections::{HashMap}; 6 | use serde_json; 7 | use serde::{Deserialize, Serialize}; 8 | use rmp_serde::Deserializer as RMPDeserializer; 9 | use rmp_serde::Serializer; 10 | use utils::StructMapWriter; 11 | use std::io::Cursor; 12 | use messages::{Message, ErrorType, Reason}; 13 | use ::{ID, WampResult, Error, ErrorKind, Dict, List}; 14 | 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 | 37 | fn send_message_msgpack(sender: &Sender, message: &Message) -> WSResult<()> { 38 | // Send the message 39 | let mut buf: Vec = Vec::new(); 40 | message.serialize(&mut Serializer::with(&mut buf, StructMapWriter)).unwrap(); 41 | sender.send(WSMessage::Binary(buf)) 42 | } 43 | 44 | impl ConnectionHandler { 45 | 46 | fn handle_message(&mut self, message: Message) -> WampResult<()> { 47 | debug!("Recieved message {:?}", message); 48 | match message { 49 | Message::Hello(realm, details) => { 50 | self.handle_hello(realm, details) 51 | }, 52 | Message::Subscribe(request_id, options, topic) => { 53 | self.handle_subscribe(request_id, options, topic) 54 | }, 55 | Message::Publish(request_id, options, topic, args, kwargs) => { 56 | self.handle_publish(request_id, options, topic, args, kwargs) 57 | }, 58 | Message::Unsubscribe(request_id, topic_id) => { 59 | self.handle_unsubscribe(request_id, topic_id) 60 | }, 61 | Message::Goodbye(details, reason) => { 62 | self.handle_goodbye(details, reason) 63 | }, 64 | Message::Register(request_id, options, procedure) => { 65 | self.handle_register(request_id, options, procedure) 66 | }, 67 | Message::Unregister(request_id, procedure_id) => { 68 | self.handle_unregister(request_id, procedure_id) 69 | }, 70 | Message::Call(request_id, options, procedure, args, kwargs) => { 71 | self.handle_call(request_id, options, procedure, args, kwargs) 72 | }, 73 | Message::Yield(invocation_id, options, args, kwargs) => { 74 | self.handle_yield(invocation_id, options, args, kwargs) 75 | } 76 | Message::Error(e_type, request_id, details, reason, args, kwargs) => { 77 | self.handle_error(e_type, request_id, details, reason, args, kwargs) 78 | } 79 | t => { 80 | Err(Error::new(ErrorKind::InvalidMessageType(t))) 81 | } 82 | } 83 | } 84 | 85 | fn handle_error(&mut self, e_type: ErrorType, request_id: ID, details: Dict, reason: Reason, args: Option, kwargs: Option) -> WampResult<()> { 86 | if e_type == ErrorType::Invocation { 87 | debug!("Responding to error message for invocation (id: {})", request_id); 88 | match self.realm { 89 | Some(ref realm) => { 90 | let mut realm = realm.lock().unwrap(); 91 | let mut manager = &mut realm.registration_manager; 92 | if let Some((call_id, callee)) = manager.active_calls.remove(&request_id) { 93 | let error_message = Message::Error(ErrorType::Call, call_id, details, reason, args, kwargs); 94 | send_message(&callee, &error_message) 95 | } else { 96 | Err(Error::new(ErrorKind::InvalidState("Recieved an error message for a call that wasn't sent"))) 97 | } 98 | }, None => { 99 | Err(Error::new(ErrorKind::InvalidState("Recieved a message while not attached to a realm"))) 100 | } 101 | } 102 | } else { 103 | Err(Error::new(ErrorKind::InvalidState("Got an error message that was not for a call message"))) 104 | } 105 | } 106 | 107 | fn parse_message(&self, msg: WSMessage) -> WampResult { 108 | match msg { 109 | WSMessage::Text(payload) => { 110 | match serde_json::from_str(&payload) { 111 | Ok(message) => Ok(message), 112 | Err(e) => Err(Error::new(ErrorKind::JSONError(e))) 113 | } 114 | }, 115 | WSMessage::Binary(payload) => { 116 | let mut de = RMPDeserializer::new(Cursor::new(payload)); 117 | match Deserialize::deserialize(&mut de) { 118 | Ok(message) => { 119 | Ok(message) 120 | }, 121 | Err(e) => { 122 | Err(Error::new(ErrorKind::MsgPackError(e))) 123 | } 124 | } 125 | } 126 | } 127 | } 128 | 129 | fn send_error(&self, err_type: ErrorType, request_id: ID, reason: Reason) -> WSResult<()> { 130 | send_message(&self.info, &Message::Error(err_type, request_id, HashMap::new(), reason, None, None)).map_err(|e| { 131 | let kind = e.get_kind(); 132 | if let ErrorKind::WSError(e) = kind { 133 | e 134 | } else { 135 | WSError::new(WSErrorKind::Internal, kind.description()) 136 | } 137 | }) 138 | } 139 | fn on_message_error(&mut self, error: Error) -> WSResult<()> { 140 | use std::error::Error as StdError; 141 | match error.get_kind() { 142 | ErrorKind::WSError(e) => Err(e), 143 | ErrorKind::URLError(_) => {unimplemented!()}, 144 | ErrorKind::UnexpectedMessage(msg) => { 145 | error!("Unexpected Message: {}", msg); 146 | self.terminate_connection() 147 | }, 148 | ErrorKind::ThreadError(_) => {unimplemented!()}, 149 | ErrorKind::ConnectionLost => {unimplemented!()}, 150 | ErrorKind::Closing(_) => {unimplemented!{}}, 151 | ErrorKind::JSONError(e) => { 152 | error!("Could not parse JSON: {}", e); 153 | self.terminate_connection() 154 | }, 155 | ErrorKind::MsgPackError(e) => { 156 | error!("Could not parse MsgPack: {}", e.description()); 157 | self.terminate_connection() 158 | }, 159 | ErrorKind::MalformedData => { 160 | unimplemented!() 161 | }, 162 | ErrorKind::InvalidMessageType(msg) => { 163 | error!("Router unable to handle message {:?}", msg); 164 | self.terminate_connection() 165 | }, 166 | ErrorKind::InvalidState(s) => { 167 | error!("Invalid State: {}", s); 168 | self.terminate_connection() 169 | }, 170 | ErrorKind::Timeout => { 171 | error!("Connection timeout"); 172 | self.terminate_connection() 173 | 174 | } 175 | ErrorKind::ErrorReason(err_type, id, reason) => { 176 | self.send_error(err_type, id, reason) 177 | } 178 | } 179 | } 180 | 181 | } 182 | 183 | impl Handler for ConnectionHandler { 184 | fn on_request(&mut self, request: &Request) -> WSResult { 185 | info!("New request"); 186 | let mut response = match Response::from_request(request) { 187 | Ok(response) => response, 188 | Err(e) => { 189 | error!("Could not create response: {}", e); 190 | return Err(e); 191 | } 192 | }; 193 | try!(self.process_protocol(request, &mut response)); 194 | debug!("Sending response"); 195 | Ok(response) 196 | } 197 | 198 | fn on_message(&mut self, msg: WSMessage) -> WSResult<()> { 199 | debug!("Receveied message: {:?}", msg); 200 | let message = match self.parse_message(msg) { 201 | Err(e) => return self.on_message_error(e), 202 | Ok(m) => m 203 | }; 204 | match self.handle_message(message) { 205 | Err(e) => self.on_message_error(e), 206 | _ => Ok(()) 207 | } 208 | } 209 | 210 | fn on_close(&mut self, _code: CloseCode, _reason: &str) { 211 | let state = self.info.lock().unwrap().state.clone(); 212 | if state != ConnectionState::Disconnected { 213 | trace!("Client disconnected. Closing connection"); 214 | self.terminate_connection().ok(); 215 | } 216 | } 217 | 218 | 219 | } 220 | -------------------------------------------------------------------------------- /src/messages/types/value.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use CallResult; 3 | use serde; 4 | use super::{Reason, CallError}; 5 | use std::fmt; 6 | 7 | pub type Dict = HashMap; 8 | pub type List = Vec; 9 | 10 | // TODO properly implement Hash and Eq 11 | #[derive(Debug, PartialEq, Clone, Hash, Eq)] 12 | pub struct URI { 13 | pub uri: String 14 | } 15 | 16 | impl URI { 17 | pub fn new(uri: &str) -> URI { 18 | URI { 19 | uri: uri.to_string() 20 | } 21 | } 22 | } 23 | 24 | #[derive(Debug, PartialEq, Clone)] 25 | pub enum Value { 26 | // The ID and URI types cannot be distinguished from string and integer types respectively. 27 | // So, we just ignore them here 28 | Dict(Dict), 29 | Integer(i64), 30 | String(String), 31 | List(List), 32 | Boolean(bool) 33 | } 34 | 35 | struct URIVisitor; 36 | struct ValueVisitor; 37 | 38 | 39 | pub trait ArgList { 40 | fn get_int(&self, index: usize) -> CallResult>; 41 | fn get_string<'a>(&'a self, index: usize) -> CallResult>; 42 | fn verify_len(&self, expected_len: usize) -> CallResult<()>; 43 | } 44 | 45 | pub trait ArgDict { 46 | fn get_int(&self, key: &str) -> CallResult>; 47 | fn get_string<'a>(&'a self, key: &str) -> CallResult>; 48 | } 49 | 50 | impl ArgList for List { 51 | fn get_int(&self, index: usize) -> CallResult> { 52 | let value = self.get(index); 53 | match value { 54 | Some(value) => { 55 | if let &Value::Integer(value) = value { 56 | Ok(Some(value)) 57 | } else { 58 | Err(CallError::new(Reason::InvalidArgument, Some(vec![Value::String(format!("Expected integer, got {}", value.summarize()))]), None)) 59 | } 60 | }, 61 | None => { 62 | Ok(None) 63 | } 64 | } 65 | } 66 | 67 | fn get_string<'a>(&'a self, index: usize) -> CallResult> { 68 | let value = self.get(index); 69 | match value { 70 | Some(value) => { 71 | if let &Value::String(ref value) = value { 72 | Ok(Some(value)) 73 | } else { 74 | Err(CallError::new(Reason::InvalidArgument, Some(vec![Value::String(format!("Expected string, got {}", value.summarize()))]), None)) 75 | } 76 | }, 77 | None => { 78 | Ok(None) 79 | } 80 | } 81 | } 82 | 83 | fn verify_len(&self, expected_len: usize) -> CallResult<()> { 84 | if self.len() >= expected_len { 85 | Ok(()) 86 | } else { 87 | Err(CallError::new(Reason::InvalidArgument, Some(vec![Value::String(format!("Expected {} arguments, got {}", expected_len, self.len()))]), None)) 88 | } 89 | } 90 | } 91 | 92 | impl ArgDict for Dict { 93 | fn get_int(&self, key: &str) -> CallResult> { 94 | let value = self.get(key); 95 | match value { 96 | Some(value) => { 97 | if let &Value::Integer(value) = value { 98 | Ok(Some(value)) 99 | } else { 100 | Err(CallError::new(Reason::InvalidArgument, Some(vec![Value::String(format!("Expected integer, got {}", value.summarize()))]), None)) 101 | } 102 | }, 103 | None => { 104 | Ok(None) 105 | } 106 | } 107 | } 108 | fn get_string<'a>(&'a self, key: &str) -> CallResult> { 109 | let value = self.get(key); 110 | match value { 111 | Some(value) => { 112 | if let &Value::String(ref value) = value { 113 | Ok(Some(value)) 114 | } else { 115 | Err(CallError::new(Reason::InvalidArgument, Some(vec![Value::String(format!("Expected string, got {}", value.summarize()))]), None)) 116 | } 117 | }, 118 | None => { 119 | Ok(None) 120 | } 121 | } 122 | } 123 | } 124 | 125 | impl Value { 126 | pub fn summarize(&self) -> String { 127 | match self { 128 | &Value::Dict(ref d) => { 129 | let mut result = String::new(); 130 | result.push('{'); 131 | result.push_str(&d.iter().take(50).map(|(key, value)| format!("{}:{}", key, value.summarize())).collect::>().join(",")); 132 | result.push('}'); 133 | result 134 | }, 135 | &Value::Integer(i) => { 136 | i.to_string() 137 | }, 138 | &Value::String(ref s) => { 139 | if s.len() > 50 { 140 | s[..50].to_string() 141 | } else { 142 | s.clone() 143 | } 144 | } 145 | &Value::List(ref l) => { 146 | let mut result = String::new(); 147 | result.push('['); 148 | result.push_str(&l.iter().take(50).map(|element| element.summarize()).collect::>().join(",")); 149 | result.push(']'); 150 | result 151 | } 152 | &Value::Boolean(b) => { 153 | b.to_string() 154 | } 155 | } 156 | } 157 | } 158 | 159 | // XXX Right now there is no way to tell the difference between a URI and a string, or an ID and an Integer 160 | impl <'de> serde::de::Visitor<'de> for ValueVisitor { 161 | type Value = Value; 162 | 163 | 164 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 165 | formatter.write_str("JSON value") 166 | } 167 | 168 | #[inline] 169 | fn visit_str(self, value: &str) -> Result 170 | where E: serde::de::Error { 171 | Ok(Value::String(value.to_string())) 172 | } 173 | 174 | 175 | #[inline] 176 | fn visit_i64(self, value: i64) -> Result 177 | where E: serde::de::Error { 178 | Ok(Value::Integer(value)) 179 | } 180 | 181 | #[inline] 182 | fn visit_u64(self, value: u64) -> Result 183 | where E: serde::de::Error { 184 | Ok(Value::Integer(value as i64)) 185 | } 186 | 187 | #[inline] 188 | fn visit_bool(self, value: bool) -> Result 189 | where E: serde::de::Error { 190 | Ok(Value::Boolean(value)) 191 | } 192 | 193 | 194 | #[inline] 195 | fn visit_map(self, mut visitor: Visitor) -> Result 196 | where Visitor: serde::de::MapAccess<'de>, 197 | { 198 | let mut values = HashMap::new(); 199 | if let Some(size) = visitor.size_hint() { 200 | values.reserve(size); 201 | } 202 | 203 | while let Some((key, value)) = visitor.next_entry()? { 204 | values.insert(key, value); 205 | } 206 | 207 | 208 | 209 | Ok(Value::Dict(values)) 210 | } 211 | 212 | #[inline] 213 | fn visit_seq(self, mut visitor: Visitor) -> Result 214 | where Visitor: serde::de::SeqAccess<'de>, 215 | { 216 | let mut values = Vec::new(); 217 | if let Some(size) = visitor.size_hint() { 218 | values.reserve(size); 219 | } 220 | 221 | while let Some(value) = visitor.next_element()? { 222 | values.push(value); 223 | } 224 | 225 | 226 | 227 | Ok(Value::List(values)) 228 | } 229 | } 230 | 231 | /*------------------------- 232 | Value 233 | -------------------------*/ 234 | impl serde::Serialize for Value { 235 | fn serialize(&self, serializer: S) -> Result 236 | where S: serde::ser::Serializer, 237 | { 238 | match self { 239 | &Value::Dict(ref dict) => dict.serialize(serializer), 240 | &Value::String(ref s) => serializer.serialize_str(s), 241 | &Value::Integer(i) => serializer.serialize_i64(i), 242 | &Value::List(ref list) => list.serialize(serializer), 243 | &Value::Boolean(b) => serializer.serialize_bool(b) 244 | } 245 | } 246 | } 247 | 248 | impl <'de> serde::Deserialize<'de> for Value { 249 | fn deserialize(deserializer: D) -> Result 250 | where D: serde::Deserializer<'de>, 251 | { 252 | deserializer.deserialize_any(ValueVisitor) 253 | } 254 | } 255 | 256 | /*------------------------- 257 | URI 258 | -------------------------*/ 259 | 260 | impl serde::Serialize for URI { 261 | fn serialize(&self, serializer: S) -> Result 262 | where S: serde::ser::Serializer, 263 | { 264 | serializer.serialize_str(&self.uri) 265 | } 266 | } 267 | 268 | impl <'de> serde::Deserialize<'de> for URI { 269 | fn deserialize(deserializer: D) -> Result 270 | where D: serde::Deserializer<'de>, 271 | { 272 | deserializer.deserialize_str(URIVisitor) 273 | } 274 | } 275 | 276 | impl <'de> serde::de::Visitor<'de> for URIVisitor { 277 | type Value = URI; 278 | 279 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 280 | formatter.write_str("URI") 281 | } 282 | #[inline] 283 | fn visit_str(self, value: &str) -> Result 284 | where E: serde::de::Error, 285 | { 286 | Ok(URI { 287 | uri: value.to_string() 288 | }) 289 | } 290 | 291 | } 292 | -------------------------------------------------------------------------------- /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::{ConnectionInfo, random_id}; 4 | use ::{ID, URI, MatchingPolicy, InvocationPolicy}; 5 | use messages::Reason; 6 | use std::sync::{Arc, Mutex}; 7 | use std::cell::RefCell; 8 | use std::collections::HashMap; 9 | use std::fmt::{Debug, Formatter, self}; 10 | use rand::thread_rng; 11 | use rand::Rng; 12 | 13 | 14 | 15 | /// Contains a trie corresponding to the registration patterns that connections have requested. 16 | /// 17 | /// Each level of the trie corresponds to a fragment of a uri between the '.' character. 18 | /// Thus each registration that starts with 'com' for example will be grouped together. 19 | /// Registrations can be added and removed, and the connections that match a particular URI 20 | /// can be iterated over using the `filter()` method. 21 | 22 | pub struct RegistrationPatternNode { 23 | edges: HashMap>, 24 | connections: ProcdureCollection

, 25 | prefix_connections: ProcdureCollection

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

{ 74 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 75 | self.fmt_with_indent(f, 0) 76 | } 77 | } 78 | 79 | impl ProcdureCollection

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

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

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

{ 171 | RegistrationPatternNode { 172 | edges: HashMap::new(), 173 | connections: ProcdureCollection { 174 | invocation_policy: InvocationPolicy::Single, 175 | round_robin_counter: RefCell::new(0), 176 | procedures: Vec::new() 177 | }, 178 | prefix_connections:ProcdureCollection { 179 | invocation_policy: InvocationPolicy::Single, 180 | round_robin_counter: RefCell::new(0), 181 | procedures: Vec::new() 182 | }, 183 | id: random_id(), 184 | prefix_id: random_id() 185 | } 186 | } 187 | 188 | fn add_registration<'a, I>(&mut self, mut uri_bits: I, registrant: P, matching_policy: MatchingPolicy, invocation_policy: InvocationPolicy) -> Result where I: Iterator { 189 | match uri_bits.next() { 190 | Some(uri_bit) => { 191 | if uri_bit.len() == 0 { 192 | if matching_policy != MatchingPolicy::Wildcard { 193 | return Err(PatternError::new(Reason::InvalidURI)); 194 | } 195 | } 196 | let edge = self.edges.entry(uri_bit.to_string()).or_insert(RegistrationPatternNode::new()); 197 | edge.add_registration(uri_bits, registrant, matching_policy, invocation_policy) 198 | }, 199 | None => { 200 | if matching_policy == MatchingPolicy::Prefix { 201 | try!(self.prefix_connections.add_procedure(registrant, matching_policy, invocation_policy)); 202 | Ok(self.prefix_id) 203 | } else { 204 | try!(self.connections.add_procedure(registrant, matching_policy, invocation_policy)); 205 | Ok(self.id) 206 | } 207 | } 208 | } 209 | } 210 | 211 | fn remove_registration<'a, I>(&mut self, mut uri_bits: I, registrant_id: u64, is_prefix: bool) -> Result where I: Iterator { 212 | // TODO consider deleting nodes in the tree if they are no longer in use. 213 | match uri_bits.next() { 214 | Some(uri_bit) => { 215 | if let Some(mut edge) = self.edges.get_mut(uri_bit) { 216 | edge.remove_registration(uri_bits, registrant_id, is_prefix) 217 | } else { 218 | return Err(PatternError::new(Reason::InvalidURI)) 219 | } 220 | }, 221 | None => { 222 | if is_prefix { 223 | self.prefix_connections.remove_procedure(registrant_id); 224 | Ok((self.prefix_id)) 225 | } else { 226 | self.connections.remove_procedure(registrant_id); 227 | Ok((self.id)) 228 | } 229 | } 230 | } 231 | } 232 | 233 | fn find_registrant(&self, uri_bits: &Vec<&str>, depth: usize) -> Option<(&DataWrapper

, ID)> { 234 | if depth == uri_bits.len() { 235 | if let Some(registrant) = self.connections.get_entry() { 236 | Some((registrant, self.id)) 237 | } else if let Some(registrant) = self.prefix_connections.get_entry() { 238 | Some((registrant, self.prefix_id)) 239 | } else { 240 | None 241 | } 242 | } else { 243 | if let Some((registrant, id)) = self.recurse(uri_bits, depth) { 244 | Some((registrant, id)) 245 | } else if let Some(registrant) = self.prefix_connections.get_entry() { 246 | Some((registrant, self.prefix_id)) 247 | } else { 248 | None 249 | } 250 | } 251 | } 252 | 253 | fn recurse(&self, uri_bits: &Vec<&str>, depth: usize) -> Option<(&DataWrapper

, ID)> { 254 | if let Some(edge) = self.edges.get(uri_bits[depth]) { 255 | if let Some(registrant) = edge.find_registrant(uri_bits, depth + 1) { 256 | return Some(registrant) 257 | } 258 | } 259 | if let Some(edge) = self.edges.get("") { 260 | if let Some(registrant) = edge.find_registrant(uri_bits, depth + 1) { 261 | return Some(registrant) 262 | } 263 | } 264 | None 265 | } 266 | 267 | } 268 | 269 | 270 | 271 | #[cfg(test)] 272 | mod test { 273 | use ::{URI, MatchingPolicy, InvocationPolicy, ID}; 274 | use super::{RegistrationPatternNode, PatternData}; 275 | 276 | #[derive(Clone)] 277 | struct MockData { 278 | id: ID 279 | } 280 | 281 | impl PatternData for MockData { 282 | fn get_id(&self) -> ID { 283 | self.id 284 | } 285 | } 286 | impl MockData { 287 | pub fn new(id: ID) -> MockData { 288 | MockData { 289 | id: id 290 | } 291 | } 292 | } 293 | 294 | #[test] 295 | fn adding_patterns() { 296 | let connection1 = MockData::new(1); 297 | let connection2 = MockData::new(2); 298 | let connection3 = MockData::new(3); 299 | let connection4 = MockData::new(4); 300 | let mut root = RegistrationPatternNode::new(); 301 | 302 | let ids = [ 303 | root.register_with(&URI::new("com.example.test..topic"), connection1, MatchingPolicy::Wildcard, InvocationPolicy::Single).unwrap(), 304 | root.register_with(&URI::new("com.example.test.specific.topic"), connection2, MatchingPolicy::Strict, InvocationPolicy::Single).unwrap(), 305 | root.register_with(&URI::new("com.example"), connection3, MatchingPolicy::Prefix, InvocationPolicy::Single).unwrap(), 306 | root.register_with(&URI::new("com.example.test"), connection4, MatchingPolicy::Prefix, InvocationPolicy::Single).unwrap(), 307 | ]; 308 | println!("ids: {:?}", ids); 309 | 310 | assert_eq!(root.get_registrant_for(URI::new("com.example.test.specific.topic")).unwrap().1, ids[1]); 311 | assert_eq!(root.get_registrant_for(URI::new("com.example.test.another.topic")).unwrap().1, ids[0]); 312 | assert_eq!(root.get_registrant_for(URI::new("com.example.test.another")).unwrap().1, ids[3]); 313 | assert_eq!(root.get_registrant_for(URI::new("com.example")).unwrap().1, ids[2]); 314 | 315 | } 316 | 317 | #[test] 318 | fn removing_patterns() { 319 | let connection1 = MockData::new(1); 320 | let connection2 = MockData::new(2); 321 | let connection3 = MockData::new(3); 322 | let connection4 = MockData::new(4); 323 | let mut root = RegistrationPatternNode::new(); 324 | 325 | let ids = [ 326 | root.register_with(&URI::new("com.example.test..topic"), connection1.clone(), MatchingPolicy::Wildcard, InvocationPolicy::Single).unwrap(), 327 | root.register_with(&URI::new("com.example.test.specific.topic"), connection2, MatchingPolicy::Strict, InvocationPolicy::Single).unwrap(), 328 | root.register_with(&URI::new("com.example"), connection3, MatchingPolicy::Prefix, InvocationPolicy::Single).unwrap(), 329 | root.register_with(&URI::new("com.example.test"), connection4.clone(), MatchingPolicy::Prefix, InvocationPolicy::Single).unwrap(), 330 | ]; 331 | 332 | root.unregister_with("com.example.test..topic", &connection1, false).unwrap(); 333 | root.unregister_with("com.example.test", &connection4, true).unwrap(); 334 | 335 | println!("ids: {:?}", ids); 336 | assert_eq!(root.get_registrant_for(URI::new("com.example.test.specific.topic")).unwrap().1, ids[1]); 337 | 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /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::{ConnectionInfo, random_id}; 4 | use ::{ID, URI, MatchingPolicy}; 5 | use messages::Reason; 6 | use std::sync::{Arc, Mutex}; 7 | use std::collections::HashMap; 8 | use std::slice::Iter; 9 | use std::mem; 10 | use std::fmt::{Debug, Formatter, self}; 11 | 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 | 22 | pub struct SubscriptionPatternNode { 23 | edges: HashMap>, 24 | connections: Vec>, 25 | prefix_connections: Vec>, 26 | id: ID, 27 | prefix_id: ID 28 | } 29 | 30 | /// Represents data that a pattern trie will hold 31 | pub trait PatternData { 32 | fn get_id(&self) -> ID; 33 | } 34 | 35 | struct DataWrapper { 36 | subscriber: P, 37 | policy: MatchingPolicy 38 | } 39 | 40 | /// A lazy iterator that traverses the pattern trie. See `SubscriptionPatternNode` for more. 41 | pub struct MatchIterator<'a, P> where 42 | P : PatternData, 43 | P : 'a { 44 | uri: Vec, 45 | current: Box> 46 | } 47 | 48 | struct StackFrame<'a, P> where 49 | P : PatternData, 50 | P : 'a { 51 | node: &'a SubscriptionPatternNode

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

>), 71 | PrefixComplete, 72 | Subs(Iter<'a, DataWrapper

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

{ 110 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 111 | self.fmt_with_indent(f, 0) 112 | } 113 | } 114 | 115 | impl SubscriptionPatternNode

{ 116 | 117 | fn fmt_with_indent(&self, f: &mut Formatter, indent: usize) -> fmt::Result { 118 | try!(writeln!(f, "{} pre: {:?} subs: {:?}", 119 | self.id, 120 | self.prefix_connections.iter().map(|sub| sub.subscriber.get_id()).collect::>(), 121 | self.connections.iter().map(|sub| sub.subscriber.get_id()).collect::>())); 122 | for (chunk, node) in self.edges.iter() { 123 | for _ in 0..indent * 2 { 124 | try!(write!(f, " ")); 125 | } 126 | try!(write!(f, "{} - ", chunk)); 127 | try!(node.fmt_with_indent(f, indent + 1)); 128 | } 129 | Ok(()) 130 | } 131 | 132 | /// Add a new subscription to the pattern trie with the given pattern and matching policy. 133 | pub fn subscribe_with(&mut self, topic: &URI, subscriber: P, matching_policy: MatchingPolicy) -> Result { 134 | let mut uri_bits = topic.uri.split("."); 135 | let initial = match uri_bits.next() { 136 | Some(initial) => initial, 137 | None => return Err(PatternError::new(Reason::InvalidURI)) 138 | }; 139 | let edge = self.edges.entry(initial.to_string()).or_insert(SubscriptionPatternNode::new()); 140 | edge.add_subscription(uri_bits, subscriber, matching_policy) 141 | } 142 | 143 | /// Removes a subscription from the pattern trie. 144 | pub fn unsubscribe_with(&mut self, topic: &str, subscriber: &P, is_prefix: bool) -> Result { 145 | let uri_bits = topic.split("."); 146 | self.remove_subscription(uri_bits, subscriber.get_id(), is_prefix) 147 | } 148 | 149 | /// Constructs a new SubscriptionPatternNode to be used as the root of the trie 150 | #[inline] 151 | pub fn new() -> SubscriptionPatternNode

{ 152 | SubscriptionPatternNode { 153 | edges: HashMap::new(), 154 | connections: Vec::new(), 155 | prefix_connections: Vec::new(), 156 | id: random_id(), 157 | prefix_id: random_id() 158 | } 159 | } 160 | 161 | fn add_subscription<'a, I>(&mut self, mut uri_bits: I, subscriber: P, matching_policy: MatchingPolicy) -> Result where I: Iterator { 162 | match uri_bits.next() { 163 | Some(uri_bit) => { 164 | if uri_bit.len() == 0 { 165 | if matching_policy != MatchingPolicy::Wildcard { 166 | return Err(PatternError::new(Reason::InvalidURI)); 167 | } 168 | } 169 | let edge = self.edges.entry(uri_bit.to_string()).or_insert(SubscriptionPatternNode::new()); 170 | edge.add_subscription(uri_bits, subscriber, matching_policy) 171 | }, 172 | None => { 173 | if matching_policy == MatchingPolicy::Prefix { 174 | self.prefix_connections.push(DataWrapper { 175 | subscriber: subscriber, 176 | policy: matching_policy 177 | }); 178 | Ok(self.prefix_id) 179 | } else { 180 | self.connections.push(DataWrapper { 181 | subscriber: subscriber, 182 | policy: matching_policy 183 | }); 184 | Ok(self.id) 185 | } 186 | } 187 | } 188 | } 189 | 190 | fn remove_subscription<'a, I>(&mut self, mut uri_bits: I, subscriber_id: u64, is_prefix: bool) -> Result where I: Iterator { 191 | // TODO consider deleting nodes in the tree if they are no longer in use. 192 | match uri_bits.next() { 193 | Some(uri_bit) => { 194 | if let Some(mut edge) = self.edges.get_mut(uri_bit) { 195 | edge.remove_subscription(uri_bits, subscriber_id, is_prefix) 196 | } else { 197 | return Err(PatternError::new(Reason::InvalidURI)) 198 | } 199 | }, 200 | None => { 201 | if is_prefix { 202 | self.prefix_connections.retain(|sub| sub.subscriber.get_id() != subscriber_id); 203 | Ok((self.prefix_id)) 204 | } else { 205 | self.connections.retain(|sub| sub.subscriber.get_id() != subscriber_id); 206 | Ok((self.id)) 207 | } 208 | } 209 | } 210 | } 211 | 212 | /// Constructs a lazy iterator over all of the connections whose subscription patterns 213 | /// match the given uri. 214 | /// 215 | /// This iterator returns a triple with the connection info, the id of the subscription and 216 | /// the matching policy used when the subscription was created. 217 | pub fn filter<'a>(&'a self, topic: URI) -> MatchIterator<'a, P> { 218 | MatchIterator { 219 | current: Box::new(StackFrame { 220 | node: self, 221 | depth: 0, 222 | state: IterState::None, 223 | parent: None 224 | }), 225 | uri: topic.uri.split('.').map(|s| s.to_string()).collect() 226 | } 227 | } 228 | } 229 | 230 | impl <'a, P: PatternData> MatchIterator<'a, P> { 231 | 232 | fn push(&mut self, child: &'a SubscriptionPatternNode

) { 233 | let new_node = Box::new(StackFrame { 234 | parent: None, 235 | depth: self.current.depth + 1, 236 | node: child, 237 | state: IterState::None 238 | }); 239 | let parent = mem::replace(&mut self.current, new_node); 240 | self.current.parent = Some(parent); 241 | } 242 | 243 | /// Moves through the subscription tree, looking for the next set of connections that match the 244 | /// given uri. 245 | fn traverse(&mut self) -> Option<(&'a P, ID, MatchingPolicy)> { 246 | // This method functions as a push down automata. For each node, it starts by iterating 247 | // through the data that match a prefix of the uri 248 | // Then when that's done, it checks if the uri has been fully processed, and if so, iterates 249 | // through the connections that require exact matching 250 | // Otherwise, it pushes the current node on the stack, consumes another chunk of the uri 251 | // and moves on to any children that use wildcard matching. 252 | // Once it is finished traversing that part of the tree, it re-consumes the same chunk 253 | // of the URI, and moves on to any children that match the chunk exactly. 254 | // After all that is exhausted, it will pop the node of the stack and return to its parent 255 | match self.current.state { 256 | IterState::None => { 257 | self.current.state = IterState::Prefix(self.current.node.prefix_connections.iter()) 258 | }, 259 | IterState::Prefix(_) => { 260 | self.current.state = IterState::PrefixComplete; 261 | }, 262 | IterState::PrefixComplete => { 263 | if self.current.depth == self.uri.len() { 264 | self.current.state = IterState::Subs(self.current.node.connections.iter()); 265 | } else { 266 | if let Some(child) = self.current.node.edges.get("") { 267 | self.current.state = IterState::Wildcard; 268 | self.push(child); 269 | } else { 270 | if let Some(child) = self.current.node.edges.get(&self.uri[self.current.depth]) { 271 | self.current.state = IterState::Strict; 272 | self.push(child); 273 | } 274 | else { 275 | self.current.state = IterState::AllComplete; 276 | } 277 | } 278 | } 279 | }, 280 | IterState::Wildcard => { 281 | if self.current.depth == self.uri.len() { 282 | self.current.state = IterState::AllComplete; 283 | } else { 284 | if let Some(child) = self.current.node.edges.get(&self.uri[self.current.depth]) { 285 | self.current.state = IterState::Strict; 286 | self.push(child); 287 | } else { 288 | self.current.state = IterState::AllComplete; 289 | } 290 | } 291 | }, 292 | IterState::Strict => { 293 | self.current.state = IterState::AllComplete; 294 | }, 295 | IterState::Subs(_) => { 296 | 297 | self.current.state = IterState::AllComplete; 298 | }, 299 | IterState::AllComplete => { 300 | if self.current.depth == 0 { 301 | return None 302 | } else { 303 | let parent = self.current.parent.take(); 304 | mem::replace(&mut self.current, parent.unwrap()); 305 | } 306 | } 307 | }; 308 | self.next() 309 | } 310 | } 311 | 312 | impl <'a, P: PatternData> Iterator for MatchIterator<'a, P> { 313 | type Item = (&'a P, ID, MatchingPolicy); 314 | 315 | fn next(&mut self) -> Option<(&'a P, ID, MatchingPolicy)> { 316 | 317 | // If we are currently iterating through connections, continue iterating 318 | match self.current.state { 319 | IterState::Prefix(ref mut prefix_iter) => { 320 | let next = prefix_iter.next(); 321 | if let Some(next) = next { 322 | return Some((&next.subscriber, self.current.node.prefix_id.clone(), next.policy)) 323 | } 324 | }, 325 | IterState::Subs(ref mut sub_iter) => { 326 | let next = sub_iter.next(); 327 | if let Some(next) = next { 328 | return Some((&next.subscriber, self.current.node.id.clone(), next.policy)) 329 | } 330 | }, 331 | _ => {} 332 | 333 | }; 334 | 335 | // Otherwise, it is time to traverse through the tree. 336 | self.traverse() 337 | 338 | } 339 | } 340 | 341 | #[cfg(test)] 342 | mod test { 343 | use ::{URI, MatchingPolicy, ID}; 344 | use super::{SubscriptionPatternNode, PatternData}; 345 | 346 | #[derive(Clone)] 347 | struct MockData { 348 | id: ID 349 | } 350 | 351 | impl PatternData for MockData { 352 | fn get_id(&self) -> ID { 353 | self.id 354 | } 355 | } 356 | impl MockData { 357 | pub fn new(id: ID) -> MockData { 358 | MockData { 359 | id: id 360 | } 361 | } 362 | } 363 | 364 | #[test] 365 | fn adding_patterns() { 366 | let connection1 = MockData::new(1); 367 | let connection2 = MockData::new(2); 368 | let connection3 = MockData::new(3); 369 | let connection4 = MockData::new(4); 370 | let mut root = SubscriptionPatternNode::new(); 371 | 372 | let ids = [ 373 | root.subscribe_with(&URI::new("com.example.test..topic"), connection1, MatchingPolicy::Wildcard).unwrap(), 374 | root.subscribe_with(&URI::new("com.example.test.specific.topic"), connection2, MatchingPolicy::Strict).unwrap(), 375 | root.subscribe_with(&URI::new("com.example"), connection3, MatchingPolicy::Prefix).unwrap(), 376 | root.subscribe_with(&URI::new("com.example.test"), connection4, MatchingPolicy::Prefix).unwrap(), 377 | ]; 378 | 379 | assert_eq!(root.filter(URI::new("com.example.test.specific.topic")).map(|(_connection, id, _policy)| id).collect::>(), vec![ 380 | ids[2], ids[3], ids[0], ids[1] 381 | ]); 382 | 383 | } 384 | 385 | #[test] 386 | fn removing_patterns() { 387 | let connection1 = MockData::new(1); 388 | let connection2 = MockData::new(2); 389 | let connection3 = MockData::new(3); 390 | let connection4 = MockData::new(4); 391 | let mut root = SubscriptionPatternNode::new(); 392 | 393 | let ids = [ 394 | root.subscribe_with(&URI::new("com.example.test..topic"), connection1.clone(), MatchingPolicy::Wildcard).unwrap(), 395 | root.subscribe_with(&URI::new("com.example.test.specific.topic"), connection2, MatchingPolicy::Strict).unwrap(), 396 | root.subscribe_with(&URI::new("com.example"), connection3, MatchingPolicy::Prefix).unwrap(), 397 | root.subscribe_with(&URI::new("com.example.test"), connection4.clone(), MatchingPolicy::Prefix).unwrap(), 398 | ]; 399 | 400 | root.unsubscribe_with("com.example.test..topic", &connection1, false).unwrap(); 401 | root.unsubscribe_with("com.example.test", &connection4, true).unwrap(); 402 | 403 | assert_eq!(root.filter(URI::new("com.example.test.specific.topic")).map(|(_connection, id, _policy)| id).collect::>(), vec![ 404 | ids[2], ids[1] 405 | ]) 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /src/messages/mod.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use serde; 4 | pub use messages::types::*; 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 | match $kwargs { 44 | &Some(ref kwargs) => { 45 | match $args { 46 | &Some(ref args) => ( $($item,)* args, kwargs).serialize($serializer), 47 | &None => ( $($item,)* Vec::::new(), kwargs).serialize($serializer), 48 | } 49 | }, &None => { 50 | match $args { 51 | &Some(ref args) => ( $($item,)* args).serialize($serializer), 52 | &None => ( $($item,)*).serialize($serializer), 53 | } 54 | 55 | } 56 | } 57 | ); 58 | } 59 | 60 | impl serde::Serialize for Message { 61 | fn serialize(&self, serializer: S) -> Result 62 | where S: serde::Serializer, 63 | { 64 | match *self { 65 | Message::Hello(ref realm, ref details) => { 66 | (1, &realm, details).serialize(serializer) 67 | }, 68 | Message::Welcome(ref session, ref details) => { 69 | (2, session, details).serialize(serializer) 70 | }, 71 | Message::Abort(ref details, ref reason) => { 72 | (3, details, reason).serialize(serializer) 73 | }, 74 | Message::Goodbye(ref details, ref reason) => { 75 | (6, details, reason).serialize(serializer) 76 | }, 77 | Message::Error(ref ty, id, ref details, ref reason, ref args, ref kwargs) => { 78 | serialize_with_args!(args, kwargs, serializer, 8, ty, id, details, reason) 79 | }, 80 | Message::Subscribe(request_id, ref options, ref topic) => { 81 | (32, request_id, options, topic).serialize(serializer) 82 | }, 83 | Message::Subscribed(request_id, subscription_id) => { 84 | (33, request_id, subscription_id).serialize(serializer) 85 | }, 86 | Message::Unsubscribe(request_id, subscription_id) => { 87 | (34, request_id, subscription_id).serialize(serializer) 88 | }, 89 | Message::Unsubscribed(request_id) => { 90 | (35, request_id).serialize(serializer) 91 | }, 92 | Message::Publish(id, ref details, ref topic, ref args, ref kwargs) => { 93 | serialize_with_args!(args, kwargs, serializer, 16, id, details, topic) 94 | }, 95 | Message::Published(request_id, publication_id) => { 96 | (17, request_id, publication_id).serialize(serializer) 97 | }, 98 | Message::Event(subscription_id, publication_id, ref details, ref args, ref kwargs) => { 99 | serialize_with_args!(args, kwargs, serializer, 36, subscription_id, publication_id, details) 100 | }, 101 | Message::Register(request_id, ref options, ref procedure) => { 102 | (64, request_id, options, procedure).serialize(serializer) 103 | }, 104 | Message::Registered(request_id, registration_id) => { 105 | (65, request_id, registration_id).serialize(serializer) 106 | }, 107 | Message::Unregister(request_id, registration_id) => { 108 | (66, request_id, registration_id).serialize(serializer) 109 | }, 110 | Message::Unregistered(request_id) => { 111 | (67, request_id).serialize(serializer) 112 | }, 113 | Message::Call(id, ref options, ref topic, ref args, ref kwargs) => { 114 | serialize_with_args!(args, kwargs, serializer, 48, id, options, topic) 115 | }, 116 | Message::Invocation(id, registration_id, ref details, ref args, ref kwargs) => { 117 | serialize_with_args!(args, kwargs, serializer, 68, id, registration_id, details) 118 | }, 119 | Message::Yield(id, ref options, ref args, ref kwargs) => { 120 | serialize_with_args!(args, kwargs, serializer, 70, id, options) 121 | }, 122 | Message::Result(id, ref details, ref args, ref kwargs) => { 123 | serialize_with_args!(args, kwargs, serializer, 50, id, details) 124 | } 125 | } 126 | } 127 | } 128 | 129 | impl <'de> serde::Deserialize<'de> for Message { 130 | fn deserialize(deserializer: D) -> Result 131 | where D: serde::Deserializer<'de> { 132 | deserializer.deserialize_any(MessageVisitor) 133 | } 134 | } 135 | 136 | struct MessageVisitor; 137 | 138 | 139 | 140 | impl MessageVisitor { 141 | fn visit_hello<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 142 | let uri = try_or!(visitor.next_element(), "Hello message ended before realm uri"); 143 | let details = try_or!(visitor.next_element(), "Hello message ended before details dict"); 144 | Ok( Message::Hello(uri, details)) 145 | } 146 | 147 | fn visit_welcome<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 148 | let session = try_or!(visitor.next_element(), "Welcome message ended before session id"); 149 | let details = try_or!(visitor.next_element(), "Welcome message ended before details dict"); 150 | Ok( Message::Welcome(session, details)) 151 | } 152 | 153 | fn visit_abort<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 154 | let details = try_or!(visitor.next_element(), "Abort message ended before details dict"); 155 | let reason = try_or!(visitor.next_element(), "Abort message ended before reason uri"); 156 | Ok( Message::Abort(details, reason)) 157 | } 158 | 159 | fn visit_goodbye<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 160 | let details = try_or!(visitor.next_element(), "Goodbye message ended before details dict"); 161 | let reason = try_or!(visitor.next_element(), "Goodbye message ended before reason uri"); 162 | Ok( Message::Goodbye(details, reason)) 163 | } 164 | 165 | fn visit_error<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 166 | let message_type = try_or!(visitor.next_element(), "Error message ended before message type"); 167 | let id = try_or!(visitor.next_element(), "Error message ended before session id"); 168 | let details = try_or!(visitor.next_element(), "Error message ended before details dict"); 169 | let reason = try_or!(visitor.next_element(), "Error message ended before reason uri"); 170 | let args = try!(visitor.next_element()); 171 | let kwargs = try!(visitor.next_element()); 172 | Ok( Message::Error(message_type, id, details, reason, args, kwargs)) 173 | 174 | } 175 | 176 | fn visit_subscribe<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 177 | let request = try_or!(visitor.next_element(), "Subscribe message ended before request id"); 178 | let options = try_or!(visitor.next_element(), "Subscribe message ended before options dict"); 179 | let topic = try_or!(visitor.next_element(), "Subscribe message ended before topic uri"); 180 | Ok( Message::Subscribe(request, options, topic) ) 181 | } 182 | 183 | fn visit_subscribed<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 184 | let request = try_or!(visitor.next_element(), "Subscribed message ended before request id"); 185 | let subscription = try_or!(visitor.next_element(), "Subscribed message ended before subscription id"); 186 | Ok(Message::Subscribed(request, subscription)) 187 | } 188 | 189 | fn visit_unsubscribe<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 190 | let request = try_or!(visitor.next_element(), "Unsubscribe message ended before request id"); 191 | let subscription = try_or!(visitor.next_element(), "Unsubscribe message ended before subscription id"); 192 | Ok(Message::Unsubscribe(request, subscription)) 193 | } 194 | 195 | fn visit_unsubscribed<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 196 | let request = try_or!(visitor.next_element(), "Unsubscribed message ended before request id"); 197 | Ok(Message::Unsubscribed(request)) 198 | } 199 | 200 | fn visit_publish<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 201 | let id = try_or!(visitor.next_element(), "Publish message ended before session id"); 202 | let details = try_or!(visitor.next_element(), "Publish message ended before details dict"); 203 | let topic = try_or!(visitor.next_element(), "Publish message ended before topic uri"); 204 | let args = try!(visitor.next_element()); 205 | let kwargs = try!(visitor.next_element()); 206 | Ok(Message::Publish(id, details, topic, args, kwargs)) 207 | } 208 | 209 | fn visit_published<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 210 | let request = try_or!(visitor.next_element(), "Published message ended before request id"); 211 | let publication = try_or!(visitor.next_element(), "Published message ended before publication id"); 212 | Ok(Message::Published(request, publication)) 213 | } 214 | 215 | fn visit_event<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 216 | let subscription_id = try_or!(visitor.next_element(), "Event message ended before session subscription id"); 217 | let publication_id = try_or!(visitor.next_element(), "Event message ended before publication id"); 218 | let details = try_or!(visitor.next_element(), "Event message ended before details dict"); 219 | let args = try!(visitor.next_element()); 220 | let kwargs = try!(visitor.next_element()); 221 | Ok(Message::Event(subscription_id, publication_id, details, args, kwargs)) 222 | } 223 | 224 | fn visit_register<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 225 | let request = try_or!(visitor.next_element(), "Register message ended before request id"); 226 | let options = try_or!(visitor.next_element(), "Register message ended before request options"); 227 | let procedure = try_or!(visitor.next_element(), "Register message ended before procedure"); 228 | Ok(Message::Register(request, options, procedure)) 229 | } 230 | 231 | fn visit_registered<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 232 | let request = try_or!(visitor.next_element(), "Registered message ended before request id"); 233 | let registration_id = try_or!(visitor.next_element(), "Registered message ended before registration id"); 234 | Ok(Message::Registered(request, registration_id)) 235 | } 236 | 237 | fn visit_unregister<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 238 | let request = try_or!(visitor.next_element(), "Registered message ended before request id"); 239 | let registration_id = try_or!(visitor.next_element(), "Registered message ended before registration id"); 240 | Ok(Message::Unregister(request, registration_id)) 241 | } 242 | 243 | fn visit_unregistered<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 244 | let request = try_or!(visitor.next_element(), "Registered message ended before request id"); 245 | Ok(Message::Unregistered(request)) 246 | } 247 | 248 | fn visit_call<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 249 | let id = try_or!(visitor.next_element(), "Call message ended before session id"); 250 | let options = try_or!(visitor.next_element(), "Call message ended before options dict"); 251 | let topic = try_or!(visitor.next_element(), "Call message ended before procedure uri"); 252 | let args = try!(visitor.next_element()); 253 | let kwargs = try!(visitor.next_element()); 254 | Ok(Message::Call(id, options, topic, args, kwargs)) 255 | } 256 | 257 | fn visit_invocation<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 258 | let id = try_or!(visitor.next_element(), "Invocation message ended before session id"); 259 | let registration_id = try_or!(visitor.next_element(), "Invocation message ended before registration id"); 260 | let details = try_or!(visitor.next_element(), "Invocation message ended before details dict"); 261 | let args = try!(visitor.next_element()); 262 | let kwargs = try!(visitor.next_element()); 263 | Ok(Message::Invocation(id, registration_id, details, args, kwargs)) 264 | } 265 | 266 | fn visit_yield<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 267 | let id = try_or!(visitor.next_element(), "Yield message ended before session id"); 268 | let options = try_or!(visitor.next_element(), "Yield message ended before options dict"); 269 | let args = try!(visitor.next_element()); 270 | let kwargs = try!(visitor.next_element()); 271 | Ok(Message::Yield(id, options, args, kwargs)) 272 | } 273 | 274 | fn visit_result<'de, V>(&self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 275 | let id = try_or!(visitor.next_element(), "Result message ended before session id"); 276 | let details = try_or!(visitor.next_element(), "Result message ended before details dict"); 277 | let args = try!(visitor.next_element()); 278 | let kwargs = try!(visitor.next_element()); 279 | Ok(Message::Result(id, details, args, kwargs)) 280 | } 281 | } 282 | 283 | impl <'de> serde::de::Visitor<'de> for MessageVisitor { 284 | type Value = Message; 285 | 286 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 287 | formatter.write_str("a message") 288 | } 289 | 290 | fn visit_seq(self, mut visitor:V) -> Result where V: serde::de::SeqAccess<'de> { 291 | let message_type:u64 = try_or!(visitor.next_element(), "No message type found"); 292 | match message_type { 293 | 1 => self.visit_hello(visitor), 294 | 2 => self.visit_welcome(visitor), 295 | 3 => self.visit_abort(visitor), 296 | 6 => self.visit_goodbye(visitor), 297 | 8 => self.visit_error(visitor), 298 | 32 => self.visit_subscribe(visitor), 299 | 33 => self.visit_subscribed(visitor), 300 | 34 => self.visit_unsubscribe(visitor), 301 | 35 => self.visit_unsubscribed(visitor), 302 | 16 => self.visit_publish(visitor), 303 | 17 => self.visit_published(visitor), 304 | 36 => self.visit_event(visitor), 305 | 64 => self.visit_register(visitor), 306 | 65 => self.visit_registered(visitor), 307 | 66 => self.visit_unregister(visitor), 308 | 67 => self.visit_unregistered(visitor), 309 | 48 => self.visit_call(visitor), 310 | 68 => self.visit_invocation(visitor), 311 | 70 => self.visit_yield(visitor), 312 | 50 => self.visit_result(visitor), 313 | _ => Err(serde::de::Error::custom("Unknown message type")) 314 | } 315 | } 316 | } 317 | 318 | #[cfg(test)] 319 | mod test { 320 | use super::{Message}; 321 | use super::types::{ 322 | URI, 323 | ClientRoles, 324 | RouterRoles, 325 | HelloDetails, 326 | WelcomeDetails, 327 | ErrorDetails, 328 | Reason, 329 | ErrorType, 330 | SubscribeOptions, 331 | PublishOptions, 332 | RegisterOptions, 333 | CallOptions, 334 | YieldOptions, 335 | Value, 336 | EventDetails, 337 | InvocationDetails, 338 | ResultDetails 339 | }; 340 | use utils::StructMapWriter; 341 | use std::collections::{HashMap}; 342 | use serde_json; 343 | use rmp_serde::Deserializer as RMPDeserializer; 344 | use rmp_serde::Serializer; 345 | use serde::{Deserialize, Serialize}; 346 | 347 | 348 | macro_rules! two_way_test { 349 | ($message: expr, $s: expr) => ( 350 | { 351 | let message = $message; 352 | assert_eq!(serde_json::to_string(&message).unwrap(), $s); 353 | assert_eq!(serde_json::from_str::($s).unwrap(), message); 354 | let mut buf: Vec = Vec::new(); 355 | message.serialize(&mut Serializer::with(&mut buf, StructMapWriter)).unwrap(); 356 | let mut de = RMPDeserializer::new(&buf[..]); 357 | let new_message: Message = Deserialize::deserialize(&mut de).unwrap(); 358 | assert_eq!(new_message, message); 359 | } 360 | ); 361 | } 362 | 363 | #[test] 364 | fn serialize_hello() { 365 | two_way_test!( 366 | Message::Hello(URI::new("ca.dal.wamp.test"), HelloDetails::new(ClientRoles::new_basic())), 367 | "[1,\"ca.dal.wamp.test\",{\"roles\":{\"publisher\":{\"features\":{}},\"subscriber\":{\"features\":{}},\"caller\":{\"features\":{}},\"callee\":{\"features\":{}}}}]" 368 | ); 369 | two_way_test!( 370 | Message::Hello(URI::new("ca.dal.wamp.test"), HelloDetails::new_with_agent(ClientRoles::new(), "dal_wamp")), 371 | "[1,\"ca.dal.wamp.test\",{\"agent\":\"dal_wamp\",\"roles\":{\"publisher\":{\"features\":{}},\"subscriber\":{\"features\":{\"pattern_based_subscription\":true}},\"caller\":{\"features\":{}},\"callee\":{\"features\":{}}}}]" 372 | ) 373 | } 374 | 375 | #[test] 376 | fn serialize_welcome() { 377 | two_way_test!( 378 | Message::Welcome(493782, WelcomeDetails::new(RouterRoles::new_basic())), 379 | "[2,493782,{\"roles\":{\"dealer\":{},\"broker\":{}}}]" 380 | ); 381 | two_way_test!( 382 | Message::Welcome(493782, WelcomeDetails::new_with_agent(RouterRoles::new(), "dal_wamp")), 383 | "[2,493782,{\"agent\":\"dal_wamp\",\"roles\":{\"dealer\":{\"features\":{\"pattern_based_registration\":true}},\"broker\":{\"features\":{\"pattern_based_subscription\":true}}}}]" 384 | ); 385 | } 386 | 387 | 388 | #[test] 389 | fn serialize_abort() { 390 | two_way_test!( 391 | Message::Abort(ErrorDetails::new(), Reason::NoSuchRealm), 392 | "[3,{},\"wamp.error.no_such_realm\"]" 393 | ); 394 | two_way_test!( 395 | Message::Abort(ErrorDetails::new_with_message("The realm does not exist"), Reason::NoSuchRealm), 396 | "[3,{\"message\":\"The realm does not exist\"},\"wamp.error.no_such_realm\"]" 397 | ); 398 | } 399 | 400 | #[test] 401 | fn serialize_goodbye() { 402 | two_way_test!( 403 | Message::Goodbye(ErrorDetails::new(), Reason::GoodbyeAndOut), 404 | "[6,{},\"wamp.error.goodbye_and_out\"]" 405 | ); 406 | two_way_test!( 407 | Message::Goodbye(ErrorDetails::new_with_message("The host is shutting down now"), Reason::SystemShutdown), 408 | "[6,{\"message\":\"The host is shutting down now\"},\"wamp.error.system_shutdown\"]" 409 | ); 410 | } 411 | 412 | 413 | #[test] 414 | fn serialize_error() { 415 | two_way_test!( 416 | Message::Error(ErrorType::Subscribe, 713845233, HashMap::new(), Reason::NotAuthorized, None, None), 417 | "[8,32,713845233,{},\"wamp.error.not_authorized\"]" 418 | ); 419 | 420 | two_way_test!( 421 | Message::Error(ErrorType::Unsubscribe, 3746383, HashMap::new(), Reason::InvalidURI, Some(Vec::new()), None), 422 | "[8,34,3746383,{},\"wamp.error.invalid_uri\",[]]" 423 | ); 424 | 425 | two_way_test!( 426 | Message::Error(ErrorType::Register, 8534533, HashMap::new(), Reason::InvalidArgument, Some(Vec::new()), Some(HashMap::new())), 427 | "[8,64,8534533,{},\"wamp.error.invalid_argument\",[],{}]" 428 | ); 429 | } 430 | 431 | #[test] 432 | fn serialize_subscribe() { 433 | two_way_test!( 434 | Message::Subscribe(58944, SubscribeOptions::new(), URI::new("ca.dal.test.the_sub")), 435 | "[32,58944,{},\"ca.dal.test.the_sub\"]" 436 | ) 437 | } 438 | 439 | #[test] 440 | fn serialize_subscribed() { 441 | two_way_test!( 442 | Message::Subscribed(47853, 48975938), 443 | "[33,47853,48975938]" 444 | ) 445 | } 446 | 447 | #[test] 448 | fn serialize_unsubscribe() { 449 | two_way_test!( 450 | Message::Unsubscribe(754, 8763), 451 | "[34,754,8763]" 452 | ) 453 | } 454 | 455 | #[test] 456 | fn serialize_unsubscribed() { 457 | two_way_test!( 458 | Message::Unsubscribed(675343), 459 | "[35,675343]" 460 | ) 461 | } 462 | 463 | #[test] 464 | fn serialize_publish() { 465 | two_way_test!( 466 | Message::Publish(453453, PublishOptions::new(false), URI::new("ca.dal.test.topic1"), None, None), 467 | "[16,453453,{},\"ca.dal.test.topic1\"]" 468 | ); 469 | 470 | two_way_test!( 471 | Message::Publish(23934583, PublishOptions::new(true), URI::new("ca.dal.test.topic2"), Some(vec![Value::String("a value".to_string())]), None), 472 | "[16,23934583,{\"acknowledge\":true},\"ca.dal.test.topic2\",[\"a value\"]]" 473 | ); 474 | let mut kwargs = HashMap::new(); 475 | kwargs.insert("key1".to_string(), Value::List(vec![Value::Integer(5)])); 476 | two_way_test!( 477 | Message::Publish(3243542, PublishOptions::new(true), URI::new("ca.dal.test.topic3"), Some(Vec::new()), Some(kwargs)), 478 | "[16,3243542,{\"acknowledge\":true},\"ca.dal.test.topic3\",[],{\"key1\":[5]}]" 479 | ) 480 | } 481 | 482 | #[test] 483 | fn serialize_published() { 484 | two_way_test!( 485 | Message::Published(23443, 564564), 486 | "[17,23443,564564]" 487 | ) 488 | } 489 | 490 | #[test] 491 | fn serialize_event() { 492 | two_way_test!( 493 | Message::Event(4353453, 298173, EventDetails::new(), None, None), 494 | "[36,4353453,298173,{}]" 495 | ); 496 | 497 | two_way_test!( 498 | Message::Event(764346, 3895494, EventDetails::new(), Some(vec![Value::String("a value".to_string())]), None), 499 | "[36,764346,3895494,{},[\"a value\"]]" 500 | ); 501 | let mut kwargs = HashMap::new(); 502 | kwargs.insert("key1".to_string(), Value::List(vec![Value::Integer(5)])); 503 | two_way_test!( 504 | Message::Event(65675, 587495, EventDetails::new(), Some(Vec::new()), Some(kwargs)), 505 | "[36,65675,587495,{},[],{\"key1\":[5]}]" 506 | ) 507 | } 508 | 509 | #[test] 510 | fn serialize_register() { 511 | two_way_test!( 512 | Message::Register(25349185, RegisterOptions::new(), URI::new("ca.test.proc")), 513 | "[64,25349185,{},\"ca.test.proc\"]" 514 | ); 515 | } 516 | 517 | #[test] 518 | fn serialize_registered() { 519 | two_way_test!( 520 | Message::Registered(25349185, 2103333224), 521 | "[65,25349185,2103333224]" 522 | ); 523 | } 524 | 525 | #[test] 526 | fn serialize_unregister() { 527 | two_way_test!( 528 | Message::Unregister(788923562, 2103333224), 529 | "[66,788923562,2103333224]" 530 | ); 531 | } 532 | 533 | #[test] 534 | fn serialize_unregistered() { 535 | two_way_test!( 536 | Message::Unregistered(788923562), 537 | "[67,788923562]" 538 | ); 539 | } 540 | 541 | #[test] 542 | fn serialize_call() { 543 | two_way_test!( 544 | Message::Call(7814135, CallOptions::new(), URI::new("com.myapp.ping"), None, None), 545 | "[48,7814135,{},\"com.myapp.ping\"]" 546 | ); 547 | 548 | two_way_test!( 549 | Message::Call(764346, CallOptions::new(), URI::new("com.myapp.echo"), Some(vec![Value::String("a value".to_string())]), None), 550 | "[48,764346,{},\"com.myapp.echo\",[\"a value\"]]" 551 | ); 552 | let mut kwargs = HashMap::new(); 553 | kwargs.insert("key1".to_string(), Value::List(vec![Value::Integer(5)])); 554 | two_way_test!( 555 | Message::Call(764346, CallOptions::new(), URI::new("com.myapp.compute"), Some(Vec::new()), Some(kwargs)), 556 | "[48,764346,{},\"com.myapp.compute\",[],{\"key1\":[5]}]" 557 | ) 558 | } 559 | 560 | #[test] 561 | fn serialize_invocation() { 562 | two_way_test!( 563 | Message::Invocation(7814135, 9823526, InvocationDetails::new(), None, None), 564 | "[68,7814135,9823526,{}]" 565 | ); 566 | 567 | two_way_test!( 568 | Message::Invocation(764346, 9823526, InvocationDetails::new(), Some(vec![Value::String("a value".to_string())]), None), 569 | "[68,764346,9823526,{},[\"a value\"]]" 570 | ); 571 | let mut kwargs = HashMap::new(); 572 | kwargs.insert("key1".to_string(), Value::List(vec![Value::Integer(5)])); 573 | two_way_test!( 574 | Message::Invocation(764346, 9823526, InvocationDetails::new(), Some(Vec::new()), Some(kwargs)), 575 | "[68,764346,9823526,{},[],{\"key1\":[5]}]" 576 | ) 577 | } 578 | 579 | #[test] 580 | fn serialize_yield() { 581 | two_way_test!( 582 | Message::Yield(6131533, YieldOptions::new(), None, None), 583 | "[70,6131533,{}]" 584 | ); 585 | 586 | two_way_test!( 587 | Message::Yield(6131533, YieldOptions::new(), Some(vec![Value::String("a value".to_string())]), None), 588 | "[70,6131533,{},[\"a value\"]]" 589 | ); 590 | let mut kwargs = HashMap::new(); 591 | kwargs.insert("key1".to_string(), Value::List(vec![Value::Integer(5)])); 592 | two_way_test!( 593 | Message::Yield(6131533, YieldOptions::new(), Some(Vec::new()), Some(kwargs)), 594 | "[70,6131533,{},[],{\"key1\":[5]}]" 595 | ) 596 | } 597 | 598 | #[test] 599 | fn serialize_result() { 600 | two_way_test!( 601 | Message::Result(7814135, ResultDetails::new(), None, None), 602 | "[50,7814135,{}]" 603 | ); 604 | 605 | two_way_test!( 606 | Message::Result(764346, ResultDetails::new(), Some(vec![Value::String("a value".to_string())]), None), 607 | "[50,764346,{},[\"a value\"]]" 608 | ); 609 | let mut kwargs = HashMap::new(); 610 | kwargs.insert("key1".to_string(), Value::List(vec![Value::Integer(5)])); 611 | two_way_test!( 612 | Message::Result(764346, ResultDetails::new(), Some(Vec::new()), Some(kwargs)), 613 | "[50,764346,{},[],{\"key1\":[5]}]" 614 | ) 615 | } 616 | 617 | } 618 | -------------------------------------------------------------------------------- /src/client.rs: -------------------------------------------------------------------------------- 1 | use ws::{ 2 | connect, 3 | Sender, 4 | CloseCode, 5 | Handler, 6 | Message as WSMessage, 7 | Handshake, 8 | Frame, 9 | Result as WSResult, 10 | Error as WSError, 11 | ErrorKind as WSErrorKind, 12 | Request, 13 | }; 14 | 15 | use ws::util::{Token, Timeout}; 16 | 17 | use messages::{URI, Dict, List, WelcomeDetails, SubscribeOptions, PublishOptions, CallOptions, InvocationDetails, YieldOptions, ResultDetails, RegisterOptions, Message, HelloDetails, Reason, ErrorDetails, ClientRoles, MatchingPolicy, ErrorType}; 18 | use std::collections::HashMap; 19 | use serde_json; 20 | use serde::{Deserialize, Serialize}; 21 | use std::fmt; 22 | use std::time::Duration; 23 | use ::{WampResult, Error, ErrorKind, ID, CallResult, CallError}; 24 | use std::thread; 25 | use std::sync::{Mutex, Arc, MutexGuard}; 26 | use rmp_serde::Deserializer as RMPDeserializer; 27 | use rmp_serde::Serializer; 28 | use utils::StructMapWriter; 29 | use std::io::Cursor; 30 | use eventual::{Complete, Future}; 31 | use url::Url; 32 | use std::sync::mpsc::{channel, Sender as CHSender}; 33 | 34 | macro_rules! try_websocket { 35 | ($e: expr) => ( 36 | match $e { 37 | Ok(result) => result, 38 | Err(e) => return Err(Error::new(ErrorKind::WSError(e))) 39 | } 40 | ); 41 | } 42 | 43 | const CONNECTION_TIMEOUT:Token = Token(124); 44 | const EXPIRE_TIMEOUT: Token = Token(125); 45 | 46 | pub struct Connection { 47 | realm: URI, 48 | url: String, 49 | timeout: u64, 50 | } 51 | 52 | pub struct Subscription { 53 | pub topic: URI, 54 | subscription_id: ID 55 | } 56 | 57 | pub struct Registration { 58 | pub procedure: URI, 59 | registration_id: ID 60 | } 61 | 62 | struct SubscriptionCallbackWrapper { 63 | callback: Box 64 | } 65 | 66 | struct RegistrationCallbackWrapper { 67 | callback: Box CallResult<(Option, Option)>> 68 | } 69 | 70 | static WAMP_JSON:&'static str = "wamp.2.json"; 71 | static WAMP_MSGPACK:&'static str = "wamp.2.msgpack"; 72 | 73 | #[derive(PartialEq, Debug)] 74 | enum ConnectionState { 75 | Connecting, 76 | Connected, 77 | ShuttingDown, 78 | Disconnected 79 | } 80 | 81 | type ConnectionResult = Result>, Error>; 82 | 83 | unsafe impl <'a> Send for ConnectionInfo {} 84 | 85 | unsafe impl<'a> Sync for ConnectionInfo {} 86 | 87 | unsafe impl <'a> Send for SubscriptionCallbackWrapper {} 88 | 89 | unsafe impl<'a> Sync for SubscriptionCallbackWrapper {} 90 | 91 | unsafe impl <'a> Send for RegistrationCallbackWrapper {} 92 | 93 | unsafe impl<'a> Sync for RegistrationCallbackWrapper {} 94 | 95 | pub struct Client { 96 | connection_info: Arc>, 97 | max_session_id: ID, 98 | } 99 | 100 | pub struct ConnectionHandler { 101 | connection_info: Arc>, 102 | realm: URI, 103 | state_transmission: CHSender, 104 | timeout: Option, 105 | } 106 | 107 | struct ConnectionInfo { 108 | connection_state: ConnectionState, 109 | sender: Sender, 110 | subscription_requests: HashMap, SubscriptionCallbackWrapper, URI)>, 111 | unsubscription_requests: HashMap, ID)>, 112 | subscriptions: HashMap, 113 | registrations: HashMap, 114 | call_requests: HashMap>, 115 | registration_requests: HashMap, RegistrationCallbackWrapper, URI)>, 116 | unregistration_requests: HashMap, ID)>, 117 | protocol: String, 118 | publish_requests: HashMap>, 119 | shutdown_complete: Option>, 120 | session_id: ID 121 | } 122 | 123 | trait MessageSender { 124 | fn send_message(&self, message: Message) -> WampResult<()>; 125 | } 126 | 127 | impl MessageSender for ConnectionInfo { 128 | fn send_message(&self, message: Message) -> WampResult<()> { 129 | 130 | debug!("Sending message {:?} via {}", message, self.protocol); 131 | let send_result = if self.protocol == WAMP_JSON { 132 | send_message_json(&self.sender, &message) 133 | } else { 134 | send_message_msgpack(&self.sender, &message) 135 | }; 136 | match send_result { 137 | Ok(()) => Ok(()), 138 | Err(e) => Err(Error::new(ErrorKind::WSError(e))) 139 | } 140 | } 141 | } 142 | 143 | 144 | 145 | fn send_message_json(sender: &Sender, message: &Message) -> WSResult<()> { 146 | // Send the message 147 | sender.send(WSMessage::Text(serde_json::to_string(message).unwrap())) 148 | 149 | } 150 | 151 | fn send_message_msgpack(sender: &Sender, message: &Message) -> WSResult<()> { 152 | 153 | // Send the message 154 | let mut buf: Vec = Vec::new(); 155 | message.serialize(&mut Serializer::with(&mut buf, StructMapWriter)).unwrap(); 156 | sender.send(WSMessage::Binary(buf)) 157 | 158 | } 159 | 160 | impl Connection { 161 | pub fn new(url: &str, realm: &str) -> Connection { 162 | Connection { 163 | realm: URI::new(realm), 164 | url: url.to_string(), 165 | timeout: 5000, 166 | } 167 | } 168 | 169 | pub fn connect<'a>(&self) -> WampResult { 170 | let (tx, rx) = channel(); 171 | 172 | let url = self.url.clone(); 173 | let timeout = self.timeout; 174 | let realm = self.realm.clone(); 175 | 176 | thread::spawn(move || { 177 | trace!("Beginning Connection"); 178 | 179 | let connect_result = connect(url, |out| { 180 | trace!("Got sender"); 181 | // Set up timeout 182 | out.timeout(timeout, CONNECTION_TIMEOUT).unwrap(); 183 | 184 | let info = Arc::new(Mutex::new(ConnectionInfo { 185 | protocol: String::new(), 186 | subscription_requests: HashMap::new(), 187 | unsubscription_requests: HashMap::new(), 188 | subscriptions: HashMap::new(), 189 | registrations: HashMap::new(), 190 | call_requests: HashMap::new(), 191 | registration_requests: HashMap::new(), 192 | unregistration_requests: HashMap::new(), 193 | sender: out, 194 | connection_state: ConnectionState::Connecting, 195 | publish_requests: HashMap::new(), 196 | shutdown_complete: None, 197 | session_id: 0 198 | })); 199 | 200 | let handler = ConnectionHandler { 201 | state_transmission: tx.clone(), 202 | connection_info: info, 203 | realm: realm.clone(), 204 | timeout: None, 205 | }; 206 | 207 | handler 208 | }).map_err(|e| { 209 | Error::new(ErrorKind::WSError(e)) 210 | }); 211 | 212 | debug!("Result of connection: {:?}", connect_result); 213 | 214 | match connect_result { 215 | Ok(_) => (), 216 | Err(e) => {tx.send(Err(e)).unwrap();} 217 | } 218 | }); 219 | 220 | // let info = try!(rx.recv().unwrap()); 221 | 222 | match rx.recv() { 223 | Ok(data) => { 224 | let info = try!(data); 225 | Ok(Client{ 226 | connection_info: info, 227 | max_session_id: 0, 228 | }) 229 | }, 230 | Err(_) => Err(Error::new(ErrorKind::Timeout)), 231 | } 232 | } 233 | 234 | pub fn set_timeout(&mut self, timeout: u64) { 235 | self.timeout = timeout; 236 | } 237 | } 238 | 239 | macro_rules! cancel_future_tuple { 240 | ($dict: expr) => ({ 241 | for (_, future) in $dict.drain() { 242 | future.0.fail(CallError::new(Reason::NetworkFailure, None, None)); 243 | } 244 | }); 245 | } 246 | 247 | macro_rules! cancel_future { 248 | ($dict: expr) => ({ 249 | for (_, future) in $dict.drain() { 250 | future.fail(CallError::new(Reason::NetworkFailure, None, None)); 251 | } 252 | }); 253 | } 254 | 255 | impl Handler for ConnectionHandler { 256 | fn on_open(&mut self, handshake: Handshake) -> WSResult<()> { 257 | debug!("Connection Opened"); 258 | 259 | let mut info = self.connection_info.lock().unwrap(); 260 | 261 | info.protocol = match try!(handshake.response.protocol()) { 262 | Some(protocol) => { 263 | protocol.to_string() 264 | } None => { 265 | warn!("Router did not specify protocol. Defaulting to wamp.2.json"); 266 | WAMP_JSON.to_string() 267 | } 268 | }; 269 | 270 | let hello_message = Message::Hello(self.realm.clone(), HelloDetails::new(ClientRoles::new())); 271 | 272 | debug!("Sending Hello message"); 273 | 274 | thread::sleep(Duration::from_millis(200)); 275 | 276 | match info.send_message(hello_message) { 277 | Ok(_) => Ok(()), 278 | Err(e) => { 279 | if let ErrorKind::WSError(e) = e.kind { 280 | Err(e) 281 | } else { 282 | Err(WSError::new(WSErrorKind::Internal, "Unknown error")) 283 | } 284 | } 285 | } 286 | } 287 | 288 | fn on_message(&mut self, message: WSMessage) -> WSResult<()> { 289 | debug!("Server sent a message: {:?}", message); 290 | 291 | match message { 292 | WSMessage::Text(message) => { 293 | match serde_json::from_str(&message) { 294 | Ok(message) => { 295 | if !self.handle_message(message) { 296 | // TODO FIXME 297 | return Ok(()); 298 | } 299 | } Err(_) => { 300 | error!("Received unknown message: {}", message); 301 | return Ok(()); 302 | } 303 | } 304 | }, 305 | WSMessage::Binary(message) => { 306 | let mut de = RMPDeserializer::new(Cursor::new(&*message)); 307 | match Deserialize::deserialize(&mut de) { 308 | Ok(message) => { 309 | if !self.handle_message(message) { 310 | return Ok(()); 311 | } 312 | }, 313 | Err(_) => { 314 | error!("Could not understand MsgPack message"); 315 | } 316 | } 317 | } 318 | } 319 | Ok(()) 320 | } 321 | 322 | 323 | 324 | fn on_close(&mut self, _code: CloseCode, _reason: &str) { 325 | debug!("Closing connection"); 326 | 327 | let mut info = self.connection_info.lock().unwrap(); 328 | 329 | info.sender.close(CloseCode::Normal).ok(); 330 | info.connection_state = ConnectionState::Disconnected; 331 | 332 | cancel_future_tuple!(info.subscription_requests); 333 | cancel_future_tuple!(info.unsubscription_requests); 334 | cancel_future_tuple!(info.registration_requests); 335 | cancel_future_tuple!(info.unregistration_requests); 336 | 337 | cancel_future!(info.publish_requests); 338 | cancel_future!(info.call_requests); 339 | 340 | info.sender.shutdown().ok(); 341 | 342 | match info.shutdown_complete.take() { 343 | Some(promise) => { 344 | promise.complete(()); 345 | }, 346 | None => {} 347 | } 348 | } 349 | 350 | fn on_timeout(&mut self, token: Token) -> WSResult<()> { 351 | if token == CONNECTION_TIMEOUT { 352 | let info = self.connection_info.lock().unwrap(); 353 | if info.connection_state == ConnectionState::Connecting { 354 | info.sender.shutdown()?; 355 | drop(info); 356 | self.state_transmission.send(Err(Error::new(ErrorKind::Timeout))).unwrap(); 357 | } 358 | } 359 | 360 | if token == EXPIRE_TIMEOUT { 361 | debug!("connection lost!"); 362 | let mut info = self.connection_info.lock().unwrap(); 363 | info.connection_state = ConnectionState::Disconnected; 364 | info.sender.close(CloseCode::Away)?; 365 | } 366 | 367 | Ok(()) 368 | } 369 | 370 | fn on_new_timeout(&mut self, token: Token, timeout: Timeout) -> WSResult<()> { 371 | if token == EXPIRE_TIMEOUT { 372 | if let Some(last_timeout) = self.timeout.take() { 373 | let info = self.connection_info.lock().unwrap(); 374 | info.sender.cancel(last_timeout)?; 375 | } 376 | self.timeout = Some(timeout); 377 | } 378 | 379 | Ok(()) 380 | } 381 | 382 | // TODO: custom timeout 383 | fn on_frame(&mut self, frame: Frame) -> WSResult> { 384 | let info = self.connection_info.lock().unwrap(); 385 | 386 | if info.connection_state == ConnectionState::Connected { 387 | info.sender.timeout(30000, EXPIRE_TIMEOUT)?; 388 | } 389 | 390 | Ok(Some(frame)) 391 | } 392 | 393 | fn on_error(&mut self, err: WSError) { 394 | debug!("WS error: {:#?}", err); 395 | } 396 | 397 | fn build_request(&mut self, url: &Url) -> WSResult { 398 | trace!("Building request"); 399 | let mut request = try!(Request::from_url(url)); 400 | request.add_protocol(WAMP_MSGPACK); 401 | request.add_protocol(WAMP_JSON); 402 | Ok(request) 403 | } 404 | 405 | } 406 | 407 | 408 | impl ConnectionHandler { 409 | fn handle_message(&mut self, message: Message) -> bool { 410 | let mut info = self.connection_info.lock().unwrap(); 411 | 412 | debug!("Processing message from server (state: {:?})", info.connection_state); 413 | 414 | match info.connection_state { 415 | ConnectionState::Connecting => { 416 | if let Message::Welcome(session_id, details) = message { 417 | self.handle_welcome(info, session_id, details) 418 | } else { 419 | return false; 420 | } 421 | }, ConnectionState:: Connected => { 422 | debug!("Recieved a message from the server: {:?}", message); 423 | match message { 424 | Message::Subscribed(request_id, subscription_id) => { 425 | self.handle_subscribed(info, request_id, subscription_id) 426 | }, 427 | Message::Unsubscribed(request_id) => { 428 | self.handle_unsubscribed(info, request_id) 429 | }, 430 | Message::Event(subscription_id, _, _, args, kwargs) => { 431 | self.handle_event(info, subscription_id, args, kwargs) 432 | }, 433 | Message::Published(request_id, publication_id) => { 434 | self.handle_published(info, request_id, publication_id) 435 | }, 436 | Message::Registered(request_id, registration_id) => { 437 | self.handle_registered(info, request_id, registration_id) 438 | }, 439 | Message::Unregistered(request_id) => { 440 | self.handle_unregistered(info, request_id) 441 | }, 442 | Message::Invocation(request_id, registration_id, details, args, kwargs) => { 443 | self.handle_invocation(info, request_id, registration_id, details, args, kwargs) 444 | }, 445 | Message::Result(call_id, details, args, kwargs) => { 446 | self.handle_result(info, call_id, details, args, kwargs) 447 | }, 448 | Message::Error(e_type, request_id, details, reason, args, kwargs) => { 449 | self.handle_error(info, e_type, request_id, details, reason, args, kwargs) 450 | } 451 | Message::Goodbye(_, reason) => { 452 | self.handle_goodbye(info, reason); 453 | return false; 454 | } 455 | _ => { 456 | warn!("Recieved unknown message. Ignoring. {:?}", message) 457 | } 458 | } 459 | }, ConnectionState::ShuttingDown => { 460 | if let Message::Goodbye(_, _) = message { 461 | // The router has seen our goodbye message and has responded in kind 462 | info!("Router acknolwedged disconnect"); 463 | 464 | match info.shutdown_complete.take() { 465 | Some(promise) => promise.complete(()), 466 | None => {} 467 | } 468 | return false; 469 | } else { 470 | warn!("Recieved message after shutting down, ignoring: {:?}", message); 471 | return false; 472 | } 473 | }, ConnectionState::Disconnected => { 474 | // Should never happen 475 | return false; 476 | } 477 | } 478 | true 479 | } 480 | 481 | fn handle_subscribed(&self, mut info: MutexGuard, request_id: ID, subscription_id: ID) { 482 | // TODO handle errors here 483 | info!("Recieved a subscribed notification"); 484 | match info.subscription_requests.remove(&request_id) { 485 | Some((promise, callback, topic)) => { 486 | debug!("Completing promise"); 487 | let subscription = Subscription{topic: topic, subscription_id: subscription_id}; 488 | info.subscriptions.insert(subscription_id, callback); 489 | drop(info); 490 | promise.complete(subscription) 491 | }, 492 | None => { 493 | warn!("Recieved a subscribed notification for a subscription we don't have. ID: {}", request_id); 494 | } 495 | } 496 | } 497 | 498 | fn handle_subscribe_error(&self, mut info: MutexGuard, request_id: ID, reason: Reason, args: Option, kwargs: Option) { 499 | warn!("Recieved an error for a subscription"); 500 | match info.subscription_requests.remove(&request_id) { 501 | Some((promise, _, _)) => { 502 | drop(info); 503 | promise.fail(CallError::new(reason, args, kwargs)); 504 | }, 505 | None => { 506 | warn!("Recieved a an error notification for a request we didn't make. ID: {}", request_id); 507 | } 508 | } 509 | } 510 | 511 | fn handle_unsubscribed(&self, mut info: MutexGuard, request_id: ID) { 512 | match info.unsubscription_requests.remove(&request_id) { 513 | Some((promise, subscription_id)) => { 514 | info.unsubscription_requests.remove(&subscription_id); 515 | drop(info); 516 | promise.complete(()) 517 | }, 518 | None => { 519 | warn!("Recieved a unsubscribed notification for a subscription we don't have. ID: {}", request_id); 520 | } 521 | } 522 | } 523 | 524 | fn handle_unsubscribe_error(&self, mut info: MutexGuard, request_id: ID, reason: Reason, args: Option, kwargs: Option) { 525 | match info.unsubscription_requests.remove(&request_id) { 526 | Some((promise, subscription_id)) => { 527 | info.unsubscription_requests.remove(&subscription_id); 528 | drop(info); 529 | promise.fail(CallError::new(reason, args, kwargs)) 530 | }, 531 | None => { 532 | warn!("Recieved a unsubscribed error for a subscription we don't have. ID: {}", request_id); 533 | } 534 | } 535 | } 536 | 537 | fn handle_registered(&self, mut info: MutexGuard, request_id: ID, registration_id: ID) { 538 | // TODO handle errors here 539 | info!("Recieved a registered notification"); 540 | match info.registration_requests.remove(&request_id) { 541 | Some((promise, callback, procedure)) => { 542 | info.registrations.insert(registration_id, callback); 543 | drop(info); 544 | let registration = Registration{procedure: procedure, registration_id: registration_id}; 545 | promise.complete(registration) 546 | }, 547 | None => { 548 | warn!("Recieved a registered notification for a registration we don't have. ID: {}", request_id); 549 | } 550 | } 551 | } 552 | 553 | fn handle_register_error(&self, mut info: MutexGuard, request_id: ID, reason: Reason, args: Option, kwargs: Option) { 554 | info!("Recieved a registration error"); 555 | match info.registration_requests.remove(&request_id) { 556 | Some((promise, _, _)) => { 557 | drop(info); 558 | promise.fail(CallError::new(reason, args, kwargs)) 559 | }, 560 | None => { 561 | warn!("Recieved a registered error for a registration we don't have. ID: {}", request_id); 562 | } 563 | } 564 | } 565 | 566 | fn handle_unregistered(&self, mut info: MutexGuard, request_id: ID) { 567 | match info.unregistration_requests.remove(&request_id) { 568 | Some((promise, registration_id)) => { 569 | info.registrations.remove(®istration_id); 570 | drop(info); 571 | promise.complete(()) 572 | }, 573 | None => { 574 | warn!("Recieved a unregistered notification for a registration we don't have. ID: {}", request_id); 575 | } 576 | } 577 | } 578 | 579 | fn handle_unregister_error(&self, mut info: MutexGuard, request_id: ID, reason: Reason, args: Option, kwargs: Option) { 580 | match info.unregistration_requests.remove(&request_id) { 581 | Some((promise, _)) => { 582 | drop(info); 583 | promise.fail(CallError::new(reason, args, kwargs)) 584 | }, 585 | None => { 586 | warn!("Recieved a unregistered error for a registration we don't have. ID: {}", request_id); 587 | } 588 | } 589 | } 590 | 591 | fn handle_published(&self, mut info: MutexGuard, request_id: ID, publication_id: ID) { 592 | match info.publish_requests.remove(&request_id) { 593 | Some(promise) => { 594 | promise.complete(publication_id); 595 | }, 596 | None => { 597 | warn!("Recieved published notification for a request we weren't tracking: {}", request_id) 598 | } 599 | } 600 | } 601 | fn handle_publish_error(&self, mut info: MutexGuard, request_id: ID, reason: Reason, args: Option, kwargs: Option) { 602 | match info.publish_requests.remove(&request_id) { 603 | Some(promise) => { 604 | promise.fail(CallError::new(reason, args, kwargs)) 605 | }, 606 | None => { 607 | warn!("Recieved published error for a publication: {}", request_id) 608 | } 609 | } 610 | } 611 | 612 | fn handle_welcome(&self, mut info: MutexGuard, session_id: ID, _details: WelcomeDetails) { 613 | // todo cancel timeout 614 | info.session_id = session_id; 615 | info.connection_state = ConnectionState::Connected; 616 | drop(info); 617 | self.state_transmission.send(Ok(self.connection_info.clone())).unwrap(); 618 | } 619 | 620 | fn handle_event(&self, mut info: MutexGuard, subscription_id: ID, args: Option, kwargs: Option) { 621 | let args = args.unwrap_or(Vec::new()); 622 | let kwargs = kwargs.unwrap_or(HashMap::new()); 623 | match info.subscriptions.get_mut(&subscription_id) { 624 | Some(subscription) => { 625 | let ref mut callback = subscription.callback; 626 | callback(args, kwargs); 627 | }, 628 | None => { 629 | warn!("Recieved an event for a subscription we don't have. ID: {}", subscription_id); 630 | } 631 | } 632 | } 633 | 634 | fn handle_invocation(&self, mut info: MutexGuard, request_id: ID, registration_id: ID, _details: InvocationDetails, args: Option, kwargs: Option) { 635 | let args = args.unwrap_or(Vec::new()); 636 | let kwargs = kwargs.unwrap_or(HashMap::new()); 637 | let message = match info.registrations.get_mut(®istration_id) { 638 | Some(registration) => { 639 | let ref mut callback = registration.callback; 640 | match callback(args, kwargs) { 641 | Ok((rargs, rkwargs)) => { 642 | Message::Yield(request_id, YieldOptions::new(), rargs, rkwargs) 643 | }, Err(error) => { 644 | let (reason, args, kwargs) = error.to_tuple(); 645 | Message::Error(ErrorType::Invocation, request_id, HashMap::new(), reason, args, kwargs) 646 | } 647 | } 648 | }, 649 | None => { 650 | warn!("Recieved an invocation for a procedure we don't have. ID: {}", registration_id); 651 | return; 652 | } 653 | }; 654 | info.send_message(message).ok(); 655 | } 656 | 657 | fn handle_result(&self, mut info: MutexGuard, call_id: ID, _details: ResultDetails, args: Option, kwargs: Option) { 658 | let args = args.unwrap_or(Vec::new()); 659 | let kwargs = kwargs.unwrap_or(HashMap::new()); 660 | match info.call_requests.remove(&call_id) { 661 | Some(promise) => { 662 | promise.complete((args, kwargs)); 663 | }, 664 | None => { 665 | warn!("Recieved a result for a call we didn't make. ID: {}", call_id); 666 | } 667 | } 668 | } 669 | 670 | fn handle_call_error(&self, mut info: MutexGuard, request_id: ID, reason: Reason, args: Option, kwargs: Option) { 671 | match info.call_requests.remove(&request_id) { 672 | Some(promise) => { 673 | promise.fail(CallError::new(reason, args, kwargs)) 674 | }, 675 | None => { 676 | warn!("Recieved an error for a call we didn't make. ID: {}", request_id); 677 | } 678 | } 679 | } 680 | 681 | fn handle_goodbye(&self, mut info: MutexGuard, reason: Reason) { 682 | info!("Router said goodbye. Reason: {:?}", reason); 683 | 684 | info.send_message(Message::Goodbye(ErrorDetails::new(), Reason::GoodbyeAndOut)).unwrap(); 685 | info.connection_state = ConnectionState::ShuttingDown; 686 | 687 | } 688 | 689 | fn handle_error(&self, info: MutexGuard, e_type: ErrorType, request_id: ID, _details: Dict, reason: Reason, args: Option, kwargs: Option) { 690 | match e_type { 691 | ErrorType::Subscribe => { 692 | self.handle_subscribe_error(info, request_id, reason, args, kwargs) 693 | }, 694 | ErrorType::Unsubscribe => { 695 | self.handle_unsubscribe_error(info, request_id, reason, args, kwargs) 696 | }, 697 | ErrorType::Publish => { 698 | self.handle_publish_error(info, request_id, reason, args, kwargs) 699 | }, 700 | ErrorType::Register => { 701 | self.handle_register_error(info, request_id, reason, args, kwargs) 702 | }, 703 | ErrorType::Unregister => { 704 | self.handle_unregister_error(info, request_id, reason, args, kwargs) 705 | }, 706 | ErrorType::Invocation => { 707 | warn!("Recieved an error for an invocation message, which we did not (and could not) send") 708 | }, 709 | ErrorType::Call => { 710 | self.handle_call_error(info, request_id, reason, args, kwargs) 711 | } 712 | } 713 | } 714 | 715 | } 716 | 717 | impl Client { 718 | fn get_next_session_id(&mut self) -> ID { 719 | self.max_session_id += 1; 720 | self.max_session_id 721 | } 722 | 723 | pub fn subscribe_with_pattern(&mut self, topic_pattern: URI, callback: Box, policy: MatchingPolicy) -> WampResult> { 724 | // Send a subscribe messages 725 | let request_id = self.get_next_session_id(); 726 | let (complete, future) = Future::::pair(); 727 | let callback = SubscriptionCallbackWrapper {callback: callback}; 728 | let mut options = SubscribeOptions::new(); 729 | 730 | if policy != MatchingPolicy::Strict { 731 | options.pattern_match = policy 732 | } 733 | 734 | let mut info = self.connection_info.lock().unwrap(); 735 | info.subscription_requests.insert(request_id, (complete, callback, topic_pattern.clone())); 736 | try!(info.send_message(Message::Subscribe(request_id, options, topic_pattern))); 737 | Ok(future) 738 | } 739 | 740 | pub fn subscribe(&mut self, topic: URI, callback: Box) -> WampResult> { 741 | self.subscribe_with_pattern(topic, callback, MatchingPolicy::Strict) 742 | } 743 | 744 | pub fn register_with_pattern(&mut self, procedure_pattern: URI, callback: Box CallResult<(Option, Option)> >, policy: MatchingPolicy) -> WampResult> { 745 | // Send a register messages 746 | let request_id = self.get_next_session_id(); 747 | let (complete, future) = Future::::pair(); 748 | let callback = RegistrationCallbackWrapper {callback: callback}; 749 | let mut options = RegisterOptions::new(); 750 | if policy != MatchingPolicy::Strict { 751 | options.pattern_match = policy 752 | } 753 | debug!("Acquiring lock on connection info"); 754 | let mut info = self.connection_info.lock().unwrap(); 755 | debug!("Lock on connection info acquired"); 756 | info.registration_requests.insert(request_id, (complete, callback, procedure_pattern.clone())); 757 | try!(info.send_message(Message::Register(request_id, options, procedure_pattern))); 758 | Ok(future) 759 | } 760 | 761 | pub fn register(&mut self, procedure: URI, callback: Box CallResult<(Option, Option)> >) -> WampResult> { 762 | self.register_with_pattern(procedure, callback, MatchingPolicy::Strict) 763 | } 764 | 765 | pub fn unsubscribe(&mut self, subscription: Subscription) -> WampResult> { 766 | let request_id = self.get_next_session_id(); 767 | let mut info = self.connection_info.lock().unwrap(); 768 | try!(info.send_message(Message::Unsubscribe(request_id, subscription.subscription_id))); 769 | let (complete, future) = Future::<(), CallError>::pair(); 770 | info.unsubscription_requests.insert(request_id, (complete, subscription.subscription_id)); 771 | Ok(future) 772 | } 773 | 774 | pub fn unregister(&mut self, registration: Registration) -> WampResult> { 775 | let request_id = self.get_next_session_id(); 776 | let mut info = self.connection_info.lock().unwrap(); 777 | try!(info.send_message(Message::Unregister(request_id, registration.registration_id))); 778 | let (complete, future) = Future::<(), CallError>::pair(); 779 | 780 | info.unregistration_requests.insert(request_id, (complete, registration.registration_id)); 781 | Ok(future) 782 | } 783 | 784 | 785 | 786 | pub fn publish(&mut self, topic: URI, args: Option, kwargs: Option) -> WampResult<()> { 787 | info!("Publishing to {:?} with {:?} | {:?}", topic, args, kwargs); 788 | let request_id = self.get_next_session_id(); 789 | self.connection_info.lock().unwrap().send_message(Message::Publish(request_id, PublishOptions::new(false), topic, args, kwargs)) 790 | } 791 | 792 | pub fn call(&mut self, procedure: URI, args: Option, kwargs: Option) -> WampResult> { 793 | info!("Calling {:?} with {:?} | {:?}", procedure, args, kwargs); 794 | let request_id = self.get_next_session_id(); 795 | let (complete, future) = Future::<(List, Dict), CallError>::pair(); 796 | let mut info = self.connection_info.lock().unwrap(); 797 | info.call_requests.insert(request_id, complete); 798 | try!(info.send_message(Message::Call(request_id, CallOptions::new(), procedure, args, kwargs))); 799 | Ok(future) 800 | } 801 | 802 | pub fn publish_and_acknowledge(&mut self, topic: URI, args: Option, kwargs: Option) -> WampResult> { 803 | info!("Publishing to {:?} with {:?} | {:?}", topic, args, kwargs); 804 | let request_id = self.get_next_session_id(); 805 | let (complete, future) = Future::::pair(); 806 | let mut info = self.connection_info.lock().unwrap(); 807 | info.publish_requests.insert(request_id, complete); 808 | try!(info.send_message(Message::Publish(request_id, PublishOptions::new(true), topic, args, kwargs))); 809 | Ok(future) 810 | } 811 | 812 | pub fn shutdown(&mut self) -> WampResult> { 813 | let mut info = self.connection_info.lock().unwrap(); 814 | if info.connection_state == ConnectionState::Connected { 815 | info.connection_state = ConnectionState::ShuttingDown; 816 | let (complete, future) = Future::pair(); 817 | info.shutdown_complete = Some(complete); 818 | // TODO add timeout in case server doesn't respond. 819 | try!(info.send_message(Message::Goodbye(ErrorDetails::new(), Reason::SystemShutdown))); 820 | Ok(future) 821 | } else { 822 | Err(Error::new(ErrorKind::InvalidState("Tried to shut down a client that was already shutting down"))) 823 | } 824 | } 825 | 826 | pub fn is_closed(&self) -> bool { 827 | let info = self.connection_info.lock().unwrap(); 828 | 829 | match info.connection_state { 830 | ConnectionState::ShuttingDown | ConnectionState::Disconnected => true, 831 | _ => false, 832 | } 833 | } 834 | } 835 | 836 | impl fmt::Debug for ConnectionHandler { 837 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 838 | write!(f, "{{Connection id: {}}}", self.connection_info.lock().unwrap().session_id) 839 | } 840 | } 841 | --------------------------------------------------------------------------------