github.com/decred/dcrlnd@v0.7.6/docs/grpc/javascript.md (about)

     1  # How to write a simple `lnd` client in Javascript using `node.js`
     2  
     3  ## Setup and Installation
     4  
     5  First, you'll need to initialize a simple nodejs project:
     6  ```
     7  npm init (or npm init -f if you want to use the default values without prompt)
     8  ```
     9  
    10  Then you need to install the Javascript grpc and proto loader library
    11  dependencies:
    12  ```
    13  npm install @grpc/grpc-js @grpc/proto-loader --save
    14  ```
    15  
    16  You also need to copy the `lnd` `lightning.proto` file in your project directory
    17  (or at least somewhere reachable by your Javascript code).
    18  
    19  The `lightning.proto` file is [located in the `lnrpc` directory of the `lnd`
    20  sources](https://github.com/lightningnetwork/lnd/blob/master/lnrpc/lightning.proto).
    21  
    22  ### Imports and Client
    23  
    24  Every time you work with Javascript gRPC, you will have to import `@grpc/grpc-js`, load
    25  `lightning.proto`, and create a connection to your client like so.
    26  
    27  Note that when an IP address is used to connect to the node (e.g. 192.168.1.21 instead of localhost) you need to add `--tlsextraip=192.168.1.21` to your `lnd` configuration and re-generate the certificate (delete tls.cert and tls.key and restart lnd).
    28  
    29  ```js
    30  const grpc = require('@grpc/grpc-js');
    31  const protoLoader = require('@grpc/proto-loader');
    32  const fs = require("fs");
    33  
    34  // Due to updated ECDSA generated tls.cert we need to let gprc know that
    35  // we need to use that cipher suite otherwise there will be a handhsake
    36  // error when we communicate with the lnd rpc server.
    37  process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA'
    38  
    39  // We need to give the proto loader some extra options, otherwise the code won't
    40  // fully work with lnd.
    41  const loaderOptions = {
    42    keepCase: true,
    43    longs: String,
    44    enums: String,
    45    defaults: true,
    46    oneofs: true
    47  };
    48  const packageDefinition = protoLoader.loadSync('lightning.proto', loaderOptions);
    49  
    50  //  Lnd cert is at ~/.lnd/tls.cert on Linux and
    51  //  ~/Library/Application Support/Lnd/tls.cert on Mac
    52  let lndCert = fs.readFileSync("~/.lnd/tls.cert");
    53  let credentials = grpc.credentials.createSsl(lndCert);
    54  let lnrpcDescriptor = grpc.loadPackageDefinition(packageDefinition);
    55  let lnrpc = lnrpcDescriptor.lnrpc;
    56  let lightning = new lnrpc.Lightning('localhost:10009', credentials);
    57  ```
    58  
    59  ## Examples
    60  
    61  Let's walk through some examples of Javascript gRPC clients. These examples
    62  assume that you have at least two `lnd` nodes running, the RPC location of one
    63  of which is at the default `localhost:10009`, with an open channel between the
    64  two nodes.
    65  
    66  ### Simple RPC
    67  
    68  ```js
    69  lightning.getInfo({}, function(err, response) {
    70    if (err) {
    71      console.log('Error: ' + err);
    72    }
    73    console.log('GetInfo:', response);
    74  });
    75  ```
    76  
    77  You should get something like this in your console:
    78  
    79  ```
    80  GetInfo: { identity_pubkey: '03c892e3f3f077ea1e381c081abb36491a2502bc43ed37ffb82e264224f325ff27',
    81    alias: '',
    82    num_pending_channels: 0,
    83    num_active_channels: 1,
    84    num_inactive_channels: 0,
    85    num_peers: 1,
    86    block_height: 1006,
    87    block_hash: '198ba1dc43b4190e507fa5c7aea07a74ec0009a9ab308e1736dbdab5c767ff8e',
    88    synced_to_chain: false,
    89    testnet: false,
    90    chains: [ 'bitcoin' ] }
    91  ```
    92  
    93  ### Response-streaming RPC
    94  
    95  ```js
    96  let call = lightning.subscribeInvoices({});
    97  call.on('data', function(invoice) {
    98      console.log(invoice);
    99  })
   100  .on('end', function() {
   101    // The server has finished sending
   102  })
   103  .on('status', function(status) {
   104    // Process status
   105    console.log("Current status" + status);
   106  });
   107  ```
   108  
   109  Now, create an invoice for your node at `localhost:10009`and send a payment to
   110  it from another node.
   111  ```bash
   112  $ lncli addinvoice --amt=100
   113  {
   114  	"r_hash": <RHASH>,
   115  	"pay_req": <PAYMENT_REQUEST>
   116  }
   117  $ lncli sendpayment --pay_req=<PAYMENT_REQUEST>
   118  ```
   119  Your Javascript console should now display the details of the recently satisfied
   120  invoice.
   121  
   122  ### Bidirectional-streaming RPC
   123  
   124  This example has a few dependencies:
   125  ```shell
   126  npm install --save async lodash bytebuffer
   127  ```
   128  
   129  You can run the following in your shell or put it in a program and run it like
   130  `node script.js`
   131  
   132  ```js
   133  // Load some libraries specific to this example
   134  const async = require('async');
   135  const _ = require('lodash');
   136  const ByteBuffer = require('bytebuffer');
   137  
   138  let dest_pubkey = <RECEIVER_ID_PUBKEY>;
   139  let dest_pubkey_bytes = ByteBuffer.fromHex(dest_pubkey);
   140  
   141  // Set a listener on the bidirectional stream
   142  let call = lightning.sendPayment();
   143  call.on('data', function(payment) {
   144    console.log("Payment sent:");
   145    console.log(payment);
   146  });
   147  call.on('end', function() {
   148    // The server has finished
   149    console.log("END");
   150  });
   151  
   152  // You can send single payments like this
   153  call.write({ dest: dest_pubkey_bytes, amt: 6969 });
   154  
   155  // Or send a bunch of them like this
   156  function paymentSender(destination, amount) {
   157    return function(callback) {
   158      console.log("Sending " + amount + " atoms");
   159      console.log("To: " + destination);
   160      call.write({
   161        dest: destination,
   162        amt: amount
   163      });
   164      _.delay(callback, 2000);
   165    };
   166  }
   167  let payment_senders = [];
   168  for (let i = 0; i < 10; i++) {
   169    payment_senders[i] = paymentSender(dest_pubkey_bytes, 100);
   170  }
   171  async.series(payment_senders, function() {
   172    call.end();
   173  });
   174  
   175  ```
   176  This example will send a payment of 100 atoms every 2 seconds.
   177  
   178  
   179  ### Using Macaroons
   180  
   181  To authenticate using macaroons you need to include the macaroon in the metadata
   182  of each request.
   183  
   184  The following snippet will add the macaroon to every request automatically:
   185  
   186  ```js
   187  const fs = require('fs');
   188  const grpc = require('@grpc/grpc-js');
   189  const protoLoader = require('@grpc/proto-loader');
   190  const loaderOptions = {
   191    keepCase: true,
   192    longs: String,
   193    enums: String,
   194    defaults: true,
   195    oneofs: true
   196  };
   197  const packageDefinition = protoLoader.loadSync('lightning.proto', loaderOptions);
   198  
   199  process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA'
   200  
   201  // Lnd admin macaroon is at ~/.lnd/data/chain/bitcoin/simnet/admin.macaroon on Linux and
   202  // ~/Library/Application Support/Lnd/data/chain/bitcoin/simnet/admin.macaroon on Mac
   203  let m = fs.readFileSync('~/.lnd/data/chain/bitcoin/simnet/admin.macaroon');
   204  let macaroon = m.toString('hex');
   205  
   206  // build meta data credentials
   207  let metadata = new grpc.Metadata()
   208  metadata.add('macaroon', macaroon)
   209  let macaroonCreds = grpc.credentials.createFromMetadataGenerator((_args, callback) => {
   210    callback(null, metadata);
   211  });
   212  
   213  // build ssl credentials using the cert the same as before
   214  let lndCert = fs.readFileSync("~/.lnd/tls.cert");
   215  let sslCreds = grpc.credentials.createSsl(lndCert);
   216  
   217  // combine the cert credentials and the macaroon auth credentials
   218  // such that every call is properly encrypted and authenticated
   219  let credentials = grpc.credentials.combineChannelCredentials(sslCreds, macaroonCreds);
   220  
   221  // Pass the crendentials when creating a channel
   222  let lnrpcDescriptor = grpc.loadPackageDefinition(packageDefinition);
   223  let lnrpc = lnrpcDescriptor.lnrpc;
   224  let client = new lnrpc.Lightning('some.address:10009', credentials);
   225  
   226  client.getInfo({}, (err, response) => {
   227    if (err) {
   228      console.log('Error: ' + err);
   229    }
   230    console.log('GetInfo:', response);
   231  });
   232  ```
   233  
   234  ## Conclusion
   235  
   236  With the above, you should have all the `lnd` related `gRPC` dependencies
   237  installed locally in your project. In order to get up to speed with `protofbuf`
   238  usage from Javascript, see [this official `protobuf` reference for
   239  Javascript](https://developers.google.com/protocol-buffers/docs/reference/javascript-generated).
   240  Additionally, [this official gRPC
   241  resource](http://www.grpc.io/docs/tutorials/basic/node.html) provides more
   242  details around how to drive `gRPC` from `node.js`.
   243  
   244  ## API documentation
   245  
   246  There is an [online API documentation](https://api.lightning.community?javascript)
   247  available that shows all currently existing RPC methods, including code snippets
   248  on how to use them.