use super::*;
fn send_nearby_published_event(update_tx: &Sender<AppUpdate>, event: &Event) {
let Ok(event_json) = serde_json::to_string(event) else {
return;
};
let _ = update_tx.send(AppUpdate::NearbyPublishedEvent {
event_id: event.id.to_string(),
kind: event.kind.as_u16() as u32,
created_at_secs: event.created_at.as_secs(),
event_json,
});
}
impl AppCore {
pub(super) fn emit_nearby_published_event(&self, event: &Event) {
send_nearby_published_event(&self.update_tx, event);
}
pub(super) fn publish_runtime_event(
&mut self,
event: Event,
label: &'static str,
completion: Option<(String, String)>,
) {
if self.defer_owner_app_keys_publish && is_app_keys_event(&event) {
self.push_debug_log(
"publish.runtime",
"label=runtime skipped=defer_owner_app_keys".to_string(),
);
return;
}
self.remember_event(event.id.to_string());
self.emit_nearby_published_event(&event);
let Some((client, relay_urls)) = self
.logged_in
.as_ref()
.map(|logged_in| (logged_in.client.clone(), logged_in.relay_urls.clone()))
else {
return;
};
if relay_urls.is_empty() {
self.push_debug_log(
"publish.runtime",
format!("label={label} success=false relays=0 skipped=no_servers"),
);
return;
}
let tx = self.core_sender.clone();
let relay_count = relay_urls.len();
self.runtime.spawn(async move {
let result = publish_event_fire_and_forget(&client, &relay_urls, &event, label).await;
let success = result
.as_ref()
.map(|relays| !relays.is_empty())
.unwrap_or(false);
let detail = match &result {
Ok(relays) => {
format!(
"label={label} success=true relays={relay_count} queued_relays={}",
relays.join(",")
)
}
Err(error) => {
format!("label={label} success=false relays={relay_count} error={error}")
}
};
if let Some((message_id, chat_id)) = completion {
let _ = tx.send(CoreMsg::Internal(Box::new(InternalEvent::DebugLog {
category: "publish.runtime".to_string(),
detail: detail.clone(),
})));
let _ = tx.send(CoreMsg::Internal(Box::new(
InternalEvent::PublishFinished {
message_id,
chat_id,
success,
},
)));
} else {
let _ = tx.send(CoreMsg::Internal(Box::new(InternalEvent::DebugLog {
category: "publish.runtime".to_string(),
detail,
})));
}
});
}
pub(super) fn sign_runtime_unsigned_event(&self, event: UnsignedEvent) -> Option<Event> {
let logged_in = self.logged_in.as_ref()?;
if event.pubkey == logged_in.device_keys.public_key() {
return event.sign_with_keys(&logged_in.device_keys).ok();
}
if let Some(owner_keys) = logged_in.owner_keys.as_ref() {
if event.pubkey == owner_keys.public_key() {
return event.sign_with_keys(owner_keys).ok();
}
}
None
}
pub(super) fn publish_local_identity_artifacts(&mut self) {
let Some(logged_in) = self.logged_in.as_ref() else {
return;
};
let owner_keys = logged_in.owner_keys.clone();
let device_keys = logged_in.device_keys.clone();
let owner_pubkey = logged_in.owner_pubkey;
let local_invite = logged_in.local_invite.clone();
let local_app_keys = self.app_keys.get(&owner_pubkey.to_hex()).cloned();
let local_profile = self.owner_profiles.get(&owner_pubkey.to_hex()).cloned();
let publish_app_keys = !self.defer_owner_app_keys_publish;
let client = logged_in.client.clone();
let relay_urls = logged_in.relay_urls.clone();
let tx = self.core_sender.clone();
let update_tx = self.update_tx.clone();
let mut events: Vec<(&'static str, Event)> = Vec::new();
if let (Some(keys), Some(profile)) = (owner_keys.clone(), local_profile) {
if let Ok(event) =
EventBuilder::new(Kind::Metadata, build_profile_metadata_json(&profile))
.sign_with_keys(&keys)
{
events.push(("metadata", event));
}
}
if let (true, Some(keys), Some(app_keys)) = (publish_app_keys, owner_keys, local_app_keys) {
if let Some(ndr_app_keys) = known_app_keys_to_ndr(&app_keys) {
if let Ok(unsigned) = ndr_app_keys.get_encrypted_event(&keys) {
if let Ok(event) = unsigned.sign_with_keys(&keys) {
events.push(("app-keys", event));
}
}
}
}
if let Ok(unsigned) = local_invite.get_event() {
if let Ok(event) = unsigned.sign_with_keys(&device_keys) {
events.push(("invite", event));
}
}
for (_, event) in &events {
self.remember_event(event.id.to_string());
send_nearby_published_event(&update_tx, event);
}
self.runtime.spawn(async move {
for (label, event) in events {
let _ = publish_event_with_retry(&client, &relay_urls, event, label).await;
}
let _ = tx.send(CoreMsg::Internal(Box::new(InternalEvent::SyncComplete)));
});
}
pub(super) fn publish_local_app_keys(&mut self) {
self.republish_local_identity_artifacts();
if let Some((owner, app_keys, created_at)) = self.logged_in.as_ref().and_then(|logged_in| {
self.app_keys
.get(&logged_in.owner_pubkey.to_hex())
.and_then(known_app_keys_to_ndr)
.map(|app_keys| {
(
logged_in.owner_pubkey,
app_keys,
self.app_keys
.get(&logged_in.owner_pubkey.to_hex())
.map(|known| known.created_at_secs)
.unwrap_or_else(|| unix_now().get()),
)
})
}) {
if let Some(logged_in) = self.logged_in.as_ref() {
logged_in
.ndr_runtime
.ingest_app_keys_snapshot(owner, app_keys, created_at);
}
}
self.process_runtime_events();
}
pub(super) fn republish_local_identity_artifacts(&mut self) {
self.publish_local_identity_artifacts();
}
}