• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Unleash / unleash-edge / #1636

25 Feb 2025 04:07AM UTC coverage: 64.48% (+0.9%) from 63.597%
#1636

push

web-flow
dep-update: bump aws-config from 1.5.16 to 1.5.17 (#772)

Bumps [aws-config](https://github.com/smithy-lang/smithy-rs) from 1.5.16 to 1.5.17.
- [Release notes](https://github.com/smithy-lang/smithy-rs/releases)
- [Changelog](https://github.com/smithy-lang/smithy-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/smithy-lang/smithy-rs/commits)

---
updated-dependencies:
- dependency-name: aws-config
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

1661 of 2576 relevant lines covered (64.48%)

1.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.15
/server/src/feature_cache.rs
1
use crate::types::EdgeToken;
2
use dashmap::DashMap;
3
use tokio::sync::broadcast;
4
use unleash_types::client_features::ClientFeaturesDelta;
5
use unleash_types::{
6
    client_features::{ClientFeature, ClientFeatures, Segment},
7
    Deduplicate,
8
};
9

10
#[derive(Debug, Clone)]
11
pub enum UpdateType {
12
    Full(String),
13
    Update(String),
14
    Deletion,
15
}
16

17
#[derive(Debug, Clone)]
18
pub struct FeatureCache {
19
    features: DashMap<String, ClientFeatures>,
20
    update_sender: broadcast::Sender<UpdateType>,
21
}
22

23
impl FeatureCache {
24
    pub fn new(features: DashMap<String, ClientFeatures>) -> Self {
2✔
25
        let (tx, _rx) = tokio::sync::broadcast::channel::<UpdateType>(16);
4✔
26
        Self {
27
            features,
28
            update_sender: tx,
29
        }
30
    }
31

32
    pub fn len(&self) -> usize {
1✔
33
        self.features.len()
1✔
34
    }
35

36
    pub fn subscribe(&self) -> broadcast::Receiver<UpdateType> {
×
37
        self.update_sender.subscribe()
×
38
    }
39
    pub fn get(&self, key: &str) -> Option<dashmap::mapref::one::Ref<'_, String, ClientFeatures>> {
1✔
40
        self.features.get(key)
2✔
41
    }
42

43
    pub fn insert(&self, key: String, features: ClientFeatures) -> Option<ClientFeatures> {
1✔
44
        let v = self.features.insert(key.clone(), features);
2✔
45
        self.send_full_update(key);
1✔
46
        v
1✔
47
    }
48

49
    pub fn send_full_update(&self, cache_key: String) {
1✔
50
        let _ = self.update_sender.send(UpdateType::Full(cache_key));
1✔
51
    }
52

53
    pub fn remove(&self, key: &str) -> Option<(String, ClientFeatures)> {
1✔
54
        let v = self.features.remove(key);
1✔
55
        self.send_full_update(key.to_string());
2✔
56
        v
1✔
57
    }
58

59
    pub fn modify(&self, key: String, token: &EdgeToken, features: ClientFeatures) {
1✔
60
        self.features
3✔
61
            .entry(key.clone())
1✔
62
            .and_modify(|existing_features| {
1✔
63
                let updated = update_client_features(token, existing_features, &features);
1✔
64
                *existing_features = updated;
2✔
65
            })
66
            .or_insert(features);
2✔
67
        self.send_full_update(key);
1✔
68
    }
69

70
    pub fn apply_delta(&self, key: String, delta: &ClientFeaturesDelta) {
1✔
71
        self.features
3✔
72
            .entry(key.clone())
1✔
73
            .and_modify(|existing_features| {
1✔
74
                existing_features.apply_delta(delta);
1✔
75
            })
76
            .or_insert(ClientFeatures::create_from_delta(delta));
2✔
77
        self.send_full_update(key);
1✔
78
    }
79

80
    pub fn is_empty(&self) -> bool {
1✔
81
        self.features.is_empty()
1✔
82
    }
83

84
    pub fn iter(&self) -> dashmap::iter::Iter<'_, String, ClientFeatures> {
×
85
        self.features.iter()
×
86
    }
87
}
88

89
impl Default for FeatureCache {
90
    fn default() -> Self {
1✔
91
        FeatureCache::new(DashMap::default())
1✔
92
    }
93
}
94

95
fn update_client_features(
1✔
96
    token: &EdgeToken,
97
    old: &ClientFeatures,
98
    update: &ClientFeatures,
99
) -> ClientFeatures {
100
    let mut updated_features =
1✔
101
        update_projects_from_feature_update(token, &old.features, &update.features);
102
    updated_features.sort();
2✔
103
    let segments = merge_segments_update(old.segments.clone(), update.segments.clone());
1✔
104
    ClientFeatures {
105
        version: old.version.max(update.version),
1✔
106
        features: updated_features,
107
        segments: segments.map(|mut s| {
1✔
108
            s.sort();
109
            s
110
        }),
111
        query: old.query.clone().or(update.query.clone()),
2✔
112
        meta: old.meta.clone().or(update.meta.clone()),
2✔
113
    }
114
}
115

116
pub(crate) fn update_projects_from_feature_update(
1✔
117
    token: &EdgeToken,
118
    original: &[ClientFeature],
119
    updated: &[ClientFeature],
120
) -> Vec<ClientFeature> {
121
    let projects_to_update = &token.projects;
1✔
122
    if projects_to_update.contains(&"*".into()) {
2✔
123
        updated.into()
1✔
124
    } else {
125
        let mut to_keep: Vec<ClientFeature> = original
1✔
126
            .iter()
127
            .filter(|toggle| {
1✔
128
                let p = toggle.project.clone().unwrap_or_else(|| "default".into());
1✔
129
                !projects_to_update.contains(&p)
2✔
130
            })
131
            .cloned()
132
            .collect();
133
        to_keep.extend(updated.iter().cloned());
2✔
134
        to_keep
1✔
135
    }
136
}
137

138
fn merge_segments_update(
1✔
139
    segments: Option<Vec<Segment>>,
140
    updated_segments: Option<Vec<Segment>>,
141
) -> Option<Vec<Segment>> {
142
    match (segments, updated_segments) {
1✔
143
        (Some(s), Some(mut o)) => {
×
144
            o.extend(s);
×
145
            Some(o.deduplicate())
×
146
        }
147
        (Some(s), None) => Some(s),
×
148
        (None, Some(o)) => Some(o),
×
149
        (None, None) => None,
1✔
150
    }
151
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc