1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Pending actix4

use std::collections::{BTreeMap, HashMap};

use actix_web::{
    dev::{Payload, RequestHead},
    Error, FromRequest, HttpMessage, HttpRequest,
};
use futures::{future, future::Ready};
use serde::{
    ser::{SerializeMap, Serializer},
    Serialize,
};
use serde_json::value::Value;

#[derive(Clone, Debug, Default)]
pub struct Tags {
    pub tags: HashMap<String, String>,
    pub extra: HashMap<String, String>,
}

impl Serialize for Tags {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut seq = serializer.serialize_map(Some(self.tags.len()))?;
        for tag in self.tags.clone() {
            if !tag.1.is_empty() {
                seq.serialize_entry(&tag.0, &tag.1)?;
            }
        }
        seq.end()
    }
}

#[allow(dead_code)]
fn insert_if_not_empty(label: &str, val: &str, tags: &mut HashMap<String, String>) {
    if !val.is_empty() {
        tags.insert(label.to_owned(), val.to_owned());
    }
}

impl Tags {
    #![allow(unused)] // TODO: Start using tags

    pub fn from_request_head(req_head: &RequestHead) -> Tags {
        req_head.into()
    }

    pub fn with_tags(tags: HashMap<String, String>) -> Tags {
        if tags.is_empty() {
            return Tags::default();
        }
        Tags {
            tags,
            extra: HashMap::new(),
        }
    }

    pub fn get(&self, label: &str) -> String {
        let none = "None".to_owned();
        self.tags.get(label).map(String::from).unwrap_or(none)
    }

    pub fn extend(&mut self, tags: HashMap<String, String>) {
        self.tags.extend(tags);
    }

    pub fn tag_tree(self) -> BTreeMap<String, String> {
        let mut result = BTreeMap::new();

        for (k, v) in self.tags {
            result.insert(k.clone(), v.clone());
        }
        result
    }

    pub fn extra_tree(self) -> BTreeMap<String, Value> {
        let mut result = BTreeMap::new();

        for (k, v) in self.extra {
            result.insert(k.clone(), Value::from(v));
        }
        result
    }
}

impl slog::KV for Tags {
    fn serialize(
        &self,
        _record: &slog::Record<'_>,
        serializer: &mut dyn slog::Serializer,
    ) -> slog::Result {
        for (key, val) in &self.tags {
            serializer.emit_str(slog::Key::from(key.clone()), val)?;
        }
        Ok(())
    }
}

impl FromRequest for Tags {
    type Error = Error;
    type Future = Ready<Result<Self, Self::Error>>;

    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        let tags = {
            let exts = req.extensions();
            match exts.get::<Tags>() {
                Some(t) => t.clone(),
                None => Tags::from_request_head(req.head()),
            }
        };

        future::ok(tags)
    }
}

impl From<&RequestHead> for Tags {
    fn from(req_head: &RequestHead) -> Self {
        let mut tags = HashMap::new();
        tags.insert("uri.method".to_owned(), req_head.method.to_string());
        Tags {
            tags,
            extra: HashMap::new(),
        }
    }
}

impl From<Tags> for BTreeMap<String, String> {
    fn from(tags: Tags) -> BTreeMap<String, String> {
        let mut result = BTreeMap::new();

        for (k, v) in tags.tags {
            result.insert(k.clone(), v.clone());
        }

        result
    }
}