feat: add DVM feeds
This commit is contained in:
14
src-tauri/Cargo.lock
generated
14
src-tauri/Cargo.lock
generated
@@ -3595,6 +3595,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"nostr",
|
||||
"thiserror",
|
||||
"webln",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7152,6 +7153,19 @@ dependencies = [
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webln"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75257015c2a40fc43c672fb03b70311f75e48b1020c8acff808ca628c46d87c"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"secp256k1",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.6"
|
||||
|
||||
@@ -33,7 +33,7 @@ tauri-plugin-theme = "2.1.2"
|
||||
tauri-plugin-decorum = { git = "https://github.com/clearlysid/tauri-plugin-decorum" }
|
||||
tauri-specta = { version = "2.0.0-rc.15", features = ["derive", "typescript"] }
|
||||
|
||||
nostr-sdk = { git = "https://github.com/rust-nostr/nostr", features = ["lmdb"] }
|
||||
nostr-sdk = { git = "https://github.com/rust-nostr/nostr", features = ["lmdb", "webln", "all-nips"] }
|
||||
nostr-connect = { git = "https://github.com/rust-nostr/nostr" }
|
||||
|
||||
specta = "^2.0.0-rc.20"
|
||||
|
||||
@@ -239,6 +239,173 @@ pub async fn get_all_events_from(
|
||||
Ok(alt_events)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn get_all_events_by_kind(
|
||||
kind: u16,
|
||||
until: Option<String>,
|
||||
state: State<'_, Nostr>,
|
||||
) -> Result<Vec<String>, String> {
|
||||
let client = &state.client;
|
||||
|
||||
let as_of = match until {
|
||||
Some(until) => Timestamp::from_str(&until).map_err(|err| err.to_string())?,
|
||||
None => Timestamp::now(),
|
||||
};
|
||||
|
||||
let filter = Filter::new()
|
||||
.kind(Kind::Custom(kind))
|
||||
.limit(FETCH_LIMIT)
|
||||
.until(as_of);
|
||||
|
||||
let mut events = Events::new(&[filter.clone()]);
|
||||
|
||||
let mut rx = client
|
||||
.stream_events(vec![filter], Some(Duration::from_secs(3)))
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
while let Some(event) = rx.next().await {
|
||||
events.insert(event);
|
||||
}
|
||||
|
||||
let alt_events: Vec<String> = events.iter().map(|ev| ev.as_json()).collect();
|
||||
|
||||
Ok(alt_events)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn get_all_providers(state: State<'_, Nostr>) -> Result<Vec<String>, String> {
|
||||
let client = &state.client;
|
||||
|
||||
let filter = Filter::new()
|
||||
.kind(Kind::Custom(31990))
|
||||
.custom_tag(SingleLetterTag::lowercase(Alphabet::K), vec!["5300"]);
|
||||
|
||||
let mut events = Events::new(&[filter.clone()]);
|
||||
|
||||
let mut rx = client
|
||||
.stream_events(vec![filter], Some(Duration::from_secs(3)))
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
while let Some(event) = rx.next().await {
|
||||
events.insert(event);
|
||||
}
|
||||
|
||||
let alt_events: Vec<String> = events.iter().map(|ev| ev.as_json()).collect();
|
||||
|
||||
Ok(alt_events)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn request_events_from_provider(
|
||||
provider: String,
|
||||
state: State<'_, Nostr>,
|
||||
) -> Result<String, String> {
|
||||
let client = &state.client;
|
||||
let signer = client.signer().await.map_err(|err| err.to_string())?;
|
||||
let public_key = signer
|
||||
.get_public_key()
|
||||
.await
|
||||
.map_err(|err| err.to_string())?;
|
||||
let provider = PublicKey::parse(&provider).map_err(|err| err.to_string())?;
|
||||
|
||||
// Get current user's relay list
|
||||
let relay_list = client
|
||||
.database()
|
||||
.relay_list(public_key)
|
||||
.await
|
||||
.map_err(|err| err.to_string())?;
|
||||
|
||||
let relay_list: Vec<String> = relay_list.iter().map(|item| item.0.to_string()).collect();
|
||||
|
||||
// Create job request
|
||||
let builder = EventBuilder::job_request(
|
||||
Kind::JobRequest(5300),
|
||||
vec![
|
||||
Tag::public_key(provider),
|
||||
Tag::custom(TagKind::Relays, relay_list),
|
||||
],
|
||||
)
|
||||
.map_err(|err| err.to_string())?;
|
||||
|
||||
match client.send_event_builder(builder).await {
|
||||
Ok(output) => {
|
||||
let filter = Filter::new()
|
||||
.kind(Kind::JobResult(6300))
|
||||
.author(provider)
|
||||
.pubkey(public_key)
|
||||
.since(Timestamp::now());
|
||||
|
||||
let opts = SubscribeAutoCloseOptions::default()
|
||||
.filter(FilterOptions::WaitDurationAfterEOSE(Duration::from_secs(2)));
|
||||
|
||||
let _ = client.subscribe(vec![filter], Some(opts)).await;
|
||||
|
||||
Ok(output.val.to_hex())
|
||||
}
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn get_all_events_by_request(
|
||||
id: String,
|
||||
provider: String,
|
||||
state: State<'_, Nostr>,
|
||||
) -> Result<Vec<RichEvent>, String> {
|
||||
let client = &state.client;
|
||||
let public_key = PublicKey::parse(&id).map_err(|err| err.to_string())?;
|
||||
let provider = PublicKey::parse(&provider).map_err(|err| err.to_string())?;
|
||||
|
||||
let filter = Filter::new()
|
||||
.kind(Kind::JobResult(6300))
|
||||
.author(provider)
|
||||
.pubkey(public_key)
|
||||
.limit(1);
|
||||
|
||||
let events = client
|
||||
.database()
|
||||
.query(vec![filter])
|
||||
.await
|
||||
.map_err(|err| err.to_string())?;
|
||||
|
||||
if let Some(event) = events.first() {
|
||||
let parsed: Vec<Vec<String>> =
|
||||
serde_json::from_str(&event.content).map_err(|err| err.to_string())?;
|
||||
|
||||
let vec: Vec<Tag> = parsed
|
||||
.into_iter()
|
||||
.filter_map(|item| Tag::parse(&item).ok())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let tags = Tags::new(vec);
|
||||
let ids: Vec<EventId> = tags.event_ids().copied().collect();
|
||||
|
||||
let filter = Filter::new().ids(ids);
|
||||
let mut events = Events::new(&[filter.clone()]);
|
||||
|
||||
let mut rx = client
|
||||
.stream_events(vec![filter], Some(Duration::from_secs(3)))
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
while let Some(event) = rx.next().await {
|
||||
events.insert(event);
|
||||
}
|
||||
|
||||
let alt_events = process_event(client, events, false).await;
|
||||
|
||||
Ok(alt_events)
|
||||
} else {
|
||||
Err("Job result not found.".into())
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn get_local_events(
|
||||
|
||||
@@ -71,11 +71,11 @@ pub async fn create_column(
|
||||
if let Ok(public_key) = PublicKey::parse(&id) {
|
||||
let is_newsfeed = payload.url().to_string().contains("newsfeed");
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let state = webview.state::<Nostr>();
|
||||
let client = &state.client;
|
||||
if is_newsfeed {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let state = webview.state::<Nostr>();
|
||||
let client = &state.client;
|
||||
|
||||
if is_newsfeed {
|
||||
if let Ok(contact_list) =
|
||||
client.database().contacts_public_keys(public_key).await
|
||||
{
|
||||
@@ -102,27 +102,31 @@ pub async fn create_column(
|
||||
println!("Subscription error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
} else if let Ok(event_id) = EventId::parse(&id) {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let state = webview.state::<Nostr>();
|
||||
let client = &state.client;
|
||||
let is_thread = payload.url().to_string().contains("events");
|
||||
|
||||
let subscription_id = SubscriptionId::new(webview.label());
|
||||
if is_thread {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let state = webview.state::<Nostr>();
|
||||
let client = &state.client;
|
||||
|
||||
let filter = Filter::new()
|
||||
.event(event_id)
|
||||
.kinds(vec![Kind::TextNote, Kind::Custom(1111)])
|
||||
.since(Timestamp::now());
|
||||
let subscription_id = SubscriptionId::new(webview.label());
|
||||
|
||||
if let Err(e) = client
|
||||
.subscribe_with_id(subscription_id, vec![filter], None)
|
||||
.await
|
||||
{
|
||||
println!("Subscription error: {}", e);
|
||||
}
|
||||
});
|
||||
let filter = Filter::new()
|
||||
.event(event_id)
|
||||
.kinds(vec![Kind::TextNote, Kind::Custom(1111)])
|
||||
.since(Timestamp::now());
|
||||
|
||||
if let Err(e) = client
|
||||
.subscribe_with_id(subscription_id, vec![filter], None)
|
||||
.await
|
||||
{
|
||||
println!("Subscription error: {}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +121,10 @@ fn main() {
|
||||
get_all_events_by_authors,
|
||||
get_all_events_by_hashtags,
|
||||
get_all_events_from,
|
||||
get_all_events_by_kind,
|
||||
get_all_providers,
|
||||
request_events_from_provider,
|
||||
get_all_events_by_request,
|
||||
get_local_events,
|
||||
get_global_events,
|
||||
search,
|
||||
@@ -232,8 +236,7 @@ fn main() {
|
||||
// Config
|
||||
let opts = Options::new()
|
||||
.gossip(true)
|
||||
.max_avg_latency(Duration::from_millis(300))
|
||||
.automatic_authentication(true)
|
||||
.max_avg_latency(Duration::from_millis(500))
|
||||
.timeout(Duration::from_secs(5));
|
||||
|
||||
// Setup nostr client
|
||||
@@ -546,6 +549,8 @@ fn main() {
|
||||
) {
|
||||
println!("Emit error: {}", e)
|
||||
}
|
||||
} else if event.kind == Kind::JobResult(6300) {
|
||||
println!("Job result: {}", event.as_json())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user