1
1
use std:: fmt;
2
+ use std:: sync:: { atomic, Arc } ;
2
3
3
- use core;
4
+ use core:: { self , futures} ;
5
+ use core:: futures:: sync:: mpsc;
6
+ use server_utils:: tokio_core:: reactor:: Remote ;
4
7
use ws;
5
8
6
9
use session;
7
10
use Origin ;
8
11
12
+ /// Output of WebSocket connection. Use this to send messages to the other endpoint.
13
+ #[ derive( Clone ) ]
14
+ pub struct Sender {
15
+ out : ws:: Sender ,
16
+ active : Arc < atomic:: AtomicBool > ,
17
+ }
18
+
19
+ impl Sender {
20
+ /// Creates a new `Sender`.
21
+ pub fn new ( out : ws:: Sender , active : Arc < atomic:: AtomicBool > ) -> Self {
22
+ Sender {
23
+ out : out,
24
+ active : active,
25
+ }
26
+ }
27
+
28
+ fn check_active ( & self ) -> ws:: Result < ( ) > {
29
+ if self . active . load ( atomic:: Ordering :: SeqCst ) {
30
+ Ok ( ( ) )
31
+ } else {
32
+ Err ( ws:: Error :: new ( ws:: ErrorKind :: Internal , "Attempting to send a message to closed connection." ) )
33
+ }
34
+ }
35
+
36
+ /// Sends a message over the connection.
37
+ /// Will return error if the connection is not active any more.
38
+ pub fn send < M > ( & self , msg : M ) -> ws:: Result < ( ) > where
39
+ M : Into < ws:: Message >
40
+ {
41
+ self . check_active ( ) ?;
42
+ self . out . send ( msg)
43
+ }
44
+
45
+ /// Sends a message over the endpoints of all connections.
46
+ /// Will return error if the connection is not active any more.
47
+ pub fn broadcast < M > ( & self , msg : M ) -> ws:: Result < ( ) > where
48
+ M : Into < ws:: Message >
49
+ {
50
+ self . check_active ( ) ?;
51
+ self . out . broadcast ( msg)
52
+ }
53
+
54
+ /// Sends a close code to the other endpoint.
55
+ /// Will return error if the connection is not active any more.
56
+ pub fn close ( & self , code : ws:: CloseCode ) -> ws:: Result < ( ) > {
57
+ self . check_active ( ) ?;
58
+ self . out . close ( code)
59
+ }
60
+ }
61
+
9
62
/// Request context
10
63
pub struct RequestContext {
11
64
/// Session id
@@ -15,7 +68,20 @@ pub struct RequestContext {
15
68
/// Requested protocols
16
69
pub protocols : Vec < String > ,
17
70
/// Direct channel to send messages to a client.
18
- pub out : ws:: Sender ,
71
+ pub out : Sender ,
72
+ /// Remote to underlying event loop.
73
+ pub remote : Remote ,
74
+ }
75
+
76
+ impl RequestContext {
77
+ /// Get this session as a `Sink` spawning a new future
78
+ /// in the underlying event loop.
79
+ pub fn sender ( & self ) -> mpsc:: Sender < String > {
80
+ let out = self . out . clone ( ) ;
81
+ let ( sender, receiver) = mpsc:: channel ( 1 ) ;
82
+ self . remote . spawn ( move |_| SenderFuture ( out, receiver) ) ;
83
+ sender
84
+ }
19
85
}
20
86
21
87
impl fmt:: Debug for RequestContext {
@@ -36,7 +102,44 @@ pub trait MetaExtractor<M: core::Metadata>: Send + Sync + 'static {
36
102
}
37
103
}
38
104
105
+ impl < M , F > MetaExtractor < M > for F where
106
+ M : core:: Metadata ,
107
+ F : Fn ( & RequestContext ) -> M + Send + Sync + ' static ,
108
+ {
109
+ fn extract ( & self , context : & RequestContext ) -> M {
110
+ ( * self ) ( context)
111
+ }
112
+ }
113
+
39
114
/// Dummy metadata extractor
40
115
#[ derive( Clone ) ]
41
116
pub struct NoopExtractor ;
42
117
impl < M : core:: Metadata > MetaExtractor < M > for NoopExtractor { }
118
+
119
+ struct SenderFuture ( Sender , mpsc:: Receiver < String > ) ;
120
+ impl futures:: Future for SenderFuture {
121
+ type Item = ( ) ;
122
+ type Error = ( ) ;
123
+
124
+ fn poll ( & mut self ) -> futures:: Poll < Self :: Item , Self :: Error > {
125
+ use self :: futures:: Stream ;
126
+
127
+ loop {
128
+ let item = self . 1 . poll ( ) ?;
129
+ match item {
130
+ futures:: Async :: NotReady => {
131
+ return Ok ( futures:: Async :: NotReady ) ;
132
+ } ,
133
+ futures:: Async :: Ready ( None ) => {
134
+ return Ok ( futures:: Async :: Ready ( ( ) ) ) ;
135
+ } ,
136
+ futures:: Async :: Ready ( Some ( val) ) => {
137
+ if let Err ( e) = self . 0 . send ( val) {
138
+ warn ! ( "Error sending a subscription update: {:?}" , e) ;
139
+ return Ok ( futures:: Async :: Ready ( ( ) ) ) ;
140
+ }
141
+ } ,
142
+ }
143
+ }
144
+ }
145
+ }
0 commit comments