update publish community

This commit is contained in:
2026-09-19 09:27:41 +07:00
parent 9a391ca76d
commit 97e7539cea
5 changed files with 520 additions and 68 deletions
+30 -3
View File
@@ -132,6 +132,30 @@ impl CommunityList {
(0..self.frags).all(|index| held.contains(&index))
}
pub fn joined(&self, entry: CommunityListEntry) -> CommunityList {
merge(
self.clone(),
CommunityList {
entries: vec![entry],
..Default::default()
},
)
}
pub fn tombstoned(&self, community_id: CommunityId, removed_at: u64) -> CommunityList {
merge(
self.clone(),
CommunityList {
tombstones: vec![Tombstone {
community_id,
removed_at,
extra: Extra::default(),
}],
..Default::default()
},
)
}
pub fn fits(&self) -> Result<(), ListError> {
if self.entries.len() > MAX_MEMBERSHIPS {
return Err(ListError::TooManyMemberships(self.entries.len()));
@@ -207,6 +231,7 @@ pub async fn build_list_event<S>(
signer: &S,
list: &CommunityList,
fragment: u64,
at_secs: u64,
) -> Result<Event, ListError>
where
S: AsyncGetPublicKey + AsyncSignEvent + AsyncNip44 + ?Sized,
@@ -218,6 +243,7 @@ where
EventBuilder::new(Kind::Custom(KIND_COMMUNITY_LIST), content)
.tag(Tag::identifier(fragment.to_string()))
.custom_created_at(Timestamp::from_secs(at_secs))
.finalize_async(signer)
.await
.map_err(crypto_error)
@@ -816,7 +842,7 @@ mod tests {
..Default::default()
};
let event = smol::block_on(build_list_event(&me, &mine, 1)).expect("builds");
let event = smol::block_on(build_list_event(&me, &mine, 1, AT_SECS)).expect("builds");
assert_eq!(event.kind, Kind::Custom(KIND_COMMUNITY_LIST));
assert_eq!(fragment_index(&event).expect("a fragment index"), 1);
assert_eq!(
@@ -858,7 +884,7 @@ mod tests {
.insert("read_key".to_owned(), serde_json::json!("aa".repeat(32)));
let rebuilt = smol::block_on(parse_list_event(
&me,
&smol::block_on(build_list_event(&me, &held, 0)).expect("builds"),
&smol::block_on(build_list_event(&me, &held, 0, AT_SECS)).expect("builds"),
))
.expect("parses");
assert_eq!(rebuilt, held);
@@ -878,7 +904,7 @@ mod tests {
.collect(),
);
assert!(matches!(
smol::block_on(build_list_event(&me, &crowded, 0)),
smol::block_on(build_list_event(&me, &crowded, 0, AT_SECS)),
Err(ListError::TooManyMemberships(n)) if n == MAX_MEMBERSHIPS + 1
));
@@ -1019,4 +1045,5 @@ mod tests {
}
const AT: u64 = 1_719_800_000_000;
const AT_SECS: u64 = AT / 1000;
}
+38 -2
View File
@@ -3,18 +3,20 @@ use std::collections::{BTreeMap, BTreeSet};
use std::sync::LazyLock;
use anyhow::{Result, anyhow};
use data_encoding::HEXLOWER;
use nostr_sdk::prelude::*;
use serde::{Deserialize, Serialize};
use crate::cord01::{KIND_WRAP_EPHEMERAL, OpenedStream};
use crate::cord02::list::JoinMaterial;
use crate::cord02::list::{CommunityListEntry, JoinMaterial};
use crate::cord02::{
ChannelMetadata, CommunityGenesis, CommunityMetadata, ControlFold, ROOT_EPOCH,
};
use crate::cord03::{self, ChatRumor, plane_keys};
use crate::cord04::{EntityHead, Floors, ParsedEdition, vsk};
use crate::cord05::ChannelGrant;
use crate::derive::control_signer_group_key;
use crate::{ChannelId, CommunityId, Epoch, GroupKey, decode_hex_32};
use crate::{ChannelId, CommunityId, Epoch, Extra, GroupKey, decode_hex_32};
static LOCAL_KEYS: LazyLock<Keys> = LazyLock::new(Keys::generate);
@@ -337,6 +339,40 @@ impl CommunityState {
}
}
pub fn list_entry(state: &CommunityState, name: &str) -> CommunityListEntry {
let material = JoinMaterial {
community_id: state.id,
owner: state.owner,
owner_salt: HEXLOWER.encode(&state.owner_salt),
community_root: HEXLOWER.encode(&state.community_root),
root_epoch: state.root_epoch,
control_pk: state.control_pks.get(&state.root_epoch.0).copied(),
control_root: state.control_root.map(|root| HEXLOWER.encode(&root)),
channels: state
.channels
.iter()
.map(|channel| ChannelGrant {
id: channel.id,
key: channel.key.map(|key| HEXLOWER.encode(&key)),
epoch: channel.epoch,
name: channel.name.clone(),
extra: Extra::default(),
})
.collect(),
relays: state.relays.iter().map(RelayUrl::to_string).collect(),
name: name.to_owned(),
extra: Extra::default(),
};
CommunityListEntry {
community_id: state.id,
seed: material.clone(),
current: material,
added_at: state.added_at_ms,
extra: Extra::default(),
}
}
fn state_identifier(id: &CommunityId) -> String {
format!("{STATE_PREFIX}{}", id.to_hex())
}