12
12
#![ warn( rustdoc:: bare_urls) ]
13
13
14
14
use std:: collections:: HashMap ;
15
- use std:: net:: { IpAddr , Ipv4Addr , SocketAddr } ;
15
+ use std:: net:: { IpAddr , Ipv4Addr , SocketAddr , SocketAddrV4 } ;
16
16
use std:: sync:: Arc ;
17
17
use std:: time:: Duration ;
18
18
@@ -44,8 +44,6 @@ pub use self::error::Error;
44
44
const HTML : & str = include_str ! ( "../index.html" ) ;
45
45
const JS : & str = include_str ! ( "../proxy.js" ) ;
46
46
const CSS : & str = include_str ! ( "../style.css" ) ;
47
- const IP_ADDR : IpAddr = IpAddr :: V4 ( Ipv4Addr :: LOCALHOST ) ;
48
- const TIMEOUT : Duration = Duration :: from_secs ( 30 ) ;
49
47
50
48
type PendingResponseMap = HashMap < Uuid , Sender < Result < Value , String > > > ;
51
49
@@ -158,30 +156,72 @@ struct ProxyState {
158
156
pub pending_responses : Mutex < PendingResponseMap > ,
159
157
}
160
158
159
+ /// Configuration options for [`BrowserSignerProxy`].
160
+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
161
+ pub struct BrowserSignerProxyOptions {
162
+ /// Request timeout for the signer extension. Default is 30 seconds.
163
+ pub timeout : Duration ,
164
+ /// Proxy server IP address and port. Default is `127.0.0.1:7400`.
165
+ pub addr : SocketAddr ,
166
+ }
167
+
161
168
/// Nostr Browser Signer Proxy
162
169
///
163
170
/// Proxy to use Nostr Browser signer (NIP-07) in native applications.
164
171
#[ derive( Debug , Clone ) ]
165
172
pub struct BrowserSignerProxy {
166
- port : u16 ,
173
+ /// Configuration options for the proxy
174
+ options : BrowserSignerProxyOptions ,
175
+ /// Internal state of the proxy including request queues
167
176
state : Arc < ProxyState > ,
177
+ /// Handle to the running proxy server (initialized on demand)
168
178
handle : OnceCell < Arc < JoinHandle < ( ) > > > ,
179
+ /// Notification trigger for graceful shutdown
169
180
shutdown : Arc < Notify > ,
170
181
}
171
182
183
+ impl Default for BrowserSignerProxyOptions {
184
+ fn default ( ) -> Self {
185
+ Self {
186
+ timeout : Duration :: from_secs ( 30 ) ,
187
+ // 7 for NIP-07 and 400 because the NIP title is 40 bytes :)
188
+ addr : SocketAddr :: V4 ( SocketAddrV4 :: new ( Ipv4Addr :: LOCALHOST , 7400 ) ) ,
189
+ }
190
+ }
191
+ }
192
+
193
+ impl BrowserSignerProxyOptions {
194
+ /// Sets the timeout duration.
195
+ pub const fn timeout ( mut self , timeout : Duration ) -> Self {
196
+ self . timeout = timeout;
197
+ self
198
+ }
199
+
200
+ /// Sets the IP address.
201
+ pub const fn ip_addr ( mut self , new_ip : IpAddr ) -> Self {
202
+ self . addr = SocketAddr :: new ( new_ip, self . addr . port ( ) ) ;
203
+ self
204
+ }
205
+
206
+ /// Sets the port number.
207
+ pub const fn port ( mut self , new_port : u16 ) -> Self {
208
+ self . addr = SocketAddr :: new ( self . addr . ip ( ) , new_port) ;
209
+ self
210
+ }
211
+ }
212
+
172
213
// TODO: use atomic-destructor to automatically shutdown this when all instances are dropped
173
214
174
215
impl BrowserSignerProxy {
175
- // TODO: use a builder instead, to allow to config IP, port, timeout and so on.
176
216
/// Construct a new browser signer proxy
177
- pub fn new ( port : u16 ) -> Self {
217
+ pub fn new ( options : BrowserSignerProxyOptions ) -> Self {
178
218
let state = ProxyState {
179
219
outgoing_requests : Mutex :: new ( Vec :: new ( ) ) ,
180
220
pending_responses : Mutex :: new ( HashMap :: new ( ) ) ,
181
221
} ;
182
222
183
223
Self {
184
- port ,
224
+ options ,
185
225
state : Arc :: new ( state) ,
186
226
handle : OnceCell :: new ( ) ,
187
227
shutdown : Arc :: new ( Notify :: new ( ) ) ,
@@ -191,7 +231,7 @@ impl BrowserSignerProxy {
191
231
/// Get the signer proxy webpage URL
192
232
#[ inline]
193
233
pub fn url ( & self ) -> String {
194
- format ! ( "http://{IP_ADDR}:{} " , self . port )
234
+ format ! ( "http://{} " , self . options . addr )
195
235
}
196
236
197
237
/// Start the proxy
@@ -201,8 +241,7 @@ impl BrowserSignerProxy {
201
241
let _handle: & Arc < JoinHandle < ( ) > > = self
202
242
. handle
203
243
. get_or_try_init ( || async {
204
- let addr: SocketAddr = SocketAddr :: new ( IP_ADDR , self . port ) ;
205
- let listener = TcpListener :: bind ( addr) . await ?;
244
+ let listener = TcpListener :: bind ( self . options . addr ) . await ?;
206
245
207
246
let state = self . state . clone ( ) ;
208
247
let shutdown = self . shutdown . clone ( ) ;
@@ -281,7 +320,7 @@ impl BrowserSignerProxy {
281
320
self . store_outgoing_request ( request) . await ;
282
321
283
322
// Wait for response
284
- match time:: timeout ( TIMEOUT , rx)
323
+ match time:: timeout ( self . options . timeout , rx)
285
324
. await
286
325
. map_err ( |_| Error :: Timeout ) ??
287
326
{
0 commit comments