1- use crate :: { Error , credentials:: Credentials } ;
2- use gl_client:: node:: Node as ClientNode ;
1+ use crate :: { credentials:: Credentials , util:: exec, Error } ;
32use gl_client:: credentials:: NodeIdProvider ;
3+ use gl_client:: node:: { Client as GlClient , ClnClient , Node as ClientNode } ;
4+
5+ use gl_client:: pb:: cln as clnpb;
6+ use tokio:: sync:: OnceCell ;
47
58/// The `Node` is an RPC stub representing the node running in the
69/// cloud. It is the main entrypoint to interact with the node.
7- #[ derive( uniffi:: Object ) ]
10+ #[ derive( uniffi:: Object , Clone ) ]
811#[ allow( unused) ]
912pub struct Node {
1013 inner : ClientNode ,
14+ cln_client : OnceCell < ClnClient > ,
15+ gl_client : OnceCell < GlClient > ,
1116}
1217
1318#[ uniffi:: export]
@@ -18,9 +23,121 @@ impl Node {
1823 . inner
1924 . node_id ( )
2025 . map_err ( |_e| Error :: UnparseableCreds ( ) ) ?;
21- let client = ClientNode :: new ( node_id, credentials. inner . clone ( ) )
26+ let inner = ClientNode :: new ( node_id, credentials. inner . clone ( ) )
2227 . expect ( "infallible client instantiation" ) ;
2328
24- Ok ( Node { inner : client } )
29+ let cln_client = OnceCell :: const_new ( ) ;
30+ let gl_client = OnceCell :: const_new ( ) ;
31+ Ok ( Node {
32+ inner,
33+ cln_client,
34+ gl_client,
35+ } )
36+ }
37+
38+ pub fn stop ( & self ) -> Result < ( ) , Error > {
39+ let mut cln_client = exec ( self . get_cln_client ( ) ) ?. clone ( ) ;
40+
41+ let req = clnpb:: StopRequest { } ;
42+
43+ // It's ok, the error here is expected and should just be
44+ // telling us that we've lost the connection. This is to
45+ // be expected on shutdown, so we clamp this to success.
46+ exec ( cln_client. stop ( req) ) ;
47+ Ok ( ( ) )
48+ }
49+
50+ /// Receive an off-chain payment.
51+ ///
52+ /// This method generates a request for a payment, also called an
53+ /// invoice, that encodes all the information, including amount
54+ /// and destination, for a prospective sender to send a lightning
55+ /// payment. The invoice includes negotiation of an LSPS2 / JIT
56+ /// channel, meaning that if there is no channel sufficient to
57+ /// receive the requested funds, the node will negotiate an
58+ /// opening, and when/if executed the payment will cause a channel
59+ /// to be created, and the incoming payment to be forwarded.
60+ fn receive (
61+ & self ,
62+ label : String ,
63+ description : String ,
64+ amount_msat : Option < u64 > ,
65+ ) -> Result < ReceiveResponse , Error > {
66+ let mut gl_client = exec ( self . get_gl_client ( ) ) ?. clone ( ) ;
67+
68+ let req = gl_client:: pb:: LspInvoiceRequest {
69+ amount_msat : amount_msat. unwrap_or_default ( ) ,
70+ description : description,
71+ label : label,
72+ lsp_id : "" . to_owned ( ) ,
73+ token : "" . to_owned ( ) ,
74+ } ;
75+ let res = exec ( gl_client. lsp_invoice ( req) )
76+ . map_err ( |s| Error :: Rpc ( s. to_string ( ) ) ) ?
77+ . into_inner ( ) ;
78+ Ok ( ReceiveResponse { bolt11 : res. bolt11 } )
79+ }
80+
81+ fn onchain_send ( & self , req : & OnchainSendRequest ) -> Result < OnchainSendResponse , Error > {
82+ unimplemented ! ( )
83+ }
84+ fn onchain_receive (
85+ & self ,
86+ addresstype : Option < AddressType > ,
87+ ) -> Result < OnchainReceiveResponse , Error > {
88+ unimplemented ! ( )
89+ }
90+
91+ fn send ( & self , invoice : String ) -> SendResponse {
92+ unimplemented ! ( )
93+ }
94+ }
95+
96+ // Not exported through uniffi
97+ impl Node {
98+ async fn get_gl_client < ' a > ( & ' a self ) -> Result < & ' a GlClient , Error > {
99+ let inner = self . inner . clone ( ) ;
100+ self . gl_client
101+ . get_or_try_init ( || async { inner. schedule :: < GlClient > ( ) . await } )
102+ . await
103+ . map_err ( |e| Error :: Rpc ( e. to_string ( ) ) )
104+ }
105+
106+ async fn get_cln_client < ' a > ( & ' a self ) -> Result < & ' a ClnClient , Error > {
107+ let inner = self . inner . clone ( ) ;
108+
109+ self . cln_client
110+ . get_or_try_init ( || async { inner. schedule :: < ClnClient > ( ) . await } )
111+ . await
112+ . map_err ( |e| Error :: Rpc ( e. to_string ( ) ) )
25113 }
26114}
115+
116+ #[ derive( uniffi:: Object ) ]
117+ struct OnchainSendResponse { }
118+
119+ #[ derive( uniffi:: Object ) ]
120+ struct OnchainSendRequest {
121+ label : String ,
122+ description : String ,
123+ amount_msat : Option < u64 > ,
124+ }
125+
126+ #[ derive( uniffi:: Enum ) ]
127+ enum AddressType {
128+ BECH32 ,
129+ P2TR ,
130+ }
131+
132+ #[ derive( uniffi:: Object ) ]
133+ struct OnchainReceiveResponse {
134+ address : String ,
135+ }
136+
137+ #[ derive( uniffi:: Object ) ]
138+ struct SendResponse { }
139+
140+ #[ derive( uniffi:: Object ) ]
141+ struct ReceiveResponse {
142+ bolt11 : String ,
143+ }
0 commit comments