@@ -7,11 +7,17 @@ import (
77 "os"
88 "strconv"
99
10+ "github.com/lightninglabs/lightning-terminal/accounts"
1011 "github.com/lightninglabs/lightning-terminal/litrpc"
1112 "github.com/lightningnetwork/lnd/lncfg"
1213 "github.com/urfave/cli"
1314)
1415
16+ const (
17+ idName = "id"
18+ labelName = "label"
19+ )
20+
1521var accountsCommands = []cli.Command {
1622 {
1723 Name : "accounts" ,
@@ -22,6 +28,7 @@ var accountsCommands = []cli.Command{
2228 createAccountCommand ,
2329 updateAccountCommand ,
2430 listAccountsCommand ,
31+ accountInfoCommand ,
2532 removeAccountCommand ,
2633 },
2734 },
@@ -31,7 +38,7 @@ var createAccountCommand = cli.Command{
3138 Name : "create" ,
3239 ShortName : "c" ,
3340 Usage : "Create a new off-chain account with a balance." ,
34- ArgsUsage : "balance [expiration_date]" ,
41+ ArgsUsage : "balance [expiration_date] [--label=LABEL] [--save_to=FILE] " ,
3542 Description : `
3643 Adds an entry to the account database. This entry represents an amount
3744 of satoshis (account balance) that can be spent using off-chain
@@ -61,6 +68,10 @@ var createAccountCommand = cli.Command{
6168 Usage : "store the account macaroon created for the " +
6269 "account to the given file" ,
6370 },
71+ cli.StringFlag {
72+ Name : labelName ,
73+ Usage : "(optional) the unique label of the account" ,
74+ },
6475 },
6576 Action : createAccount ,
6677}
@@ -111,6 +122,7 @@ func createAccount(ctx *cli.Context) error {
111122 req := & litrpc.CreateAccountRequest {
112123 AccountBalance : initialBalance ,
113124 ExpirationDate : expirationDate ,
125+ Label : ctx .String (labelName ),
114126 }
115127 resp , err := client .CreateAccount (ctxb , req )
116128 if err != nil {
@@ -139,16 +151,20 @@ var updateAccountCommand = cli.Command{
139151 Name : "update" ,
140152 ShortName : "u" ,
141153 Usage : "Update an existing off-chain account." ,
142- ArgsUsage : "id new_balance [new_expiration_date] [--save_to=]" ,
154+ ArgsUsage : "[id | label] new_balance [new_expiration_date] [--save_to=]" ,
143155 Description : `
144156 Updates an existing off-chain account and sets either a new balance or
145157 new expiration date or both.
146158 ` ,
147159 Flags : []cli.Flag {
148160 cli.StringFlag {
149- Name : "id" ,
161+ Name : idName ,
150162 Usage : "the ID of the account to update" ,
151163 },
164+ cli.StringFlag {
165+ Name : labelName ,
166+ Usage : "(optional) the unique label of the account" ,
167+ },
152168 cli.Int64Flag {
153169 Name : "new_balance" ,
154170 Usage : "the new balance of the account; -1 means do " +
@@ -176,29 +192,15 @@ func updateAccount(ctx *cli.Context) error {
176192 defer cleanup ()
177193 client := litrpc .NewAccountsClient (clientConn )
178194
195+ id , label , args , err := parseIDOrLabel (ctx )
196+ if err != nil {
197+ return err
198+ }
199+
179200 var (
180- id []byte
181201 newBalance int64
182202 expirationDate int64
183203 )
184- args := ctx .Args ()
185-
186- // We parse the ID as hex even though we're supposed to send it as a hex
187- // encoded string over the RPC. But that way we can verify it's actually
188- // the id.
189- switch {
190- case ctx .IsSet ("id" ):
191- id , err = hex .DecodeString (ctx .String ("id" ))
192- case args .Present ():
193- id , err = hex .DecodeString (args .First ())
194- args = args .Tail ()
195- default :
196- return fmt .Errorf ("id is missing" )
197- }
198- if err != nil {
199- return fmt .Errorf ("error decoding id: %v" , err )
200- }
201-
202204 switch {
203205 case ctx .IsSet ("new_balance" ):
204206 newBalance = ctx .Int64 ("new_balance" )
@@ -224,7 +226,8 @@ func updateAccount(ctx *cli.Context) error {
224226 }
225227
226228 req := & litrpc.UpdateAccountRequest {
227- Id : hex .EncodeToString (id ),
229+ Id : id ,
230+ Label : label ,
228231 AccountBalance : newBalance ,
229232 ExpirationDate : expirationDate ,
230233 }
@@ -267,19 +270,71 @@ func listAccounts(ctx *cli.Context) error {
267270 return nil
268271}
269272
273+ var accountInfoCommand = cli.Command {
274+ Name : "info" ,
275+ ShortName : "i" ,
276+ Usage : "Show information about a single off-chain account." ,
277+ ArgsUsage : "[id | label]" ,
278+ Description : `
279+ Returns a single account entry from the account database.
280+ ` ,
281+ Flags : []cli.Flag {
282+ cli.StringFlag {
283+ Name : idName ,
284+ Usage : "the ID of the account" ,
285+ },
286+ cli.StringFlag {
287+ Name : labelName ,
288+ Usage : "(optional) the unique label of the account" ,
289+ },
290+ },
291+ Action : accountInfo ,
292+ }
293+
294+ func accountInfo (ctx * cli.Context ) error {
295+ ctxb := context .Background ()
296+ clientConn , cleanup , err := connectClient (ctx )
297+ if err != nil {
298+ return err
299+ }
300+ defer cleanup ()
301+ client := litrpc .NewAccountsClient (clientConn )
302+
303+ id , label , _ , err := parseIDOrLabel (ctx )
304+ if err != nil {
305+ return err
306+ }
307+
308+ req := & litrpc.AccountInfoRequest {
309+ Id : id ,
310+ Label : label ,
311+ }
312+ resp , err := client .AccountInfo (ctxb , req )
313+ if err != nil {
314+ return err
315+ }
316+
317+ printRespJSON (resp )
318+ return nil
319+ }
320+
270321var removeAccountCommand = cli.Command {
271322 Name : "remove" ,
272323 ShortName : "r" ,
273324 Usage : "Removes an off-chain account from the database." ,
274- ArgsUsage : "id " ,
325+ ArgsUsage : "[id | label] " ,
275326 Description : `
276327 Removes an account entry from the account database.
277328 ` ,
278329 Flags : []cli.Flag {
279330 cli.StringFlag {
280- Name : "id" ,
331+ Name : idName ,
281332 Usage : "the ID of the account" ,
282333 },
334+ cli.StringFlag {
335+ Name : labelName ,
336+ Usage : "(optional) the unique label of the account" ,
337+ },
283338 },
284339 Action : removeAccount ,
285340}
@@ -293,29 +348,59 @@ func removeAccount(ctx *cli.Context) error {
293348 defer cleanup ()
294349 client := litrpc .NewAccountsClient (clientConn )
295350
296- var accountID string
351+ id , label , _ , err := parseIDOrLabel (ctx )
352+ if err != nil {
353+ return err
354+ }
355+
356+ req := & litrpc.RemoveAccountRequest {
357+ Id : id ,
358+ Label : label ,
359+ }
360+ _ , err = client .RemoveAccount (ctxb , req )
361+ return err
362+ }
363+
364+ // parseIDOrLabel parses either the id or label from the command line.
365+ func parseIDOrLabel (ctx * cli.Context ) (string , string , cli.Args , error ) {
366+ var (
367+ accountID string
368+ label string
369+ )
297370 args := ctx .Args ()
298371
299372 switch {
300- case ctx .IsSet ("id" ):
301- accountID = ctx .String ("id" )
373+ case ctx .IsSet (idName ) && ctx .IsSet (labelName ):
374+ return "" , "" , nil , fmt .Errorf ("either account ID or label " +
375+ "must be specified, not both" )
376+
377+ case ctx .IsSet (idName ):
378+ accountID = ctx .String (idName )
379+
380+ case ctx .IsSet (labelName ):
381+ label = ctx .String (labelName )
382+
302383 case args .Present ():
303384 accountID = args .First ()
304385 args = args .Tail ()
305- default :
306- return fmt .Errorf ("id argument missing" )
307- }
308386
309- if len (accountID ) == 0 {
310- return fmt .Errorf ("id argument missing" )
311- }
312- if _ , err := hex .DecodeString (accountID ); err != nil {
313- return err
314- }
387+ // Since we have a positional argument, we cannot be sure it's
388+ // an ID. So we check if it's an ID by trying to hex decode it
389+ // and by checking the length. This will break if the user
390+ // chooses labels that are also valid hex encoded IDs. But since
391+ // the label is supposed to be human-readable, this should be
392+ // unlikely.
393+ _ , err := hex .DecodeString (accountID )
394+ if len (accountID ) != hex .EncodedLen (accounts .AccountIDLen ) ||
395+ err != nil {
396+
397+ label = accountID
398+ accountID = ""
399+ }
315400
316- req := & litrpc. RemoveAccountRequest {
317- Id : accountID ,
401+ default :
402+ return "" , "" , nil , fmt . Errorf ( "id argument missing" )
318403 }
319- _ , err = client . RemoveAccount ( ctxb , req )
320- return err
404+
405+ return accountID , label , args , nil
321406}
0 commit comments