karyon_p2p/routing_table/
bucket.rs1use super::{Entry, Key};
2
3use rand::{rngs::OsRng, seq::SliceRandom};
4
5pub type EntryStatusFlag = u16;
7
8pub const CONNECTED_ENTRY: EntryStatusFlag = 0b000001;
10
11pub const DISCONNECTED_ENTRY: EntryStatusFlag = 0b000010;
13
14pub const PENDING_ENTRY: EntryStatusFlag = 0b000100;
17
18pub const UNREACHABLE_ENTRY: EntryStatusFlag = 0b001000;
20
21pub const UNSTABLE_ENTRY: EntryStatusFlag = 0b010000;
23
24pub const INCOMPATIBLE_ENTRY: EntryStatusFlag = 0b100000;
28
29#[allow(dead_code)]
30pub const ALL_ENTRY: EntryStatusFlag = 0b111111;
31
32#[derive(Clone, Debug)]
34pub struct BucketEntry {
35 pub status: EntryStatusFlag,
36 pub entry: Entry,
37 pub failures: u32,
38 pub last_seen: i64,
39}
40
41impl BucketEntry {
42 pub fn is_connected(&self) -> bool {
43 self.status ^ CONNECTED_ENTRY == 0
44 }
45
46 pub fn is_incompatible(&self) -> bool {
47 self.status ^ INCOMPATIBLE_ENTRY == 0
48 }
49
50 pub fn is_unreachable(&self) -> bool {
51 self.status ^ UNREACHABLE_ENTRY == 0
52 }
53
54 pub fn is_unstable(&self) -> bool {
55 self.status ^ UNSTABLE_ENTRY == 0
56 }
57}
58
59pub const BUCKET_SIZE: usize = 20;
61
62#[derive(Debug, Clone)]
64pub struct Bucket {
65 entries: Vec<BucketEntry>,
66}
67
68impl Bucket {
69 pub fn new() -> Self {
71 Self {
72 entries: Vec::with_capacity(BUCKET_SIZE),
73 }
74 }
75
76 pub fn add(&mut self, entry: &Entry) {
78 self.entries.push(BucketEntry {
79 status: PENDING_ENTRY,
80 entry: entry.clone(),
81 failures: 0,
82 last_seen: chrono::Utc::now().timestamp(),
83 })
84 }
85
86 pub fn len(&self) -> usize {
88 self.entries.len()
89 }
90
91 pub fn iter(&self) -> impl Iterator<Item = &BucketEntry> {
93 self.entries.iter()
94 }
95
96 pub fn remove(&mut self, key: &Key) {
98 let position = self.entries.iter().position(|e| &e.entry.key == key);
99 if let Some(i) = position {
100 self.entries.remove(i);
101 }
102 }
103
104 pub fn random_iter(&self, amount: usize) -> impl Iterator<Item = &BucketEntry> {
106 self.entries.choose_multiple(&mut OsRng, amount)
107 }
108
109 pub fn update_entry(&mut self, key: &Key, entry_flag: EntryStatusFlag) {
116 if let Some(e) = self.entries.iter_mut().find(|e| &e.entry.key == key) {
117 e.status = entry_flag;
118 if e.is_unreachable() || e.is_unstable() {
119 e.failures += 1;
120 }
121
122 if !e.is_unreachable() {
123 e.last_seen = chrono::Utc::now().timestamp();
124 }
125 }
126 }
127
128 pub fn contains_key(&self, key: &Key) -> bool {
130 self.entries.iter().any(|e| &e.entry.key == key)
131 }
132}