Skip to content

Commit 6f5685a

Browse files
committed
Merge #225: ffi(nostr): complete nips module
2 parents 0d2df38 + 6a2e5bd commit 6f5685a

File tree

18 files changed

+1228
-47
lines changed

18 files changed

+1228
-47
lines changed

bindings/nostr-ffi/src/error.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ impl From<nostr::event::tag::Error> for NostrError {
8585
}
8686
}
8787

88+
impl From<nostr::nips::nip01::Error> for NostrError {
89+
fn from(e: nostr::nips::nip01::Error) -> NostrError {
90+
Self::Generic { err: e.to_string() }
91+
}
92+
}
93+
8894
impl From<nostr::nips::nip04::Error> for NostrError {
8995
fn from(e: nostr::nips::nip04::Error) -> NostrError {
9096
Self::Generic { err: e.to_string() }
@@ -133,6 +139,12 @@ impl From<nostr::nips::nip46::Error> for NostrError {
133139
}
134140
}
135141

142+
impl From<nostr::nips::nip47::Error> for NostrError {
143+
fn from(e: nostr::nips::nip47::Error) -> NostrError {
144+
Self::Generic { err: e.to_string() }
145+
}
146+
}
147+
136148
impl From<nostr::nips::nip53::Error> for NostrError {
137149
fn from(e: nostr::nips::nip53::Error) -> NostrError {
138150
Self::Generic { err: e.to_string() }

bindings/nostr-ffi/src/event/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,11 @@ impl Event {
168168
}
169169

170170
/// Extract coordinates from tags (`a` tag)
171-
pub fn coordinates(&self) -> Vec<Coordinate> {
172-
self.inner.coordinates().map(|p| p.into()).collect()
171+
pub fn coordinates(&self) -> Vec<Arc<Coordinate>> {
172+
self.inner
173+
.coordinates()
174+
.map(|p| Arc::new(p.into()))
175+
.collect()
173176
}
174177

175178
#[uniffi::constructor]

bindings/nostr-ffi/src/nips/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,18 @@ pub mod nip01;
66
pub mod nip04;
77
pub mod nip05;
88
pub mod nip11;
9+
pub mod nip13;
910
pub mod nip15;
1011
pub mod nip19;
12+
pub mod nip21;
13+
pub mod nip26;
1114
pub mod nip44;
1215
pub mod nip46;
16+
pub mod nip47;
1317
pub mod nip48;
1418
pub mod nip53;
1519
pub mod nip57;
20+
pub mod nip65;
1621
pub mod nip90;
1722
pub mod nip94;
1823
pub mod nip98;
Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,85 @@
11
// Copyright (c) 2023-2024 Rust Nostr Developers
22
// Distributed under the MIT software license
33

4+
use std::str::FromStr;
45
use std::sync::Arc;
56

67
use nostr::nips::nip01;
7-
use uniffi::Record;
8+
use nostr::nips::nip19::{FromBech32, ToBech32};
9+
use nostr::nips::nip21::NostrURI;
10+
use uniffi::Object;
811

12+
use crate::error::Result;
913
use crate::PublicKey;
1014

1115
/// Coordinate for event (`a` tag)
12-
#[derive(Record)]
16+
#[derive(Object)]
1317
pub struct Coordinate {
14-
/// Kind
15-
pub kind: u64,
16-
/// Public Key
17-
pub pubkey: Arc<PublicKey>,
18-
/// `d` tag identifier
19-
///
20-
/// Needed for a parametrized replaceable event.
21-
/// Leave empty for a replaceable event.
22-
pub identifier: String,
23-
/// Relays
24-
pub relays: Vec<String>,
18+
inner: nip01::Coordinate,
19+
}
20+
21+
#[uniffi::export]
22+
impl Coordinate {
23+
#[uniffi::constructor]
24+
pub fn new(kind: u64, public_key: Arc<PublicKey>) -> Self {
25+
Self {
26+
inner: nip01::Coordinate::new(kind.into(), **public_key),
27+
}
28+
}
29+
30+
#[uniffi::constructor]
31+
pub fn parse(coordinate: String) -> Result<Self> {
32+
Ok(nip01::Coordinate::from_str(&coordinate)?.into())
33+
}
34+
35+
#[uniffi::constructor]
36+
pub fn from_bech32(bech32: String) -> Result<Self> {
37+
Ok(nip01::Coordinate::from_bech32(bech32)?.into())
38+
}
39+
40+
#[uniffi::constructor]
41+
pub fn from_nostr_uri(uri: String) -> Result<Self> {
42+
Ok(nip01::Coordinate::from_nostr_uri(uri)?.into())
43+
}
44+
45+
pub fn to_bech32(&self) -> Result<String> {
46+
Ok(self.inner.to_bech32()?)
47+
}
48+
49+
pub fn to_nostr_uri(&self) -> Result<String> {
50+
Ok(self.inner.to_nostr_uri()?)
51+
}
52+
53+
pub fn kind(&self) -> u64 {
54+
self.inner.kind.into()
55+
}
56+
57+
pub fn public_key(&self) -> Arc<PublicKey> {
58+
Arc::new(self.inner.pubkey.into())
59+
}
60+
61+
pub fn identifier(&self) -> String {
62+
self.inner.identifier.clone()
63+
}
64+
65+
pub fn relays(&self) -> Vec<String> {
66+
self.inner.relays.clone()
67+
}
2568
}
2669

2770
impl From<Coordinate> for nip01::Coordinate {
2871
fn from(value: Coordinate) -> Self {
2972
Self {
30-
kind: value.kind.into(),
31-
pubkey: **value.pubkey,
32-
identifier: value.identifier,
33-
relays: value.relays,
73+
kind: value.inner.kind,
74+
pubkey: value.inner.pubkey,
75+
identifier: value.inner.identifier,
76+
relays: value.inner.relays,
3477
}
3578
}
3679
}
3780

3881
impl From<nip01::Coordinate> for Coordinate {
39-
fn from(value: nip01::Coordinate) -> Self {
40-
Self {
41-
kind: value.kind.into(),
42-
pubkey: Arc::new(value.pubkey.into()),
43-
identifier: value.identifier,
44-
relays: value.relays,
45-
}
82+
fn from(inner: nip01::Coordinate) -> Self {
83+
Self { inner }
4684
}
4785
}

bindings/nostr-ffi/src/nips/nip11.rs

Lines changed: 207 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ use std::sync::Arc;
77

88
use nostr::nips::nip11;
99
use nostr::Url;
10-
use uniffi::Object;
10+
use uniffi::{Enum, Object, Record};
1111

1212
use crate::error::Result;
13+
use crate::Timestamp;
1314

1415
#[derive(Object)]
1516
pub struct RelayInformationDocument {
@@ -24,6 +25,14 @@ impl From<nip11::RelayInformationDocument> for RelayInformationDocument {
2425

2526
#[uniffi::export]
2627
impl RelayInformationDocument {
28+
#[uniffi::constructor]
29+
/// Create new empty [`RelayInformationDocument`]
30+
pub fn new() -> Self {
31+
Self {
32+
inner: nip11::RelayInformationDocument::new(),
33+
}
34+
}
35+
2736
#[uniffi::constructor]
2837
pub fn get(url: String, proxy: Option<String>) -> Result<Arc<Self>> {
2938
let url: Url = Url::parse(&url)?;
@@ -63,4 +72,201 @@ impl RelayInformationDocument {
6372
pub fn version(&self) -> Option<String> {
6473
self.inner.version.clone()
6574
}
75+
76+
pub fn limitation(&self) -> Option<Limitation> {
77+
self.inner.limitation.clone().map(|l| l.into())
78+
}
79+
80+
pub fn retention(&self) -> Vec<Retention> {
81+
self.inner
82+
.retention
83+
.clone()
84+
.into_iter()
85+
.map(|l| l.into())
86+
.collect()
87+
}
88+
89+
pub fn relay_countries(&self) -> Vec<String> {
90+
self.inner.relay_countries.clone()
91+
}
92+
93+
pub fn language_tags(&self) -> Vec<String> {
94+
self.inner.language_tags.clone()
95+
}
96+
97+
pub fn tags(&self) -> Vec<String> {
98+
self.inner.tags.clone()
99+
}
100+
101+
pub fn posting_policy(&self) -> Option<String> {
102+
self.inner.posting_policy.clone()
103+
}
104+
105+
pub fn payments_url(&self) -> Option<String> {
106+
self.inner.payments_url.clone()
107+
}
108+
109+
pub fn fees(&self) -> Option<FeeSchedules> {
110+
self.inner.fees.clone().map(|f| f.into())
111+
}
112+
113+
pub fn icon(&self) -> Option<String> {
114+
self.inner.icon.clone()
115+
}
116+
}
117+
118+
/// These are limitations imposed by the relay on clients. Your client should
119+
/// expect that requests which exceed these practical limitations are rejected or fail immediately.
120+
#[derive(Record)]
121+
pub struct Limitation {
122+
/// Maximum number of bytes for incoming JSON that the relay will attempt to decode and act upon
123+
pub max_message_length: Option<i32>,
124+
/// Total number of subscriptions that may be active on a single websocket connection
125+
pub max_subscriptions: Option<i32>,
126+
/// Maximum number of filter values in each subscription
127+
pub max_filters: Option<i32>,
128+
/// Relay will clamp each filter's limit value to this number
129+
pub max_limit: Option<i32>,
130+
/// Maximum length of subscription id as a string
131+
pub max_subid_length: Option<i32>,
132+
/// Maximum number of elements in the tags list
133+
pub max_event_tags: Option<i32>,
134+
/// Maximum number of characters in the content field of any event
135+
pub max_content_length: Option<i32>,
136+
/// New events will require at least this difficulty of PoW,
137+
pub min_pow_difficulty: Option<i32>,
138+
/// Relay requires NIP-42 authentication to happen before a new connection may perform any other action
139+
pub auth_required: Option<bool>,
140+
/// Relay requires payment before a new connection may perform any action
141+
pub payment_required: Option<bool>,
142+
/// 'created_at' lower limit
143+
pub created_at_lower_limit: Option<Arc<Timestamp>>,
144+
/// 'created_at' upper limit
145+
pub created_at_upper_limit: Option<Arc<Timestamp>>,
146+
}
147+
148+
impl From<nip11::Limitation> for Limitation {
149+
fn from(inner: nip11::Limitation) -> Self {
150+
let nip11::Limitation {
151+
max_message_length,
152+
max_subscriptions,
153+
max_filters,
154+
max_limit,
155+
max_subid_length,
156+
max_event_tags,
157+
max_content_length,
158+
min_pow_difficulty,
159+
auth_required,
160+
payment_required,
161+
created_at_lower_limit,
162+
created_at_upper_limit,
163+
} = inner;
164+
Self {
165+
max_message_length,
166+
max_subscriptions,
167+
max_filters,
168+
max_limit,
169+
max_subid_length,
170+
max_event_tags,
171+
max_content_length,
172+
min_pow_difficulty,
173+
auth_required,
174+
payment_required,
175+
created_at_lower_limit: created_at_lower_limit.map(|c| Arc::new(c.into())),
176+
created_at_upper_limit: created_at_upper_limit.map(|c| Arc::new(c.into())),
177+
}
178+
}
179+
}
180+
181+
/// A retention shedule for the relay
182+
#[derive(Record)]
183+
pub struct Retention {
184+
/// The event kinds this retention pertains to
185+
pub kinds: Option<Vec<RetentionKind>>,
186+
/// The amount of time these events are kept
187+
pub time: Option<u64>,
188+
/// The max number of events kept before removing older events
189+
pub count: Option<u64>,
190+
}
191+
192+
impl From<nip11::Retention> for Retention {
193+
fn from(inner: nip11::Retention) -> Self {
194+
let nip11::Retention { kinds, time, count } = inner;
195+
Self {
196+
kinds: kinds.map(|k| k.into_iter().map(|k| k.into()).collect()),
197+
time,
198+
count,
199+
}
200+
}
201+
}
202+
203+
#[derive(Enum)]
204+
pub enum RetentionKind {
205+
Single { single: u64 },
206+
Range { start: u64, end: u64 },
207+
}
208+
209+
impl From<nip11::RetentionKind> for RetentionKind {
210+
fn from(value: nip11::RetentionKind) -> Self {
211+
match value {
212+
nip11::RetentionKind::Single(s) => Self::Single { single: s },
213+
nip11::RetentionKind::Range(s, e) => Self::Range { start: s, end: e },
214+
}
215+
}
216+
}
217+
218+
/// Available fee schedules
219+
#[derive(Record)]
220+
pub struct FeeSchedules {
221+
/// Fees for admission to use the relay
222+
pub admission: Vec<FeeSchedule>,
223+
/// Fees for subscription to use the relay
224+
pub subscription: Vec<FeeSchedule>,
225+
/// Fees to publish to the relay
226+
pub publication: Vec<FeeSchedule>,
227+
}
228+
229+
impl From<nip11::FeeSchedules> for FeeSchedules {
230+
fn from(inner: nip11::FeeSchedules) -> Self {
231+
let nip11::FeeSchedules {
232+
admission,
233+
subscription,
234+
publication,
235+
} = inner;
236+
Self {
237+
admission: admission.into_iter().map(|a| a.into()).collect(),
238+
subscription: subscription.into_iter().map(|s| s.into()).collect(),
239+
publication: publication.into_iter().map(|p| p.into()).collect(),
240+
}
241+
}
242+
}
243+
244+
/// The specific information about a fee schedule
245+
#[derive(Record)]
246+
pub struct FeeSchedule {
247+
/// The fee amount
248+
pub amount: i32,
249+
/// The denomination of the feed
250+
pub unit: String,
251+
/// The duration for which the fee is valid
252+
pub period: Option<i32>,
253+
/// The event kinds the fee allows the client to publish to the relay
254+
pub kinds: Option<Vec<String>>,
255+
}
256+
257+
impl From<nip11::FeeSchedule> for FeeSchedule {
258+
fn from(inner: nip11::FeeSchedule) -> Self {
259+
let nip11::FeeSchedule {
260+
amount,
261+
unit,
262+
period,
263+
kinds,
264+
} = inner;
265+
Self {
266+
amount,
267+
unit,
268+
period,
269+
kinds,
270+
}
271+
}
66272
}

0 commit comments

Comments
 (0)