You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

346 lines
11KB

  1. use super::*;
  2. use crate::backends::FolderHash;
  3. use std::collections::BTreeMap;
  4. use std::fs;
  5. use std::io;
  6. use std::ops::{Deref, DerefMut};
  7. use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
  8. use fnv::FnvHashMap;
  9. pub struct EnvelopeRef<'g> {
  10. guard: RwLockReadGuard<'g, FnvHashMap<EnvelopeHash, Envelope>>,
  11. env_hash: EnvelopeHash,
  12. }
  13. impl Deref for EnvelopeRef<'_> {
  14. type Target = Envelope;
  15. fn deref(&self) -> &Envelope {
  16. self.guard.get(&self.env_hash).unwrap()
  17. }
  18. }
  19. pub struct EnvelopeRefMut<'g> {
  20. guard: RwLockWriteGuard<'g, FnvHashMap<EnvelopeHash, Envelope>>,
  21. env_hash: EnvelopeHash,
  22. }
  23. impl Deref for EnvelopeRefMut<'_> {
  24. type Target = Envelope;
  25. fn deref(&self) -> &Envelope {
  26. self.guard.get(&self.env_hash).unwrap()
  27. }
  28. }
  29. impl DerefMut for EnvelopeRefMut<'_> {
  30. fn deref_mut(&mut self) -> &mut Envelope {
  31. self.guard.get_mut(&self.env_hash).unwrap()
  32. }
  33. }
  34. #[derive(Debug, Clone, Deserialize, Default, Serialize)]
  35. pub struct Collection {
  36. pub envelopes: Arc<RwLock<FnvHashMap<EnvelopeHash, Envelope>>>,
  37. message_ids: FnvHashMap<Vec<u8>, EnvelopeHash>,
  38. date_index: BTreeMap<UnixTimestamp, EnvelopeHash>,
  39. subject_index: Option<BTreeMap<String, EnvelopeHash>>,
  40. pub threads: FnvHashMap<FolderHash, Threads>,
  41. sent_folder: Option<FolderHash>,
  42. }
  43. impl Drop for Collection {
  44. fn drop(&mut self) {
  45. let cache_dir: xdg::BaseDirectories =
  46. xdg::BaseDirectories::with_profile("meli", "threads".to_string()).unwrap();
  47. if let Ok(cached) = cache_dir.place_cache_file("threads") {
  48. /* place result in cache directory */
  49. let f = match fs::File::create(cached) {
  50. Ok(f) => f,
  51. Err(e) => {
  52. panic!("{}", e);
  53. }
  54. };
  55. let writer = io::BufWriter::new(f);
  56. bincode::serialize_into(writer, &self.threads).unwrap();
  57. }
  58. }
  59. }
  60. impl Collection {
  61. pub fn new(envelopes: FnvHashMap<EnvelopeHash, Envelope>) -> Collection {
  62. let date_index = BTreeMap::new();
  63. let subject_index = None;
  64. let message_ids = FnvHashMap::with_capacity_and_hasher(2048, Default::default());
  65. /* Scrap caching for now. When a cached threads file is loaded, we must remove/rehash the
  66. * thread nodes that shouldn't exist anymore (e.g. because their file moved from /new to
  67. * /cur, or it was deleted).
  68. */
  69. let threads = FnvHashMap::with_capacity_and_hasher(16, Default::default());
  70. Collection {
  71. envelopes: Arc::new(RwLock::new(envelopes)),
  72. date_index,
  73. message_ids,
  74. subject_index,
  75. threads,
  76. sent_folder: None,
  77. }
  78. }
  79. pub fn len(&self) -> usize {
  80. self.envelopes.read().unwrap().len()
  81. }
  82. pub fn is_empty(&self) -> bool {
  83. self.envelopes.read().unwrap().is_empty()
  84. }
  85. pub fn remove(&mut self, envelope_hash: EnvelopeHash, folder_hash: FolderHash) {
  86. debug!("DEBUG: Removing {}", envelope_hash);
  87. self.envelopes.write().unwrap().remove(&envelope_hash);
  88. self.threads
  89. .entry(folder_hash)
  90. .or_default()
  91. .remove(envelope_hash);
  92. for (h, t) in self.threads.iter_mut() {
  93. if *h == folder_hash {
  94. continue;
  95. }
  96. t.remove(envelope_hash);
  97. }
  98. }
  99. pub fn rename(
  100. &mut self,
  101. old_hash: EnvelopeHash,
  102. new_hash: EnvelopeHash,
  103. folder_hash: FolderHash,
  104. ) {
  105. if !self.envelopes.write().unwrap().contains_key(&old_hash) {
  106. return;
  107. }
  108. let mut env = self.envelopes.write().unwrap().remove(&old_hash).unwrap();
  109. env.set_hash(new_hash);
  110. self.message_ids
  111. .insert(env.message_id().raw().to_vec(), new_hash);
  112. self.envelopes.write().unwrap().insert(new_hash, env);
  113. {
  114. if self
  115. .threads
  116. .entry(folder_hash)
  117. .or_default()
  118. .update_envelope(&self.envelopes, old_hash, new_hash)
  119. .is_ok()
  120. {
  121. return;
  122. }
  123. }
  124. /* envelope is not in threads, so insert it */
  125. self.threads
  126. .entry(folder_hash)
  127. .or_default()
  128. .insert(&mut self.envelopes, new_hash);
  129. for (h, t) in self.threads.iter_mut() {
  130. if *h == folder_hash {
  131. continue;
  132. }
  133. t.update_envelope(&self.envelopes, old_hash, new_hash)
  134. .ok()
  135. .take();
  136. }
  137. }
  138. /// Merge new Mailbox to collection and update threads.
  139. /// Returns a list of already existing folders whose threads were updated
  140. pub fn merge(
  141. &mut self,
  142. mut new_envelopes: FnvHashMap<EnvelopeHash, Envelope>,
  143. folder_hash: FolderHash,
  144. sent_folder: Option<FolderHash>,
  145. ) -> Option<StackVec<FolderHash>> {
  146. self.sent_folder = sent_folder;
  147. for (h, e) in new_envelopes.iter() {
  148. self.message_ids.insert(e.message_id().raw().to_vec(), *h);
  149. }
  150. let &mut Collection {
  151. ref mut threads,
  152. ref mut envelopes,
  153. ref sent_folder,
  154. ..
  155. } = self;
  156. if !threads.contains_key(&folder_hash) {
  157. threads.insert(folder_hash, Threads::new(new_envelopes.len()));
  158. for (h, e) in new_envelopes {
  159. envelopes.write().unwrap().insert(h, e);
  160. }
  161. } else {
  162. threads.entry(folder_hash).and_modify(|t| {
  163. let mut ordered_hash_set =
  164. new_envelopes.keys().cloned().collect::<Vec<EnvelopeHash>>();
  165. ordered_hash_set.sort_by(|a, b| {
  166. new_envelopes[a]
  167. .date()
  168. .partial_cmp(&new_envelopes[b].date())
  169. .unwrap()
  170. });
  171. for h in ordered_hash_set {
  172. envelopes
  173. .write()
  174. .unwrap()
  175. .insert(h, new_envelopes.remove(&h).unwrap());
  176. t.insert(envelopes, h);
  177. }
  178. });
  179. }
  180. let mut ret = StackVec::new();
  181. let keys = threads.keys().cloned().collect::<Vec<FolderHash>>();
  182. for t_fh in keys {
  183. if t_fh == folder_hash {
  184. continue;
  185. }
  186. if sent_folder.map(|f| f == folder_hash).unwrap_or(false) {
  187. let envelopes_lck = envelopes.read().unwrap();
  188. let mut ordered_hash_set = threads[&folder_hash]
  189. .hash_set
  190. .iter()
  191. .cloned()
  192. .collect::<Vec<EnvelopeHash>>();
  193. ordered_hash_set.sort_by(|a, b| {
  194. envelopes_lck[a]
  195. .date()
  196. .partial_cmp(&envelopes_lck[b].date())
  197. .unwrap()
  198. });
  199. drop(envelopes_lck);
  200. let mut updated = false;
  201. for h in ordered_hash_set {
  202. updated |= threads.entry(t_fh).or_default().insert_reply(envelopes, h);
  203. }
  204. if updated {
  205. ret.push(t_fh);
  206. }
  207. continue;
  208. }
  209. if sent_folder.map(|f| f == t_fh).unwrap_or(false) {
  210. let envelopes_lck = envelopes.read().unwrap();
  211. let mut ordered_hash_set = threads[&t_fh]
  212. .hash_set
  213. .iter()
  214. .cloned()
  215. .collect::<Vec<EnvelopeHash>>();
  216. ordered_hash_set.sort_by(|a, b| {
  217. envelopes_lck[a]
  218. .date()
  219. .partial_cmp(&envelopes_lck[b].date())
  220. .unwrap()
  221. });
  222. drop(envelopes_lck);
  223. let mut updated = false;
  224. for h in ordered_hash_set {
  225. updated |= threads
  226. .entry(folder_hash)
  227. .or_default()
  228. .insert_reply(envelopes, h);
  229. }
  230. if updated {
  231. ret.push(folder_hash);
  232. }
  233. }
  234. }
  235. if ret.is_empty() {
  236. None
  237. } else {
  238. Some(ret)
  239. }
  240. }
  241. pub fn update(
  242. &mut self,
  243. old_hash: EnvelopeHash,
  244. mut envelope: Envelope,
  245. folder_hash: FolderHash,
  246. ) {
  247. let old_env = self.envelopes.write().unwrap().remove(&old_hash).unwrap();
  248. envelope.set_thread(old_env.thread());
  249. let new_hash = envelope.hash();
  250. self.message_ids
  251. .insert(envelope.message_id().raw().to_vec(), new_hash);
  252. self.envelopes.write().unwrap().insert(new_hash, envelope);
  253. if self.sent_folder.map(|f| f == folder_hash).unwrap_or(false) {
  254. for (_, t) in self.threads.iter_mut() {
  255. t.update_envelope(&self.envelopes, old_hash, new_hash)
  256. .unwrap_or(());
  257. }
  258. }
  259. {
  260. if self
  261. .threads
  262. .entry(folder_hash)
  263. .or_default()
  264. .update_envelope(&self.envelopes, old_hash, new_hash)
  265. .is_ok()
  266. {
  267. return;
  268. }
  269. }
  270. /* envelope is not in threads, so insert it */
  271. self.threads
  272. .entry(folder_hash)
  273. .or_default()
  274. .insert(&mut self.envelopes, new_hash);
  275. for (h, t) in self.threads.iter_mut() {
  276. if *h == folder_hash {
  277. continue;
  278. }
  279. t.update_envelope(&self.envelopes, old_hash, new_hash)
  280. .ok()
  281. .take();
  282. }
  283. }
  284. pub fn insert(&mut self, envelope: Envelope, folder_hash: FolderHash) {
  285. let hash = envelope.hash();
  286. self.message_ids
  287. .insert(envelope.message_id().raw().to_vec(), hash);
  288. self.envelopes.write().unwrap().insert(hash, envelope);
  289. if !self
  290. .threads
  291. .entry(folder_hash)
  292. .or_default()
  293. .insert_reply(&mut self.envelopes, hash)
  294. {
  295. self.threads
  296. .entry(folder_hash)
  297. .or_default()
  298. .insert(&mut self.envelopes, hash);
  299. }
  300. }
  301. pub fn insert_reply(&mut self, env_hash: EnvelopeHash) {
  302. debug_assert!(self.envelopes.read().unwrap().contains_key(&env_hash));
  303. for (_, t) in self.threads.iter_mut() {
  304. t.insert_reply(&mut self.envelopes, env_hash);
  305. }
  306. }
  307. pub fn get_env<'g>(&'g self, env_hash: EnvelopeHash) -> EnvelopeRef<'g> {
  308. let guard: RwLockReadGuard<'g, _> = self.envelopes.read().unwrap();
  309. EnvelopeRef { guard, env_hash }
  310. }
  311. pub fn get_env_mut<'g>(&'g mut self, env_hash: EnvelopeHash) -> EnvelopeRefMut<'g> {
  312. let guard = self.envelopes.write().unwrap();
  313. EnvelopeRefMut { guard, env_hash }
  314. }
  315. pub fn contains_key(&self, env_hash: &EnvelopeHash) -> bool {
  316. self.envelopes.read().unwrap().contains_key(env_hash)
  317. }
  318. }