1
1
#![ allow( unused) ]
2
2
3
- use std:: collections:: HashMap ;
3
+ use std:: cmp:: Ordering ;
4
+ use std:: collections:: BTreeMap ;
4
5
use std:: error:: Error ;
5
6
use std:: fmt;
7
+ use std:: sync:: { Arc , Mutex } ;
6
8
7
9
use enostr:: Filter ;
8
10
use nostrdb;
@@ -13,35 +15,44 @@ use nostrdb;
13
15
/// already is one. Using a lame (but short) placeholder name instead
14
16
/// for now ...
15
17
///
16
- /// ```ignore
18
+ /// ```no_run
17
19
/// use std::error::Error;
20
+ /// use std::sync::{Arc, Mutex};
18
21
///
19
22
/// use notedeck::submgr::{SubMgr, SubSpecBuilder, SubError};
20
23
/// use enostr::Filter;
21
24
///
22
25
/// #[tokio::main]
23
26
/// async fn main() -> Result<(), Box<dyn Error>> {
24
- /// let mut submgr = SubMgr::new();
27
+ /// let submgr = SubMgr::new();
25
28
///
29
+ /// // Define a filter and build the subscription specification
26
30
/// let filter = Filter::new().kinds(vec![1, 2, 3]).build();
27
- /// let ep = submgr.subscribe(SubSpecBuilder::new(vec![filter]).build())?;
31
+ /// let spec = SubSpecBuilder::new(vec![filter]).build();
32
+ ///
33
+ /// // Subscribe and obtain a SubReceiver
34
+ /// let receiver = SubMgr::subscribe(submgr.clone(), spec)?;
35
+ ///
36
+ /// // Process incoming note keys
28
37
/// loop {
29
- /// match ep.next().await {
30
- /// Ok(nks) => {
31
- /// // process the note keys
38
+ /// match receiver.next().await {
39
+ /// Ok(note_keys) => {
40
+ /// // Process the note keys
41
+ /// println!("Received note keys: {:?}", note_keys);
32
42
/// },
33
43
/// Err(SubError::ReevaluateState) => {
34
- /// // not really an error, break out of loop and reevaluate state
44
+ /// // Not really an error; break out to reevaluate the state
35
45
/// break;
36
46
/// },
37
47
/// Err(err) => {
38
- /// // something bad happened
48
+ /// // Handle other errors
39
49
/// eprintln!("Error: {:?}", err);
40
50
/// break;
41
51
/// },
42
52
/// }
43
53
/// }
44
- /// submgr.unsubscribe(ep)?;
54
+ ///
55
+ /// // The subscription will automatically be cleaned up when the receiver goes out of scope
45
56
/// Ok(())
46
57
/// }
47
58
/// ```
@@ -73,9 +84,30 @@ impl Error for SubError {}
73
84
74
85
pub type SubResult < T > = Result < T , SubError > ;
75
86
87
+ #[ derive( Debug , Clone , Copy ) ]
76
88
pub struct SubId ( nostrdb:: Subscription ) ;
77
89
78
- #[ derive( Debug ) ]
90
+ impl Ord for SubId {
91
+ fn cmp ( & self , other : & Self ) -> Ordering {
92
+ self . 0 . id ( ) . cmp ( & other. 0 . id ( ) ) // Access the inner `u64` and compare
93
+ }
94
+ }
95
+
96
+ impl PartialOrd for SubId {
97
+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
98
+ Some ( self . cmp ( other) ) // Delegate to `cmp`
99
+ }
100
+ }
101
+
102
+ impl PartialEq for SubId {
103
+ fn eq ( & self , other : & Self ) -> bool {
104
+ self . 0 . id ( ) == other. 0 . id ( ) // Compare the inner `u64`
105
+ }
106
+ }
107
+
108
+ impl Eq for SubId { }
109
+
110
+ #[ derive( Debug , Clone ) ]
79
111
pub enum SubConstraint {
80
112
OneShot , // terminate subscription after initial query
81
113
Local , // only query the local db, no remote subs
@@ -108,6 +140,7 @@ impl SubSpecBuilder {
108
140
}
109
141
}
110
142
143
+ #[ derive( Debug , Clone ) ]
111
144
pub struct SubSpec {
112
145
rmtid : String ,
113
146
filters : Vec < Filter > ,
@@ -118,32 +151,61 @@ pub struct SubSpec {
118
151
}
119
152
120
153
pub struct SubMgr {
121
- subs : HashMap < SubId , ( SubSpec , SubEndpoint ) > ,
154
+ subs : BTreeMap < SubId , ( SubSpec , SubSender ) > ,
122
155
}
123
156
124
157
impl SubMgr {
125
- pub fn new ( ) -> Self {
126
- SubMgr {
127
- subs : HashMap :: new ( ) ,
128
- }
158
+ pub fn new ( ) -> Arc < Mutex < Self > > {
159
+ Arc :: new ( Mutex :: new ( SubMgr {
160
+ subs : BTreeMap :: new ( ) ,
161
+ } ) )
129
162
}
130
163
131
- pub fn subscribe ( & mut self , sub : SubSpec ) -> SubResult < SubEndpoint > {
132
- unimplemented ! ( ) ;
164
+ pub fn subscribe ( sub_mgr : Arc < Mutex < SubMgr > > , spec : SubSpec ) -> SubResult < SubReceiver > {
165
+ let mut mgr = sub_mgr. lock ( ) . unwrap ( ) ;
166
+ let ( id, sender, receiver) = mgr. make_subscription ( & spec) ?;
167
+ mgr. subs . insert ( id, ( spec, sender) ) ;
168
+ Ok ( SubReceiver {
169
+ id,
170
+ sub_mgr : sub_mgr. clone ( ) ,
171
+ } )
172
+ }
173
+
174
+ pub fn unsubscribe ( sub_mgr : Arc < Mutex < SubMgr > > , id : SubId ) -> SubResult < ( ) > {
175
+ let mut mgr = sub_mgr. lock ( ) . unwrap ( ) ;
176
+ mgr. subs . remove ( & id) ;
177
+ Ok ( ( ) )
133
178
}
134
179
135
- pub fn unsubscribe ( & mut self , ep : SubEndpoint ) -> SubResult < ( ) > {
180
+ fn make_subscription ( & mut self , sub : & SubSpec ) -> SubResult < ( SubId , SubSender , SubReceiver ) > {
136
181
unimplemented ! ( ) ;
137
182
}
138
183
}
139
184
140
- pub struct SubEndpoint {
185
+ pub struct SubSender {
186
+ // internals omitted ...
187
+ }
188
+
189
+ pub struct SubReceiver {
190
+ sub_mgr : Arc < Mutex < SubMgr > > ,
141
191
id : SubId ,
142
192
// internals omitted ...
143
193
}
144
194
145
- impl SubEndpoint {
195
+ impl SubReceiver {
196
+ pub fn new ( id : SubId , sub_mgr : Arc < Mutex < SubMgr > > ) -> Self {
197
+ SubReceiver { id, sub_mgr }
198
+ }
199
+
146
200
pub async fn next ( & self ) -> SubResult < Vec < nostrdb:: NoteKey > > {
147
201
unimplemented ! ( ) ;
148
202
}
149
203
}
204
+
205
+ impl Drop for SubReceiver {
206
+ fn drop ( & mut self ) {
207
+ if let Err ( err) = SubMgr :: unsubscribe ( self . sub_mgr . clone ( ) , self . id . clone ( ) ) {
208
+ eprintln ! ( "Failed to unsubscribe: {:?}" , err) ;
209
+ }
210
+ }
211
+ }
0 commit comments