storage: person_list_2 database, records if entry is 'public'

This commit is contained in:
Mike Dilger 2023-10-17 10:09:53 +13:00
parent 204bb4c145
commit 4b0b0e1602
3 changed files with 162 additions and 1 deletions

View File

@ -27,6 +27,7 @@ mod hashtags1;
mod people1;
mod people2;
mod person_lists1;
mod person_lists2;
mod person_relays1;
mod relationships1;
mod relays1;

View File

@ -0,0 +1,158 @@
use super::types::PersonList1;
use crate::error::Error;
use crate::storage::{RawDatabase, Storage};
use heed::types::UnalignedSlice;
use heed::RwTxn;
use nostr_types::PublicKey;
use speedy::{Readable, Writable};
use std::collections::HashMap;
use std::sync::Mutex;
// Pubkey -> Vec<(PersonList, bool)> // bool is if private or not
// key: pubkey.as_bytes()
static PERSON_LISTS2_DB_CREATE_LOCK: Mutex<()> = Mutex::new(());
static mut PERSON_LISTS2_DB: Option<RawDatabase> = None;
impl Storage {
pub(super) fn db_person_lists2(&self) -> Result<RawDatabase, Error> {
unsafe {
if let Some(db) = PERSON_LISTS2_DB {
Ok(db)
} else {
// Lock. This drops when anything returns.
let _lock = PERSON_LISTS2_DB_CREATE_LOCK.lock();
// In case of a race, check again
if let Some(db) = PERSON_LISTS2_DB {
return Ok(db);
}
// Create it. We know that nobody else is doing this and that
// it cannot happen twice.
let mut txn = self.env.write_txn()?;
let db = self
.env
.database_options()
.types::<UnalignedSlice<u8>, UnalignedSlice<u8>>()
// no .flags needed
.name("person_lists_2")
.create(&mut txn)?;
txn.commit()?;
PERSON_LISTS2_DB = Some(db);
Ok(db)
}
}
}
pub(crate) fn read_person_lists2(
&self,
pubkey: &PublicKey,
) -> Result<HashMap<PersonList1, bool>, Error> {
let key: Vec<u8> = pubkey.to_bytes();
let txn = self.env.read_txn()?;
Ok(match self.db_person_lists2()?.get(&txn, &key)? {
None => HashMap::new(),
Some(bytes) => HashMap::<PersonList1, bool>::read_from_buffer(bytes)?,
})
}
pub(crate) fn write_person_lists2<'a>(
&'a self,
pubkey: &PublicKey,
map: HashMap<PersonList1, bool>,
rw_txn: Option<&mut RwTxn<'a>>,
) -> Result<(), Error> {
let key: Vec<u8> = pubkey.to_bytes();
let bytes: Vec<u8> = map.write_to_vec()?;
let f = |txn: &mut RwTxn<'a>| -> Result<(), Error> {
self.db_person_lists2()?.put(txn, &key, &bytes)?;
Ok(())
};
match rw_txn {
Some(txn) => f(txn)?,
None => {
let mut txn = self.env.write_txn()?;
f(&mut txn)?;
txn.commit()?;
}
};
Ok(())
}
pub(crate) fn get_people_in_list2(
&self,
list: PersonList1,
public: Option<bool>,
) -> Result<Vec<PublicKey>, Error> {
let txn = self.env.read_txn()?;
let mut pubkeys: Vec<PublicKey> = Vec::new();
for result in self.db_person_lists2()?.iter(&txn)? {
let (key, val) = result?;
let pubkey = PublicKey::from_bytes(key, true)?;
let map = HashMap::<PersonList1, bool>::read_from_buffer(val)?;
if let Some(p) = map.get(&list) {
match public {
Some(p2) => {
if p2 == *p {
pubkeys.push(pubkey);
}
}
None => {
pubkeys.push(pubkey);
}
}
}
}
Ok(pubkeys)
}
pub(crate) fn clear_person_list2<'a>(
&'a self,
list: PersonList1,
rw_txn: Option<&mut RwTxn<'a>>,
) -> Result<(), Error> {
let f = |txn: &mut RwTxn<'a>| -> Result<(), Error> {
let mut fixed: Vec<(PublicKey, HashMap<PersonList1, bool>)> = Vec::new();
// Collect records that require changing
// (lmdb doesn't like changing them in place while iterating)
for result in self.db_person_lists2()?.iter(txn)? {
let (key, val) = result?;
let pubkey = PublicKey::from_bytes(key, true)?;
let mut map = HashMap::<PersonList1, bool>::read_from_buffer(val)?;
if map.contains_key(&list) {
map.remove(&list);
fixed.push((pubkey, map));
}
}
// Change them
for (pubkey, map) in fixed.drain(..) {
let key: Vec<u8> = pubkey.to_bytes();
if map.is_empty() {
self.db_person_lists2()?.delete(txn, &key)?;
} else {
let bytes: Vec<u8> = map.write_to_vec()?;
self.db_person_lists2()?.put(txn, &key, &bytes)?;
}
}
Ok(())
};
match rw_txn {
Some(txn) => f(txn)?,
None => {
let mut txn = self.env.write_txn()?;
f(&mut txn)?;
txn.commit()?;
}
};
Ok(())
}
}

View File

@ -1,5 +1,7 @@
use speedy::{Readable, Writable};
/// Lists people can be added to
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Readable, Writable)]
#[repr(u8)]
pub enum PersonList1 {
Muted = 0,