github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/cmd/rs-af/litrpc.rs (about)

     1  #![allow(unused)]
     2  #![allow(non_snake_case)]
     3  
     4  #![feature(concat_idents)]
     5  
     6  use std::net::TcpStream;
     7  
     8  use std::fmt;
     9  
    10  use reqwest;
    11  
    12  use serde::{Serialize, Deserialize};
    13  use serde::de::DeserializeOwned;
    14  
    15  use serde_json;
    16  
    17  #[derive(Clone, Debug, Serialize)]
    18  struct RpcReqest<P> where P: Serialize {
    19      method: String,
    20      params: Vec<P>,
    21      jsonrpc: String,
    22      id: u64
    23  }
    24  
    25  #[derive(Clone, Debug, Deserialize)]
    26  struct RpcResponse<R> {
    27      //#[serde(default="Option::None")]
    28      result: Option<R>,
    29  
    30      //#[serde(default="Option::None")]
    31      error: Option<RpcError>,
    32  
    33      id: u64
    34  }
    35  
    36  #[derive(Clone, Debug, Deserialize)]
    37  pub struct RpcError {
    38      code: i64,
    39      message: String,
    40      data: String
    41  }
    42  
    43  pub struct LitRpcClient {
    44      next_msg_id: u64,
    45      url: String,
    46      client: reqwest::Client
    47  }
    48  
    49  #[derive(Debug)]
    50  pub enum LitRpcError {
    51      RpcError(RpcError),
    52      RpcInvalidResponse,
    53      SerdeJsonError(serde_json::Error),
    54      HttpError(reqwest::Error),
    55  }
    56  
    57  impl From<reqwest::Error> for LitRpcError {
    58      fn from(from: reqwest::Error) -> Self {
    59          LitRpcError::HttpError(from)
    60      }
    61  }
    62  
    63  impl From<serde_json::Error> for LitRpcError {
    64      fn from(from: serde_json::Error) -> Self {
    65          LitRpcError::SerdeJsonError(from)
    66      }
    67  }
    68  
    69  impl LitRpcClient {
    70      pub fn new(addr: &str, port: u16) -> LitRpcClient {
    71          LitRpcClient {
    72              next_msg_id: 0,
    73              url: format!("http://{}:{}/oneoff", addr, port),
    74              client: reqwest::Client::new()
    75          }
    76      }
    77  
    78      pub fn call<P: Serialize, R: DeserializeOwned>(&mut self, name: &str, params: P) -> Result<R, LitRpcError> {
    79  
    80          // Construct the request object.
    81          let req = RpcReqest {
    82              method: String::from(name),
    83              params: vec![params],
    84              jsonrpc: String::from("2.0"), // required by the standard
    85              id: self.next_msg_id
    86          };
    87  
    88          // Increment the "next" value to not confuse request IDs.
    89          self.next_msg_id += 1;
    90  
    91          // Serialize the request.
    92          let req_body = serde_json::to_string(&req)?;
    93          eprintln!("request: {}", req_body);
    94  
    95          // Send it off and get a response.
    96          let mut res_json = self.client.post(self.url.as_str())
    97              .body(req_body)
    98              .send()?;
    99          let text = res_json.text()?;
   100          eprintln!("reponse: {}", text);
   101  
   102          // Deserialize...
   103          let res: RpcResponse<R> = serde_json::from_str(text.as_ref())?;
   104          if res.id != req.id {
   105              // Ok this makes no sense but we should fail out anyways.
   106              return Err(LitRpcError::RpcInvalidResponse)
   107          }
   108  
   109          // And then match on the response part thingies to figure out what to do.
   110          match (res.result, res.error) {
   111              (Some(r), None) => Ok(r),
   112              (None, Some(e)) => Err(LitRpcError::RpcError(e)),
   113              _ => Err(LitRpcError::RpcInvalidResponse)
   114          }
   115  
   116      }
   117  }
   118  
   119  macro_rules! rpc_call {
   120      {$fname:ident, $method:ident, { $($ii:ident: $it:ty),* } => $oname:ident { $($oi:ident: $ot:ty),* }} => {
   121  
   122          #[derive(Clone, Deserialize)]
   123          #[allow(non_snake_case)]
   124          pub struct $oname {
   125              $( pub $oi: $ot ),*
   126          }
   127  
   128          impl LitRpcClient {
   129  
   130              #[allow(non_snake_case)]
   131              pub fn $fname(&mut self, $($ii: $it),*) -> Result<$oname, LitRpcError> {
   132  
   133                  #[derive(Clone, Debug, Serialize)]
   134                  #[allow(non_snake_case)]
   135                  struct Params {
   136                      $( $ii: $it ),*
   137                  };
   138  
   139                  let arg = Params {
   140                      $($ii: $ii),*
   141                  };
   142  
   143                  self.call(concat!("LitRPC.", stringify!($method)), arg)
   144              }
   145          }
   146  
   147      };
   148      {$fname:ident, $method:ident, { $($ii:ident: $it:ty),* } => $oname:ident} => {
   149  
   150          impl LitRpcClient {
   151  
   152              #[allow(non_snake_case)]
   153              pub fn $fname(&mut self, $($ii: $it),*) -> Result<$oname, LitRpcError> {
   154  
   155                  #[derive(Clone, Debug, Serialize)]
   156                  #[allow(non_snake_case)]
   157                  struct Params {
   158                      $( $ii: $it ),*
   159                  };
   160  
   161                  let arg = Params {
   162                      $($ii: $ii),*
   163                  };
   164  
   165                  self.call(concat!("LitRPC.", stringify!($method)), arg)
   166              }
   167          }
   168  
   169      };
   170  }
   171  
   172  #[derive(Clone, Deserialize)]
   173  pub struct StatusReply {
   174      Status: String
   175  }
   176  
   177  impl fmt::Debug for StatusReply {
   178      fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
   179          f.write_str(format!("status: {}", self.Status).as_ref())
   180      }
   181  }
   182  
   183  // netcmds
   184  
   185  #[derive(Clone, Deserialize)]
   186  pub struct ListeningPortsReply {
   187      LisIpPorts: Vec<String>,
   188      Adr: String
   189  }
   190  
   191  rpc_call! {
   192      call_lis, Listen,
   193      { Port: String } => ListeningPortsReply
   194  }
   195  
   196  rpc_call! {
   197      call_connect, Connect,
   198      { LNAddr: String } => StatusReply
   199  }
   200  
   201  rpc_call! {
   202      call_assign_nickname, AssignNickname,
   203      { Peer: u32, Nickname: String } => StatusReply
   204  }
   205  
   206  #[derive(Clone, Deserialize)]
   207  pub struct ConInfo {
   208      PeerNumber: u32,
   209      RemoteHost: String
   210  }
   211  
   212  rpc_call! {
   213      call_list_connections, ListConnections,
   214      {} => ListConnectionsReply { Connections: Vec<ConInfo>, MyPKH: String }
   215  }
   216  
   217  rpc_call! {
   218      call_get_listening_ports, GetListeningPorts,
   219      {} => ListeningPortsReply
   220  }
   221  
   222  rpc_call! { call_get_messages, GetMessages, {} => StatusReply }
   223  rpc_call! { call_say, Say, {} => StatusReply }
   224  rpc_call! { call_stop, Stop, {} => StatusReply }
   225  
   226  rpc_call! {
   227      call_get_chan_map, GetChannelMap,
   228      {} => ChanGraphReply { Graph: String }
   229  }
   230  
   231  // chancmds
   232  
   233  #[derive(Clone, Debug, Deserialize)]
   234  pub struct ChanInfo {
   235      pub OutPoint: String,
   236      pub CoinType: u32,
   237      pub Closed: bool,
   238      pub Capacity: i64,
   239      pub MyBalance: i64,
   240      pub Height: i32,
   241      pub StateNum: i64,
   242      pub PeerIdx: u32,
   243      pub CIdx: u32,
   244      pub Data: [u8; 32],
   245      pub Pkh: [u8; 20],
   246      pub LastUpdate: u64
   247  }
   248  
   249  rpc_call! {
   250      call_chan_list, ChannelList,
   251      { ChanIdx: u32 } => ChanListReply { Channels: Vec<ChanInfo> }
   252  }
   253  
   254  rpc_call! {
   255      call_fund, FundChannel,
   256      {
   257          Peer: u32,
   258          CoinType: u32,
   259          Capacity: i64,
   260          Roundup: i64,
   261          InitialSend: i64,
   262          Data: [u8; 32]
   263      } => StatusReply
   264  }
   265  
   266  rpc_call! {
   267      call_dual_fund, DualFundChannel,
   268      {
   269          Peer: i32,
   270          CoinType: i32,
   271          OurAmount: i64,
   272          TheirAmount: i64
   273      } => StatusReply
   274  }
   275  
   276  // TODO DualFundDecline, DualFundAccept, etc.
   277  
   278  rpc_call! {
   279      call_get_pending_dual_fund, PendingDualFund,
   280      {} => PendingDualFundReply {
   281          Pending: bool,
   282          PeerIdx: u32,
   283          CoinType: u32,
   284          TheirAmount: i64,
   285          RequestedAmount: i64
   286      }
   287  }
   288  
   289  /* TODO No auto-Deserialize for [u8; 64], do something about this later.
   290  #[derive(Clone, Deserialize)]
   291  pub struct JusticeTx {
   292      Sig: [u8; 64],
   293      Txid: [u8; 16],
   294      Amt: i64,
   295      Data: [u8; 32],
   296      Pkh: [u8; 20],
   297      Idx: u64
   298  }
   299  
   300  rpc_call! {
   301      call_get_state_dump, StateDump,
   302      {} => StateDumpReply {
   303          Txs: Vec<JusticeTx>
   304      }
   305  }
   306  */
   307  
   308  rpc_call! {
   309      call_push, Push,
   310      {
   311          ChanIdx: u32,
   312          Amt: i64,
   313          Data: [u8; 32]
   314      } => PushReply {
   315          StateIdx: u64
   316      }
   317  }
   318  
   319  rpc_call! {
   320      call_close_chan, CloseChannel,
   321      { ChanIdx: u32 } => StatusReply
   322  }
   323  
   324  rpc_call! {
   325      call_break_chan, BreakChannel,
   326      { ChanIdx: u32 } => StatusReply
   327  }
   328  
   329  #[derive(Clone, Deserialize)]
   330  pub struct PrivInfo {
   331      pub OutPoint: String,
   332      pub Amt: i64,
   333      pub Height: i32,
   334      pub Delay: i32,
   335      pub CoinType: String,
   336      pub Witty: bool,
   337      pub PairKey: String,
   338      pub WIF: String
   339  }
   340  
   341  rpc_call! {
   342      call_dump_privs, DumpPrivs,
   343      {} => DumpPrivsReply { Privs: Vec<PrivInfo> }
   344  }
   345  
   346  // walletcmds
   347  
   348  #[derive(Clone, Deserialize)]
   349  pub struct CoinBalInfo {
   350      pub CoinType: u32,
   351      pub SyncHeight: i32,
   352      pub ChanTotal: i64,
   353      pub TxoTotal: i64,
   354      pub MatureWitty: i64,
   355      pub FeeRate: i64
   356  }
   357  
   358  rpc_call! {
   359      call_bal, Balance,
   360      {} => BalanceReply { Balances: Vec<CoinBalInfo> }
   361  }
   362  
   363  #[derive(Clone, Debug, Deserialize)]
   364  pub struct TxoInfo {
   365      pub OutPoint: String,
   366      pub Amt: i64,
   367      pub Height: i32,
   368      pub Delay: i32,
   369      pub CoinType: String,
   370      pub Witty: bool,
   371      pub KeyPath: String
   372  }
   373  
   374  rpc_call! {
   375      call_get_txo_list, TxoList,
   376      {} => TxoListReply { Txos: Vec<TxoInfo> }
   377  }
   378  
   379  #[derive(Clone, Deserialize)]
   380  pub struct TxidsReply {
   381      pub Txids: Vec<String>
   382  }
   383  
   384  rpc_call! {
   385      call_send, Send, // oh no it's already an identifier whoops
   386      {
   387          DestAddrs: Vec<String>,
   388          Amts: Vec<i64>
   389      } => TxidsReply
   390  }
   391  
   392  rpc_call! {
   393      call_sweep, Sweep,
   394      {
   395          DestAdr: String,
   396          NumTx: u32,
   397          Drop: bool // oh no it's an identifier too, whoops!
   398      } => TxidsReply
   399  }
   400  
   401  rpc_call! {
   402      call_fanout, Fanout,
   403      {
   404          DestAdr: String,
   405          NumOutputs: u32,
   406          AmtPerOutput: i64
   407      } => TxidsReply
   408  }
   409  
   410  #[derive(Clone, Deserialize)]
   411  pub struct FeeReply {
   412      pub CurrentFee: i64
   413  }
   414  
   415  rpc_call! {
   416      call_set_fee, SetFee,
   417      { Fee: i64, CoinType: u32 } => FeeReply
   418  }
   419  
   420  rpc_call! {
   421      call_get_fee, GetFee,
   422      { CoinType: u32 } => FeeReply
   423  }
   424  
   425  #[derive(Clone, Deserialize)]
   426  pub struct AddressReply {
   427      pub CoinTypes: Vec<u32>,
   428      pub WitAddresses: Vec<String>,
   429      pub LegacyAddresses: Vec<String>
   430  }
   431  
   432  rpc_call! {
   433      call_gen_address, Address,
   434      {
   435          NumToMake: u32,
   436          CoinType: u32
   437      } => AddressReply
   438  }
   439  
   440  rpc_call! {
   441      call_get_addresses, GetAddresses,
   442      {} => AddressReply
   443  }
   444  
   445  // TODO make RPC call definitions