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
use crate::shared::file_like::FileLike;
use crate::shared::file_metadata::Owner;
use crate::shared::server_file::ServerFile;
use crate::shared::tree_like::{TreeLike, TreeLikeMut};
use crate::shared::SharedResult;
use db_rs::{LookupSet, LookupTable};
use std::collections::HashSet;
use std::iter::FromIterator;
use tracing::*;
use uuid::Uuid;

pub struct ServerTree<'a> {
    pub ids: HashSet<Uuid>,
    pub owned_files: &'a mut LookupSet<Owner, Uuid>,
    pub shared_files: &'a mut LookupSet<Owner, Uuid>,
    pub file_children: &'a mut LookupSet<Uuid, Uuid>,
    pub files: &'a mut LookupTable<Uuid, ServerFile>,
}

impl<'a> ServerTree<'a> {
    pub fn new(
        owner: Owner, owned_files: &'a mut LookupSet<Owner, Uuid>,
        shared_files: &'a mut LookupSet<Owner, Uuid>, file_children: &'a mut LookupSet<Uuid, Uuid>,
        files: &'a mut LookupTable<Uuid, ServerFile>,
    ) -> SharedResult<Self> {
        let (owned_ids, shared_ids) =
            match (owned_files.get().get(&owner), shared_files.get().get(&owner)) {
                (Some(owned_ids), Some(shared_ids)) => (owned_ids.clone(), shared_ids.clone()),
                _ => {
                    error!("Tree created for user without owned and shared files {:?}", owner);
                    (HashSet::new(), HashSet::new())
                }
            };

        let mut ids = HashSet::new();
        ids.extend(owned_ids);
        ids.extend(shared_ids.clone());

        let mut to_get_descendants = Vec::from_iter(shared_ids);
        while let Some(id) = to_get_descendants.pop() {
            let children = file_children.get().get(&id).cloned().unwrap_or_default();
            ids.extend(children.clone());
            to_get_descendants.extend(children);
        }

        Ok(Self { ids, owned_files, shared_files, file_children, files })
    }
}

impl TreeLike for ServerTree<'_> {
    type F = ServerFile;

    fn ids(&self) -> HashSet<&Uuid> {
        self.ids.iter().collect()
    }

    fn maybe_find(&self, id: &Uuid) -> Option<&Self::F> {
        if self.ids.contains(id) {
            self.files.maybe_find(id)
        } else {
            None
        }
    }
}

impl TreeLikeMut for ServerTree<'_> {
    fn insert(&mut self, f: Self::F) -> SharedResult<Option<Self::F>> {
        let id = *f.id();
        let owner = f.owner();
        let maybe_prior = LookupTable::insert(self.files, id, f.clone())?;

        // maintain index: owned_files
        if maybe_prior.as_ref().map(|f| f.owner()) != Some(f.owner()) {
            if let Some(ref prior) = maybe_prior {
                self.owned_files.remove(&prior.owner(), &id)?;
            }
            self.owned_files.insert(owner, id)?;
        }

        // maintain index: shared_files
        let prior_sharees = if let Some(ref prior) = maybe_prior {
            prior
                .user_access_keys()
                .iter()
                .filter(|k| !k.deleted)
                .map(|k| Owner(k.encrypted_for))
                .collect()
        } else {
            HashSet::new()
        };
        let sharees = f
            .user_access_keys()
            .iter()
            .filter(|k| !k.deleted)
            .map(|k| Owner(k.encrypted_for))
            .collect::<HashSet<_>>();
        for removed_sharee in prior_sharees.difference(&sharees) {
            self.shared_files.remove(removed_sharee, &id)?;
        }
        for new_sharee in sharees.difference(&prior_sharees) {
            self.shared_files.insert(*new_sharee, id)?;
        }

        // maintain index: file_children
        if self.file_children.get().get(&id).is_none() {
            self.file_children.create_key(id)?;
        }
        if self.file_children.get().get(f.parent()).is_none() {
            self.file_children.create_key(*f.parent())?;
        }
        if maybe_prior.as_ref().map(|f| *f.parent()) != Some(*f.parent()) {
            if let Some(ref prior) = maybe_prior {
                self.file_children.remove(prior.parent(), &id)?;
            }

            self.file_children.insert(*f.parent(), id)?;
        }

        Ok(maybe_prior)
    }

    fn remove(&mut self, _id: Uuid) -> SharedResult<Option<Self::F>> {
        error!("remove metadata called in server!");
        Ok(None)
    }

    fn clear(&mut self) -> SharedResult<()> {
        error!("clear called in server!");
        Ok(())
    }
}