mirror of
https://github.com/mikedilger/gossip.git
synced 2024-09-20 03:57:03 +00:00
storage: Migrate Relationships, added some, renamed, and rebuild them
This commit is contained in:
parent
8ca7dfeb06
commit
b271be11a8
@ -42,7 +42,7 @@ pub async fn process_new_event(
|
||||
let mut maxtime = now;
|
||||
maxtime.0 += GLOBALS.storage.read_setting_future_allowance_secs() as i64;
|
||||
if let Err(e) = event.verify(Some(maxtime)) {
|
||||
tracing::error!("{}: VERIFY ERROR: {}", e, serde_json::to_string(&event)?);
|
||||
tracing::warn!("{}: VERIFY ERROR: {}", e, serde_json::to_string(&event)?);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@ -121,7 +121,7 @@ pub async fn process_new_event(
|
||||
|
||||
// Ignore if the event is already deleted (by id)
|
||||
for (_id, relbyid) in GLOBALS.storage.find_relationships_by_id(event.id)? {
|
||||
if let RelationshipById::Deletion { by, reason: _ } = relbyid {
|
||||
if let RelationshipById::Deletes { by, reason: _ } = relbyid {
|
||||
if event.delete_author_allowed(by) {
|
||||
tracing::trace!(
|
||||
"{}: Deleted Event: {} {:?} @{}",
|
||||
@ -144,7 +144,7 @@ pub async fn process_new_event(
|
||||
author: event.pubkey,
|
||||
};
|
||||
for (_id, relbyaddr) in GLOBALS.storage.find_relationships_by_addr(&ea)? {
|
||||
if let RelationshipByAddr::Deletion { by, reason: _ } = relbyaddr {
|
||||
if let RelationshipByAddr::Deletes { by, reason: _ } = relbyaddr {
|
||||
if by == event.pubkey {
|
||||
tracing::trace!(
|
||||
"{}: Deleted Event: {} {:?} @{}",
|
||||
@ -483,25 +483,39 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
let mut invalidate: Vec<Id> = Vec::new();
|
||||
|
||||
let mut f = |txn: &mut RwTxn<'a>| -> Result<(), Error> {
|
||||
// replies to
|
||||
match event.replies_to() {
|
||||
Some(EventReference::Id { id, .. }) => {
|
||||
// Reposts
|
||||
if event.kind == EventKind::Repost {
|
||||
if let Ok(inner_event) = serde_json::from_str::<Event>(&event.content) {
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
id,
|
||||
inner_event.id,
|
||||
event.id,
|
||||
RelationshipById::Reply,
|
||||
RelationshipById::Reposts,
|
||||
Some(txn),
|
||||
)?;
|
||||
} else {
|
||||
for eref in event.mentions().iter() {
|
||||
if let EventReference::Id { id, .. } = eref {
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
*id,
|
||||
event.id,
|
||||
RelationshipById::Reposts,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Quotes
|
||||
for eref in event.quotes().iter() {
|
||||
if let EventReference::Id { id, .. } = eref {
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
*id,
|
||||
event.id,
|
||||
RelationshipById::Quotes,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
Some(EventReference::Addr(ea)) => {
|
||||
GLOBALS.storage.write_relationship_by_addr(
|
||||
ea,
|
||||
event.id,
|
||||
RelationshipByAddr::Reply,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
|
||||
// timestamps
|
||||
@ -511,7 +525,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
id,
|
||||
event.id,
|
||||
RelationshipById::Timestamp,
|
||||
RelationshipById::Timestamps,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -543,7 +557,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
*id,
|
||||
event.id,
|
||||
RelationshipById::Deletion {
|
||||
RelationshipById::Deletes {
|
||||
by: event.pubkey,
|
||||
reason: reason.clone(),
|
||||
},
|
||||
@ -574,7 +588,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_addr(
|
||||
ea.clone(),
|
||||
event.id,
|
||||
RelationshipByAddr::Deletion {
|
||||
RelationshipByAddr::Deletes {
|
||||
by: event.pubkey,
|
||||
reason: reason.clone(),
|
||||
},
|
||||
@ -591,7 +605,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
reacted_to_id, // event reacted to
|
||||
event.id, // the reaction event id
|
||||
RelationshipById::Reaction {
|
||||
RelationshipById::ReactsTo {
|
||||
by: event.pubkey,
|
||||
reaction,
|
||||
},
|
||||
@ -627,6 +641,16 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
},
|
||||
Some(txn),
|
||||
)?;
|
||||
} else if let Ok((ea, _marker)) = tag.parse_address() {
|
||||
GLOBALS.storage.write_relationship_by_addr(
|
||||
ea,
|
||||
event.id,
|
||||
RelationshipByAddr::Labels {
|
||||
label: label.to_owned(),
|
||||
namespace: namespace.to_owned(),
|
||||
},
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -638,7 +662,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
id,
|
||||
event.id,
|
||||
RelationshipById::ListMutesThread,
|
||||
RelationshipById::Mutes,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -652,7 +676,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
id,
|
||||
event.id,
|
||||
RelationshipById::ListPins,
|
||||
RelationshipById::Pins,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -666,7 +690,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
id,
|
||||
event.id,
|
||||
RelationshipById::ListBookmarks,
|
||||
RelationshipById::Bookmarks,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -675,7 +699,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_addr(
|
||||
ea,
|
||||
event.id,
|
||||
RelationshipByAddr::ListBookmarks,
|
||||
RelationshipByAddr::Bookmarks,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -689,7 +713,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
id,
|
||||
event.id,
|
||||
RelationshipById::ListBookmarks,
|
||||
RelationshipById::Bookmarks,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -698,7 +722,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_addr(
|
||||
ea,
|
||||
event.id,
|
||||
RelationshipByAddr::ListBookmarks,
|
||||
RelationshipByAddr::Bookmarks,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -712,7 +736,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
id,
|
||||
event.id,
|
||||
RelationshipById::Curation,
|
||||
RelationshipById::Curates,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -720,7 +744,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_addr(
|
||||
ea,
|
||||
event.id,
|
||||
RelationshipByAddr::Curation,
|
||||
RelationshipByAddr::Curates,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -733,7 +757,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_addr(
|
||||
ea,
|
||||
event.id,
|
||||
RelationshipByAddr::LiveChatMessage,
|
||||
RelationshipByAddr::ChatsWithin,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -746,7 +770,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_addr(
|
||||
ea,
|
||||
event.id,
|
||||
RelationshipByAddr::BadgeAward,
|
||||
RelationshipByAddr::AwardsBadge,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -759,7 +783,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_addr(
|
||||
ea,
|
||||
event.id,
|
||||
RelationshipByAddr::HandlerRecommendation,
|
||||
RelationshipByAddr::RecommendsHandler,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
@ -786,7 +810,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
zapdata.id,
|
||||
event.id,
|
||||
RelationshipById::ZapReceipt {
|
||||
RelationshipById::Zaps {
|
||||
by: event.pubkey,
|
||||
amount: zapdata.amount,
|
||||
},
|
||||
@ -795,7 +819,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
|
||||
invalidate.push(zapdata.id);
|
||||
}
|
||||
Err(e) => tracing::error!("Invalid zap receipt: {}", e),
|
||||
Err(e) => tracing::warn!("Invalid zap receipt: {}", e),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@ -806,7 +830,7 @@ pub(crate) fn process_relationships_of_event<'a>(
|
||||
GLOBALS.storage.write_relationship_by_id(
|
||||
id,
|
||||
event.id,
|
||||
RelationshipById::JobResult,
|
||||
RelationshipById::SuppliesJobResult,
|
||||
Some(txn),
|
||||
)?;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/// Relationship type by Id, aliased to the latest version
|
||||
pub type RelationshipById = crate::storage::types::RelationshipById1;
|
||||
pub type RelationshipById = crate::storage::types::RelationshipById2;
|
||||
|
||||
/// Relationship type by EventAddr, aliased to the latest version
|
||||
pub type RelationshipByAddr = crate::storage::types::RelationshipByAddr1;
|
||||
pub type RelationshipByAddr = crate::storage::types::RelationshipByAddr2;
|
||||
|
38
gossip-lib/src/storage/migrations/m32.rs
Normal file
38
gossip-lib/src/storage/migrations/m32.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use crate::error::Error;
|
||||
use crate::storage::Storage;
|
||||
use heed::RwTxn;
|
||||
|
||||
impl Storage {
|
||||
pub(super) fn m32_trigger(&self) -> Result<(), Error> {
|
||||
let _ = self.db_relationships_by_id1()?;
|
||||
let _ = self.db_relationships_by_id2()?;
|
||||
let _ = self.db_relationships_by_addr1()?;
|
||||
let _ = self.db_relationships_by_addr2()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn m32_migrate<'a>(
|
||||
&'a self,
|
||||
prefix: &str,
|
||||
txn: &mut RwTxn<'a>,
|
||||
) -> Result<(), Error> {
|
||||
// Info message
|
||||
tracing::info!("{prefix}: Migrating relationship data to new type...");
|
||||
|
||||
// Migrate
|
||||
self.m32_migrate_relationship_data(txn)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn m32_migrate_relationship_data<'a>(&'a self, txn: &mut RwTxn<'a>) -> Result<(), Error> {
|
||||
// Clear the old relationships data
|
||||
self.db_relationships_by_id1()?.clear(txn)?;
|
||||
self.db_relationships_by_addr1()?.clear(txn)?;
|
||||
|
||||
// Rebuild relationships
|
||||
self.set_flag_rebuild_relationships_needed(true, Some(txn))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ mod m29;
|
||||
mod m3;
|
||||
mod m30;
|
||||
mod m31;
|
||||
mod m32;
|
||||
mod m4;
|
||||
mod m5;
|
||||
mod m6;
|
||||
@ -37,7 +38,7 @@ use crate::error::{Error, ErrorKind};
|
||||
use heed::RwTxn;
|
||||
|
||||
impl Storage {
|
||||
const MAX_MIGRATION_LEVEL: u32 = 31;
|
||||
const MAX_MIGRATION_LEVEL: u32 = 32;
|
||||
|
||||
/// Initialize the database from empty
|
||||
pub(super) fn init_from_empty(&self) -> Result<(), Error> {
|
||||
@ -123,6 +124,7 @@ impl Storage {
|
||||
29 => self.m29_trigger()?,
|
||||
30 => self.m30_trigger()?,
|
||||
31 => self.m31_trigger()?,
|
||||
32 => self.m32_trigger()?,
|
||||
_ => panic!("Unreachable migration level"),
|
||||
}
|
||||
|
||||
@ -163,6 +165,7 @@ impl Storage {
|
||||
29 => self.m29_migrate(&prefix, txn)?,
|
||||
30 => self.m30_migrate(&prefix, txn)?,
|
||||
31 => self.m31_migrate(&prefix, txn)?,
|
||||
32 => self.m32_migrate(&prefix, txn)?,
|
||||
_ => panic!("Unreachable migration level"),
|
||||
};
|
||||
|
||||
|
@ -42,7 +42,9 @@ mod person_lists_metadata3;
|
||||
mod person_relays1;
|
||||
mod relationships1;
|
||||
mod relationships_by_addr1;
|
||||
mod relationships_by_addr2;
|
||||
mod relationships_by_id1;
|
||||
mod relationships_by_id2;
|
||||
mod relays1;
|
||||
mod relays2;
|
||||
mod reprel1;
|
||||
@ -323,12 +325,12 @@ impl Storage {
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn db_relationships_by_addr(&self) -> Result<RawDatabase, Error> {
|
||||
self.db_relationships_by_addr1()
|
||||
self.db_relationships_by_addr2()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn db_relationships_by_id(&self) -> Result<RawDatabase, Error> {
|
||||
self.db_relationships_by_id1()
|
||||
self.db_relationships_by_id2()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -1892,7 +1894,7 @@ impl Storage {
|
||||
relationship_by_id: RelationshipById,
|
||||
rw_txn: Option<&mut RwTxn<'a>>,
|
||||
) -> Result<(), Error> {
|
||||
self.write_relationship_by_id1(id, related, relationship_by_id, rw_txn)
|
||||
self.write_relationship_by_id2(id, related, relationship_by_id, rw_txn)
|
||||
}
|
||||
|
||||
/// Find relationships belonging to the given event
|
||||
@ -1901,7 +1903,7 @@ impl Storage {
|
||||
/// e.g. result id replies to id, or result id deletes id
|
||||
#[inline]
|
||||
pub fn find_relationships_by_id(&self, id: Id) -> Result<Vec<(Id, RelationshipById)>, Error> {
|
||||
self.find_relationships_by_id1(id)
|
||||
self.find_relationships_by_id2(id)
|
||||
}
|
||||
|
||||
/// Write a relationship between an event and an EventAddr (replaceable)
|
||||
@ -1913,7 +1915,7 @@ impl Storage {
|
||||
relationship_by_addr: RelationshipByAddr,
|
||||
rw_txn: Option<&mut RwTxn<'a>>,
|
||||
) -> Result<(), Error> {
|
||||
self.write_relationship_by_addr1(addr, related, relationship_by_addr, rw_txn)
|
||||
self.write_relationship_by_addr2(addr, related, relationship_by_addr, rw_txn)
|
||||
}
|
||||
|
||||
/// Find relationships belonging to the given event to replaceable events
|
||||
@ -1922,7 +1924,7 @@ impl Storage {
|
||||
&self,
|
||||
addr: &EventAddr,
|
||||
) -> Result<Vec<(Id, RelationshipByAddr)>, Error> {
|
||||
self.find_relationships_by_addr1(addr)
|
||||
self.find_relationships_by_addr2(addr)
|
||||
}
|
||||
|
||||
/// Get replies to the given event
|
||||
@ -1942,7 +1944,7 @@ impl Storage {
|
||||
.find_relationships_by_id(id)?
|
||||
.iter()
|
||||
.filter_map(|(id, rel)| {
|
||||
if *rel == RelationshipById::Reply {
|
||||
if *rel == RelationshipById::RepliesTo {
|
||||
Some(*id)
|
||||
} else {
|
||||
None
|
||||
@ -1956,7 +1958,7 @@ impl Storage {
|
||||
.find_relationships_by_addr(addr)?
|
||||
.iter()
|
||||
.filter_map(|(id, rel)| {
|
||||
if *rel == RelationshipByAddr::Reply {
|
||||
if *rel == RelationshipByAddr::RepliesTo {
|
||||
Some(*id)
|
||||
} else {
|
||||
None
|
||||
@ -1976,7 +1978,7 @@ impl Storage {
|
||||
// Collect up to one reaction per pubkey
|
||||
let mut phase1: HashMap<PublicKey, char> = HashMap::new();
|
||||
for (_, rel) in self.find_relationships_by_id(id)? {
|
||||
if let RelationshipById::Reaction { by, reaction } = rel {
|
||||
if let RelationshipById::ReactsTo { by, reaction } = rel {
|
||||
if let Some(target_event) = &maybe_target_event {
|
||||
if target_event.pubkey == by {
|
||||
// Do not let people like their own post
|
||||
@ -2013,7 +2015,7 @@ impl Storage {
|
||||
pub fn get_zap_total(&self, id: Id) -> Result<MilliSatoshi, Error> {
|
||||
let mut total = MilliSatoshi(0);
|
||||
for (_, rel) in self.find_relationships_by_id(id)? {
|
||||
if let RelationshipById::ZapReceipt { by: _, amount } = rel {
|
||||
if let RelationshipById::Zaps { by: _, amount } = rel {
|
||||
total = total + amount;
|
||||
}
|
||||
}
|
||||
@ -2025,7 +2027,7 @@ impl Storage {
|
||||
let mut reasons: Vec<String> = Vec::new();
|
||||
|
||||
for (deleting_id, rel) in self.find_relationships_by_id(maybe_deleted_event.id)? {
|
||||
if let RelationshipById::Deletion { by, reason } = rel {
|
||||
if let RelationshipById::Deletes { by, reason } = rel {
|
||||
if maybe_deleted_event.delete_author_allowed(by) {
|
||||
// We must have the deletion event to check it
|
||||
if let Some(deleting_event) = self.read_event(deleting_id)? {
|
||||
@ -2048,7 +2050,7 @@ impl Storage {
|
||||
};
|
||||
for (deleting_id, rel) in self.find_relationships_by_addr(&addr)? {
|
||||
// Must be a deletion relationship
|
||||
if let RelationshipByAddr::Deletion { by, reason } = rel {
|
||||
if let RelationshipByAddr::Deletes { by, reason } = rel {
|
||||
if maybe_deleted_event.delete_author_allowed(by) {
|
||||
// We must have the deletion event to check it
|
||||
if let Some(deleting_event) = self.read_event(deleting_id)? {
|
||||
|
@ -1,10 +1,6 @@
|
||||
use crate::error::Error;
|
||||
use crate::storage::types::RelationshipByAddr1;
|
||||
use crate::storage::{RawDatabase, Storage};
|
||||
use heed::RwTxn;
|
||||
use heed::{types::UnalignedSlice, DatabaseFlags};
|
||||
use nostr_types::{EventAddr, Id};
|
||||
use speedy::{Readable, Writable};
|
||||
use std::sync::Mutex;
|
||||
|
||||
// Kind:Pubkey:d-tag -> RelationshipByAddr1:Id
|
||||
@ -43,91 +39,4 @@ impl Storage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write_relationship_by_addr1<'a>(
|
||||
&'a self,
|
||||
addr: EventAddr,
|
||||
related: Id,
|
||||
relationship_by_addr: RelationshipByAddr1,
|
||||
rw_txn: Option<&mut RwTxn<'a>>,
|
||||
) -> Result<(), Error> {
|
||||
let key = relationships_by_addr1_into_key(&addr);
|
||||
let value = relationships_by_addr1_into_value(relationship_by_addr, related)?;
|
||||
let f = |txn: &mut RwTxn<'a>| -> Result<(), Error> {
|
||||
self.db_relationships_by_addr1()?.put(txn, &key, &value)?;
|
||||
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 find_relationships_by_addr1(
|
||||
&self,
|
||||
addr: &EventAddr,
|
||||
) -> Result<Vec<(Id, RelationshipByAddr1)>, Error> {
|
||||
let key = relationships_by_addr1_into_key(addr);
|
||||
let txn = self.env.read_txn()?;
|
||||
let iter = match self
|
||||
.db_relationships_by_addr1()?
|
||||
.get_duplicates(&txn, &key)?
|
||||
{
|
||||
Some(iter) => iter,
|
||||
None => return Ok(vec![]),
|
||||
};
|
||||
let mut output: Vec<(Id, RelationshipByAddr1)> = Vec::new();
|
||||
for result in iter {
|
||||
let (_key, val) = result?;
|
||||
let (rel, id) = relationships_by_addr1_from_value(val)?;
|
||||
output.push((id, rel));
|
||||
}
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
||||
fn relationships_by_addr1_into_key(ea: &EventAddr) -> Vec<u8> {
|
||||
let u: u32 = ea.kind.into();
|
||||
let mut key: Vec<u8> = u.to_be_bytes().as_slice().to_owned();
|
||||
key.extend(ea.author.as_bytes());
|
||||
key.extend(ea.d.as_bytes());
|
||||
key
|
||||
}
|
||||
|
||||
/*
|
||||
fn relationships_by_addr1_from_key(key: &[u8]) -> Result<EventAddr, Error> {
|
||||
let u = u32::from_be_bytes(key[..4].try_into().unwrap());
|
||||
let kind: EventKind = u.into();
|
||||
let pubkey: PublicKey = PublicKey::from_bytes(&key[4..4+32], true)?;
|
||||
let d: String = String::from_utf8_lossy(&key[4+32..]).to_string();
|
||||
Ok(EventAddr {
|
||||
d,
|
||||
relays: vec![],
|
||||
kind,
|
||||
author: pubkey
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
fn relationships_by_addr1_into_value(
|
||||
relationship_by_addr: RelationshipByAddr1,
|
||||
id: Id,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let mut value: Vec<u8> = relationship_by_addr.write_to_vec()?;
|
||||
value.extend(id.as_slice());
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn relationships_by_addr1_from_value(value: &[u8]) -> Result<(RelationshipByAddr1, Id), Error> {
|
||||
let (result, len) = RelationshipByAddr1::read_with_length_from_buffer(value);
|
||||
let relationship_by_addr = result?;
|
||||
let id = Id(value[len..len + 32].try_into().unwrap());
|
||||
Ok((relationship_by_addr, id))
|
||||
}
|
||||
|
133
gossip-lib/src/storage/relationships_by_addr2.rs
Normal file
133
gossip-lib/src/storage/relationships_by_addr2.rs
Normal file
@ -0,0 +1,133 @@
|
||||
use crate::error::Error;
|
||||
use crate::storage::types::RelationshipByAddr2;
|
||||
use crate::storage::{RawDatabase, Storage};
|
||||
use heed::RwTxn;
|
||||
use heed::{types::UnalignedSlice, DatabaseFlags};
|
||||
use nostr_types::{EventAddr, Id};
|
||||
use speedy::{Readable, Writable};
|
||||
use std::sync::Mutex;
|
||||
|
||||
// Kind:Pubkey:d-tag -> RelationshipByAddr2:Id
|
||||
// (has dups)
|
||||
|
||||
static RELATIONSHIPS_BY_ADDR2_DB_CREATE_LOCK: Mutex<()> = Mutex::new(());
|
||||
static mut RELATIONSHIPS_BY_ADDR2_DB: Option<RawDatabase> = None;
|
||||
|
||||
impl Storage {
|
||||
pub(super) fn db_relationships_by_addr2(&self) -> Result<RawDatabase, Error> {
|
||||
unsafe {
|
||||
if let Some(db) = RELATIONSHIPS_BY_ADDR2_DB {
|
||||
Ok(db)
|
||||
} else {
|
||||
// Lock. This drops when anything returns.
|
||||
let _lock = RELATIONSHIPS_BY_ADDR2_DB_CREATE_LOCK.lock();
|
||||
|
||||
// In case of a race, check again
|
||||
if let Some(db) = RELATIONSHIPS_BY_ADDR2_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>>()
|
||||
.flags(DatabaseFlags::DUP_SORT) // NOT FIXED, RelationshipByAddr2 serialized isn't.
|
||||
.name("relationships_by_addr2")
|
||||
.create(&mut txn)?;
|
||||
txn.commit()?;
|
||||
RELATIONSHIPS_BY_ADDR2_DB = Some(db);
|
||||
Ok(db)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write_relationship_by_addr2<'a>(
|
||||
&'a self,
|
||||
addr: EventAddr,
|
||||
related: Id,
|
||||
relationship_by_addr: RelationshipByAddr2,
|
||||
rw_txn: Option<&mut RwTxn<'a>>,
|
||||
) -> Result<(), Error> {
|
||||
let key = relationships_by_addr2_into_key(&addr);
|
||||
let value = relationships_by_addr2_into_value(relationship_by_addr, related)?;
|
||||
let f = |txn: &mut RwTxn<'a>| -> Result<(), Error> {
|
||||
self.db_relationships_by_addr2()?.put(txn, &key, &value)?;
|
||||
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 find_relationships_by_addr2(
|
||||
&self,
|
||||
addr: &EventAddr,
|
||||
) -> Result<Vec<(Id, RelationshipByAddr2)>, Error> {
|
||||
let key = relationships_by_addr2_into_key(addr);
|
||||
let txn = self.env.read_txn()?;
|
||||
let iter = match self
|
||||
.db_relationships_by_addr2()?
|
||||
.get_duplicates(&txn, &key)?
|
||||
{
|
||||
Some(iter) => iter,
|
||||
None => return Ok(vec![]),
|
||||
};
|
||||
let mut output: Vec<(Id, RelationshipByAddr2)> = Vec::new();
|
||||
for result in iter {
|
||||
let (_key, val) = result?;
|
||||
let (rel, id) = relationships_by_addr2_from_value(val)?;
|
||||
output.push((id, rel));
|
||||
}
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
||||
fn relationships_by_addr2_into_key(ea: &EventAddr) -> Vec<u8> {
|
||||
let u: u32 = ea.kind.into();
|
||||
let mut key: Vec<u8> = u.to_be_bytes().as_slice().to_owned();
|
||||
key.extend(ea.author.as_bytes());
|
||||
key.extend(ea.d.as_bytes());
|
||||
key
|
||||
}
|
||||
|
||||
/*
|
||||
fn relationships_by_addr2_from_key(key: &[u8]) -> Result<EventAddr, Error> {
|
||||
let u = u32::from_be_bytes(key[..4].try_into().unwrap());
|
||||
let kind: EventKind = u.into();
|
||||
let pubkey: PublicKey = PublicKey::from_bytes(&key[4..4+32], true)?;
|
||||
let d: String = String::from_utf8_lossy(&key[4+32..]).to_string();
|
||||
Ok(EventAddr {
|
||||
d,
|
||||
relays: vec![],
|
||||
kind,
|
||||
author: pubkey
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
fn relationships_by_addr2_into_value(
|
||||
relationship_by_addr: RelationshipByAddr2,
|
||||
id: Id,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let mut value: Vec<u8> = relationship_by_addr.write_to_vec()?;
|
||||
value.extend(id.as_slice());
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn relationships_by_addr2_from_value(value: &[u8]) -> Result<(RelationshipByAddr2, Id), Error> {
|
||||
let (result, len) = RelationshipByAddr2::read_with_length_from_buffer(value);
|
||||
let relationship_by_addr = result?;
|
||||
let id = Id(value[len..len + 32].try_into().unwrap());
|
||||
Ok((relationship_by_addr, id))
|
||||
}
|
@ -1,10 +1,6 @@
|
||||
use crate::error::Error;
|
||||
use crate::storage::types::RelationshipById1;
|
||||
use crate::storage::{RawDatabase, Storage};
|
||||
use heed::types::UnalignedSlice;
|
||||
use heed::RwTxn;
|
||||
use nostr_types::Id;
|
||||
use speedy::{Readable, Writable};
|
||||
use std::sync::Mutex;
|
||||
|
||||
// Id:Id -> RelationshipById1
|
||||
@ -50,51 +46,4 @@ impl Storage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write_relationship_by_id1<'a>(
|
||||
&'a self,
|
||||
id: Id,
|
||||
related: Id,
|
||||
relationship_by_id: RelationshipById1,
|
||||
rw_txn: Option<&mut RwTxn<'a>>,
|
||||
) -> Result<(), Error> {
|
||||
let mut key = id.as_ref().as_slice().to_owned();
|
||||
key.extend(related.as_ref());
|
||||
let value = relationship_by_id.write_to_vec()?;
|
||||
|
||||
let f = |txn: &mut RwTxn<'a>| -> Result<(), Error> {
|
||||
self.db_relationships_by_id1()?.put(txn, &key, &value)?;
|
||||
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 find_relationships_by_id1(
|
||||
&self,
|
||||
id: Id,
|
||||
) -> Result<Vec<(Id, RelationshipById1)>, Error> {
|
||||
let start_key = id.as_slice();
|
||||
let txn = self.env.read_txn()?;
|
||||
let iter = self
|
||||
.db_relationships_by_id1()?
|
||||
.prefix_iter(&txn, start_key)?;
|
||||
let mut output: Vec<(Id, RelationshipById1)> = Vec::new();
|
||||
for result in iter {
|
||||
let (key, val) = result?;
|
||||
let id2 = Id(key[32..64].try_into().unwrap());
|
||||
let relationship_by_id = RelationshipById1::read_from_buffer(val)?;
|
||||
output.push((id2, relationship_by_id));
|
||||
}
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
100
gossip-lib/src/storage/relationships_by_id2.rs
Normal file
100
gossip-lib/src/storage/relationships_by_id2.rs
Normal file
@ -0,0 +1,100 @@
|
||||
use crate::error::Error;
|
||||
use crate::storage::types::RelationshipById2;
|
||||
use crate::storage::{RawDatabase, Storage};
|
||||
use heed::types::UnalignedSlice;
|
||||
use heed::RwTxn;
|
||||
use nostr_types::Id;
|
||||
use speedy::{Readable, Writable};
|
||||
use std::sync::Mutex;
|
||||
|
||||
// Id:Id -> RelationshipById2
|
||||
// key: id.as_slice(), id.as_slice() | Id(val[32..64].try_into()?)
|
||||
// val: relationship_by_id.write_to_vec() | RelationshipById2::read_from_buffer(val)
|
||||
|
||||
// NOTE: this means the SECOND Id relates to the FIRST Id, e.g.
|
||||
// id2 replies to id1
|
||||
// id2 reacts to id1
|
||||
// id2 deletes id1
|
||||
// id2 is a zap receipt on id1
|
||||
|
||||
static RELATIONSHIPS_BY_ID2_DB_CREATE_LOCK: Mutex<()> = Mutex::new(());
|
||||
static mut RELATIONSHIPS_BY_ID2_DB: Option<RawDatabase> = None;
|
||||
|
||||
impl Storage {
|
||||
pub(super) fn db_relationships_by_id2(&self) -> Result<RawDatabase, Error> {
|
||||
unsafe {
|
||||
if let Some(db) = RELATIONSHIPS_BY_ID2_DB {
|
||||
Ok(db)
|
||||
} else {
|
||||
// Lock. This drops when anything returns.
|
||||
let _lock = RELATIONSHIPS_BY_ID2_DB_CREATE_LOCK.lock();
|
||||
|
||||
// In case of a race, check again
|
||||
if let Some(db) = RELATIONSHIPS_BY_ID2_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("relationships_by_id2")
|
||||
.create(&mut txn)?;
|
||||
txn.commit()?;
|
||||
RELATIONSHIPS_BY_ID2_DB = Some(db);
|
||||
Ok(db)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write_relationship_by_id2<'a>(
|
||||
&'a self,
|
||||
id: Id,
|
||||
related: Id,
|
||||
relationship_by_id: RelationshipById2,
|
||||
rw_txn: Option<&mut RwTxn<'a>>,
|
||||
) -> Result<(), Error> {
|
||||
let mut key = id.as_ref().as_slice().to_owned();
|
||||
key.extend(related.as_ref());
|
||||
let value = relationship_by_id.write_to_vec()?;
|
||||
|
||||
let f = |txn: &mut RwTxn<'a>| -> Result<(), Error> {
|
||||
self.db_relationships_by_id2()?.put(txn, &key, &value)?;
|
||||
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 find_relationships_by_id2(
|
||||
&self,
|
||||
id: Id,
|
||||
) -> Result<Vec<(Id, RelationshipById2)>, Error> {
|
||||
let start_key = id.as_slice();
|
||||
let txn = self.env.read_txn()?;
|
||||
let iter = self
|
||||
.db_relationships_by_id2()?
|
||||
.prefix_iter(&txn, start_key)?;
|
||||
let mut output: Vec<(Id, RelationshipById2)> = Vec::new();
|
||||
for result in iter {
|
||||
let (key, val) = result?;
|
||||
let id2 = Id(key[32..64].try_into().unwrap());
|
||||
let relationship_by_id = RelationshipById2::read_from_buffer(val)?;
|
||||
output.push((id2, relationship_by_id));
|
||||
}
|
||||
Ok(output)
|
||||
}
|
||||
}
|
@ -25,9 +25,15 @@ pub use relationship1::Relationship1;
|
||||
mod relationship_by_addr1;
|
||||
pub use relationship_by_addr1::RelationshipByAddr1;
|
||||
|
||||
mod relationship_by_addr2;
|
||||
pub use relationship_by_addr2::RelationshipByAddr2;
|
||||
|
||||
mod relationship_by_id1;
|
||||
pub use relationship_by_id1::RelationshipById1;
|
||||
|
||||
mod relationship_by_id2;
|
||||
pub use relationship_by_id2::RelationshipById2;
|
||||
|
||||
mod relay1;
|
||||
pub use relay1::Relay1;
|
||||
|
||||
|
57
gossip-lib/src/storage/types/relationship_by_addr2.rs
Normal file
57
gossip-lib/src/storage/types/relationship_by_addr2.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use super::RelationshipByAddr1;
|
||||
use nostr_types::PublicKey;
|
||||
use speedy::{Readable, Writable};
|
||||
|
||||
/// A relationship between events by Address and Id
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Readable, Writable)]
|
||||
pub enum RelationshipByAddr2 {
|
||||
// NIP-01, NIP-10 replies
|
||||
RepliesTo,
|
||||
|
||||
// Annotation
|
||||
Annotates,
|
||||
|
||||
// NIP-09 Event Deletion
|
||||
Deletes { by: PublicKey, reason: String },
|
||||
|
||||
// NIP-32 Labeling
|
||||
Labels { label: String, namespace: String },
|
||||
|
||||
// NIP-51 Lists
|
||||
Bookmarks,
|
||||
|
||||
// NIP-51 Lists
|
||||
Curates,
|
||||
|
||||
// communities
|
||||
// interests
|
||||
// emojis
|
||||
|
||||
// NIP-53
|
||||
ChatsWithin,
|
||||
|
||||
// NIP-58
|
||||
AwardsBadge,
|
||||
|
||||
// NIP-72 Moderated Communities (Reddit-style)
|
||||
// CommunityPostsWithin,
|
||||
|
||||
// NIP-89 Recommended Application Handlers
|
||||
RecommendsHandler,
|
||||
}
|
||||
|
||||
impl From<RelationshipByAddr1> for RelationshipByAddr2 {
|
||||
fn from(one: RelationshipByAddr1) -> RelationshipByAddr2 {
|
||||
match one {
|
||||
RelationshipByAddr1::Reply => RelationshipByAddr2::RepliesTo,
|
||||
RelationshipByAddr1::Deletion { by, reason } => {
|
||||
RelationshipByAddr2::Deletes { by, reason }
|
||||
}
|
||||
RelationshipByAddr1::ListBookmarks => RelationshipByAddr2::Bookmarks,
|
||||
RelationshipByAddr1::Curation => RelationshipByAddr2::Curates,
|
||||
RelationshipByAddr1::LiveChatMessage => RelationshipByAddr2::ChatsWithin,
|
||||
RelationshipByAddr1::BadgeAward => RelationshipByAddr2::AwardsBadge,
|
||||
RelationshipByAddr1::HandlerRecommendation => RelationshipByAddr2::RecommendsHandler,
|
||||
}
|
||||
}
|
||||
}
|
78
gossip-lib/src/storage/types/relationship_by_id2.rs
Normal file
78
gossip-lib/src/storage/types/relationship_by_id2.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use super::RelationshipById1;
|
||||
use nostr_types::{MilliSatoshi, PublicKey};
|
||||
use speedy::{Readable, Writable};
|
||||
|
||||
/// A relationship between events by Ids
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Readable, Writable)]
|
||||
pub enum RelationshipById2 {
|
||||
// NIP-01, NIP-10 replies
|
||||
RepliesTo,
|
||||
|
||||
// Annotation
|
||||
Annotates,
|
||||
|
||||
// NIP-18 Reposts
|
||||
Reposts,
|
||||
|
||||
// NIP-18 Quotes
|
||||
Quotes,
|
||||
|
||||
// NIP-03 OpenTimestamps Attestations for Events
|
||||
Timestamps,
|
||||
|
||||
// NIP-09 Event Deletion
|
||||
Deletes { by: PublicKey, reason: String },
|
||||
|
||||
// NIP-25 Reactions
|
||||
ReactsTo { by: PublicKey, reaction: String },
|
||||
|
||||
// NIP-32 Labeling
|
||||
Labels { label: String, namespace: String },
|
||||
|
||||
// NIP-51 Lists
|
||||
Mutes,
|
||||
|
||||
// NIP-51 Lists
|
||||
Pins,
|
||||
|
||||
// NIP-51 Lists
|
||||
Bookmarks,
|
||||
|
||||
// NIP-51 Lists
|
||||
Curates,
|
||||
|
||||
// NIP-56 Reporting
|
||||
Reports(String),
|
||||
|
||||
// NIP-57 Lightning Zaps
|
||||
Zaps { by: PublicKey, amount: MilliSatoshi },
|
||||
|
||||
// NIP-72 Moderated Communities (Reddit-style)
|
||||
// Approves { in_community: EventAddr },
|
||||
|
||||
// NIP-90 Data Vending Machines
|
||||
SuppliesJobResult,
|
||||
}
|
||||
|
||||
impl From<RelationshipById1> for RelationshipById2 {
|
||||
fn from(one: RelationshipById1) -> RelationshipById2 {
|
||||
match one {
|
||||
RelationshipById1::Reply => RelationshipById2::RepliesTo,
|
||||
RelationshipById1::Timestamp => RelationshipById2::Timestamps,
|
||||
RelationshipById1::Deletion { by, reason } => RelationshipById2::Deletes { by, reason },
|
||||
RelationshipById1::Reaction { by, reaction } => {
|
||||
RelationshipById2::ReactsTo { by, reaction }
|
||||
}
|
||||
RelationshipById1::Labels { label, namespace } => {
|
||||
RelationshipById2::Labels { label, namespace }
|
||||
}
|
||||
RelationshipById1::ListMutesThread => RelationshipById2::Mutes,
|
||||
RelationshipById1::ListPins => RelationshipById2::Pins,
|
||||
RelationshipById1::ListBookmarks => RelationshipById2::Bookmarks,
|
||||
RelationshipById1::Curation => RelationshipById2::Curates,
|
||||
RelationshipById1::Reports(s) => RelationshipById2::Reports(s),
|
||||
RelationshipById1::ZapReceipt { by, amount } => RelationshipById2::Zaps { by, amount },
|
||||
RelationshipById1::JobResult => RelationshipById2::SuppliesJobResult,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user