romp/workflow/
context.rs

1//! Context object for the message workflow through the filter chain.
2
3use std::collections::HashMap;
4use std::sync::{Arc, RwLock};
5
6use crate::session::stomp_session::{StompSession, FLAG_ADMIN, FLAG_DOWNSTREAM};
7use chrono::{Utc, DateTime};
8
9//. TODO provide access to SERVER and CONFIG items here, rather than globals
10
11pub struct Context {
12    /// StompSession is valid for the duration of a STOMP TCP connection or WebSocket
13    pub session: Arc<RwLock<StompSession>>,
14    /// Request attributes, valid for the life of a single message, to avoid collisions prefix the attributes with the cargo project name e.g. "romp."
15    pub attributes: HashMap<&'static str, String>,
16    // TODO how to determine this if SSL is upstream
17    pub is_secure: bool,
18    /// flag is true if incoming request has upgraded to WebSockets
19    pub is_web_sockets: bool,
20    // TODO finer grained security
21    /// True if this request has admin privs, from port 61616 or login credentials
22    is_admin: Option<bool>,
23    /// If true session is upstream
24    is_downstream: Option<bool>,
25    /// Cached value of time now
26    timestamp: Option<DateTime<Utc>>,
27}
28
29impl Context {
30    pub(crate) fn new(session: Arc<RwLock<StompSession>>) -> Context {
31        Context {
32            session,
33            attributes: Default::default(),
34            is_secure: false,
35            is_web_sockets: false,
36            is_admin: None,
37            is_downstream: None,
38            timestamp: None,
39        }
40    }
41
42    // for use in tests
43    pub fn mock() -> Context {
44        Context {
45            session: Arc::new(RwLock::new(StompSession::new())),
46            attributes: Default::default(),
47            is_secure: false,
48            is_web_sockets: false,
49            is_admin: None,
50            is_downstream: None,
51            timestamp: None,
52        }
53    }
54
55    /// returns (cached) timestamp
56    pub fn now(&mut self) -> DateTime<Utc> {
57        if let None = self.timestamp {
58            self.timestamp = Some(Utc::now());
59        }
60        self.timestamp.unwrap()
61    }
62
63    /// returns (cached) admin flag from the session
64    pub fn is_admin(&mut self) -> bool {
65        if let None = self.is_admin {
66            self.is_admin = Some(self.session.read().unwrap().get_flag(FLAG_ADMIN));
67        }
68        self.is_admin.unwrap()
69    }
70
71    /// returns (cached) downstream flag from the session
72    pub fn is_downstream(&mut self) -> bool {
73        if let None = self.is_admin {
74            self.is_downstream = Some(self.session.read().unwrap().get_flag(FLAG_DOWNSTREAM));
75        }
76        self.is_downstream.unwrap()
77    }
78
79    // OW horrible, have to clone a string to get it out from behind two read locks :(
80    pub(crate) fn downstream(&self) -> String {
81        self.session.read().unwrap().downstream_connector.as_ref().unwrap().read().unwrap().downstream.name.clone()
82    }
83}