phoenix_channels/
client.rs1use std::thread;
2use std::time::Duration;
3use std::sync::{Arc, Mutex};
4use std::sync::mpsc;
5
6use slog;
7use slog_stdlog;
8use slog::Drain;
9
10use websocket::client::ClientBuilder;
11
12use receiver::Receiver;
13use sender::Sender;
14use error::ConnectError;
15use message::Message;
16use error::{JoinError, MessageError};
17
18pub type MessageResult = Result<Message, MessageError>;
19pub type MessageReceiver = mpsc::Receiver<MessageResult>;
20
21
22const PHOENIX_VERSION: &str = "2.0.0";
23
24
25#[derive(Debug)]
26pub enum ClientError {
27 Connect(ConnectError),
28 Join(JoinError),
29 Thread(String),
30}
31
32impl From<ConnectError> for ClientError {
33 fn from(e: ConnectError) -> Self {
34 return ClientError::Connect(e);
35 }
36}
37
38impl From<JoinError> for ClientError {
39 fn from(e: JoinError) -> Self {
40 return ClientError::Join(e);
41 }
42}
43
44
45
46pub fn connect(url: &str, params: Vec<(&str, &str)>, logger: Option<slog::Logger>) -> Result<(Sender, Receiver), ConnectError> {
47 let logger = logger.unwrap_or(slog::Logger::root(slog_stdlog::StdLog.fuse(), o!()));
48
49 let mut params_uri: String = "".to_owned();
51 for (k, v) in params {
52 params_uri.push_str(&format!("&{}={}", k, v));
53 }
54
55 let addr = format!("{}/websocket?vsn={}{}", url, PHOENIX_VERSION, params_uri);
59 let mut client_builder = ClientBuilder::new(&addr)?;
60
61 let socket_client = client_builder.connect_insecure()?;
62 let (reader, writer) = socket_client.split()?;
63
64 let sender = Sender::new(writer, logger.new(o!("type" => "sender")));
65 let receiver = Receiver::new(reader, logger.new(o!("type" => "receiver")));
66
67 return Ok((sender, receiver));
68}
69
70
71pub struct Client {
72 logger: slog::Logger,
73 sender_ref: Arc<Mutex<Sender>>,
74 heartbeat_handle: thread::JoinHandle<()>,
75 message_processor_handle: thread::JoinHandle<()>,
76}
77
78impl Client {
79 pub fn new(url: &str, params: Vec<(&str, &str)>, logger: Option<slog::Logger>) -> Result<(Client, MessageReceiver), ClientError> {
80 let logger = logger.unwrap_or(slog::Logger::root(slog_stdlog::StdLog.fuse(), o!()));
81 debug!(logger, "creating client"; "url" => url);
82
83 let (sender, receiver) = connect(url, params, Some(logger.clone()))?;
84
85 let (tx, rx) = mpsc::channel();
86
87 let sender_ref = Arc::new(Mutex::new(sender));
88 let heartbeat = Client::keepalive(Arc::clone(&sender_ref));
89 let message_processor = Client::process_messages(receiver, tx);
90
91 let client = Client {
92 logger: logger,
93 sender_ref: sender_ref,
94 heartbeat_handle: heartbeat,
95 message_processor_handle: message_processor,
96 };
97
98 return Ok((client, rx));
99 }
100
101 fn keepalive(sender_ref: Arc<Mutex<Sender>>) -> thread::JoinHandle<()> {
102 return thread::spawn(move || {
103 loop {
104 thread::sleep(Duration::from_secs(30));
105 let mut sender = sender_ref.lock().unwrap();
107 sender.heartbeat();
108 }
109 });
110 }
111
112 fn process_messages(receiver: Receiver, sender: mpsc::Sender<MessageResult>) -> thread::JoinHandle<()> {
113 return thread::spawn(move || {
114 for message in MessageIterator::new(receiver) {
115 let result = sender.send(message);
116
117 if result.is_err() {
119 break;
120 }
121 }
122 });
123 }
124
125 pub fn join(&self, channel: &str) -> Result<u32, ClientError> {
126 return match self.sender_ref.lock() {
127 Ok(mut sender) => Ok(sender.join(channel)?),
128 Err(_) => Err(ClientError::Thread(String::from("Cannot join as sender mutex has been poisoned"))),
129 };
130 }
131
132 pub fn join_threads(self) -> thread::Result<()> {
133 self.heartbeat_handle.join()?;
134 self.message_processor_handle.join()?;
135 return Ok(());
136 }
137}
138
139
140pub struct MessageIterator
141{
142 receiver: Receiver,
143}
144
145impl MessageIterator {
146 pub fn new(receiver: Receiver) -> MessageIterator {
147 MessageIterator {
148 receiver: receiver,
149 }
150 }
151}
152
153impl Iterator for MessageIterator {
154 type Item = MessageResult;
155
156 fn next(&mut self) -> Option<Self::Item> {
157 return self.receiver.next();
158 }
159}