2021-03-05 20:08:14 +00:00
package cliutil
import (
"context"
2021-07-28 14:56:45 +00:00
"errors"
2021-03-05 20:08:14 +00:00
"fmt"
"net/http"
"net/url"
"os"
"os/signal"
2022-09-27 16:08:04 +00:00
"reflect"
2021-03-05 20:08:14 +00:00
"strings"
"syscall"
2022-09-28 15:07:05 +00:00
"time"
2021-03-05 20:08:14 +00:00
2022-10-18 02:44:00 +00:00
"github.com/mitchellh/go-homedir"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
2021-03-05 20:08:14 +00:00
"github.com/filecoin-project/go-jsonrpc"
2023-11-14 00:06:11 +00:00
2021-03-05 20:08:14 +00:00
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/client"
2021-04-01 12:17:22 +00:00
"github.com/filecoin-project/lotus/api/v0api"
2021-04-06 11:36:16 +00:00
"github.com/filecoin-project/lotus/api/v1api"
2022-10-18 02:44:00 +00:00
"github.com/filecoin-project/lotus/lib/retry"
2021-03-05 20:08:14 +00:00
"github.com/filecoin-project/lotus/node/repo"
)
const (
metadataTraceContext = "traceContext"
)
2021-07-29 09:55:37 +00:00
// GetAPIInfo returns the API endpoint to use for the specified kind of repo.
//
// The order of precedence is as follows:
//
// 1. *-api-url command line flags.
// 2. *_API_INFO environment variables
// 3. deprecated *_API_INFO environment variables
// 4. *-repo command line flags.
2022-09-27 16:08:04 +00:00
func GetAPIInfoMulti ( ctx * cli . Context , t repo . RepoType ) ( [ ] APIInfo , error ) {
2021-03-05 20:08:14 +00:00
// Check if there was a flag passed with the listen address of the API
// server (only used by the tests)
2022-03-03 15:45:11 +00:00
for _ , f := range t . APIFlags ( ) {
2021-07-29 09:55:37 +00:00
if ! ctx . IsSet ( f ) {
continue
}
strma := ctx . String ( f )
2021-03-05 20:08:14 +00:00
strma = strings . TrimSpace ( strma )
2022-10-18 19:53:42 +00:00
return [ ] APIInfo { { Addr : strma } } , nil
2021-03-05 20:08:14 +00:00
}
2021-07-29 15:10:04 +00:00
//
// Note: it is not correct/intuitive to prefer environment variables over
// CLI flags (repo flags below).
//
2022-03-03 15:45:11 +00:00
primaryEnv , fallbacksEnvs , deprecatedEnvs := t . APIInfoEnvVars ( )
2021-07-29 15:10:04 +00:00
env , ok := os . LookupEnv ( primaryEnv )
if ok {
2022-09-27 16:08:04 +00:00
return ParseApiInfoMulti ( env ) , nil
2021-03-05 20:08:14 +00:00
}
2021-07-29 09:55:37 +00:00
2021-07-29 15:10:04 +00:00
for _ , env := range deprecatedEnvs {
2021-07-29 09:55:37 +00:00
env , ok := os . LookupEnv ( env )
if ok {
2021-07-29 15:10:04 +00:00
log . Warnf ( "Using deprecated env(%s) value, please use env(%s) instead." , env , primaryEnv )
2022-09-27 16:08:04 +00:00
return ParseApiInfoMulti ( env ) , nil
2021-07-29 09:55:37 +00:00
}
2021-03-05 20:08:14 +00:00
}
2022-03-03 15:45:11 +00:00
for _ , f := range t . RepoFlags ( ) {
2021-07-29 12:49:47 +00:00
// cannot use ctx.IsSet because it ignores default values
2021-07-29 13:36:04 +00:00
path := ctx . String ( f )
if path == "" {
2021-07-29 09:55:37 +00:00
continue
}
2021-03-05 20:08:14 +00:00
2021-07-29 13:36:04 +00:00
p , err := homedir . Expand ( path )
2021-07-29 09:55:37 +00:00
if err != nil {
2022-09-27 16:08:04 +00:00
return [ ] APIInfo { } , xerrors . Errorf ( "could not expand home dir (%s): %w" , f , err )
2021-07-29 09:55:37 +00:00
}
2021-03-05 20:08:14 +00:00
2021-07-29 09:55:37 +00:00
r , err := repo . NewFS ( p )
if err != nil {
2022-09-27 16:08:04 +00:00
return [ ] APIInfo { } , xerrors . Errorf ( "could not open repo at path: %s; %w" , p , err )
2021-07-29 09:55:37 +00:00
}
2021-07-28 14:56:45 +00:00
exists , err := r . Exists ( )
if err != nil {
2022-09-27 16:08:04 +00:00
return [ ] APIInfo { } , xerrors . Errorf ( "repo.Exists returned an error: %w" , err )
2021-07-28 14:56:45 +00:00
}
if ! exists {
2022-09-27 16:08:04 +00:00
return [ ] APIInfo { } , errors . New ( "repo directory does not exist. Make sure your configuration is correct" )
2021-07-28 14:56:45 +00:00
}
2021-03-05 20:08:14 +00:00
2021-07-29 09:55:37 +00:00
ma , err := r . APIEndpoint ( )
if err != nil {
2022-09-27 16:08:04 +00:00
return [ ] APIInfo { } , xerrors . Errorf ( "could not get api endpoint: %w" , err )
2021-07-29 09:55:37 +00:00
}
2021-03-05 20:08:14 +00:00
2021-07-29 09:55:37 +00:00
token , err := r . APIToken ( )
if err != nil {
log . Warnf ( "Couldn't load CLI token, capabilities may be limited: %v" , err )
}
2022-10-18 19:53:42 +00:00
return [ ] APIInfo { {
2021-07-29 09:55:37 +00:00
Addr : ma . String ( ) ,
Token : token ,
2022-09-27 16:08:04 +00:00
} } , nil
2021-03-05 20:08:14 +00:00
}
2021-07-29 15:10:04 +00:00
for _ , env := range fallbacksEnvs {
env , ok := os . LookupEnv ( env )
if ok {
2022-09-27 16:08:04 +00:00
return ParseApiInfoMulti ( env ) , nil
2021-07-29 15:10:04 +00:00
}
}
2023-11-13 23:59:34 +00:00
return [ ] APIInfo { } , fmt . Errorf ( "could not determine API endpoint for node type: %v. Try setting environment variable: %s" , t . Type ( ) , primaryEnv )
2021-03-05 20:08:14 +00:00
}
2022-09-27 16:08:04 +00:00
func GetAPIInfo ( ctx * cli . Context , t repo . RepoType ) ( APIInfo , error ) {
ainfos , err := GetAPIInfoMulti ( ctx , t )
2022-10-17 02:52:22 +00:00
if err != nil || len ( ainfos ) == 0 {
2022-09-27 16:08:04 +00:00
return APIInfo { } , err
}
if len ( ainfos ) > 1 {
log . Warn ( "multiple API infos received when only one was expected" )
2021-03-05 20:08:14 +00:00
}
2022-09-27 16:08:04 +00:00
return ainfos [ 0 ] , nil
}
type HttpHead struct {
addr string
header http . Header
}
func GetRawAPIMulti ( ctx * cli . Context , t repo . RepoType , version string ) ( [ ] HttpHead , error ) {
var httpHeads [ ] HttpHead
ainfos , err := GetAPIInfoMulti ( ctx , t )
2022-10-17 02:52:22 +00:00
if err != nil || len ( ainfos ) == 0 {
2022-09-27 16:08:04 +00:00
return httpHeads , xerrors . Errorf ( "could not get API info for %s: %w" , t . Type ( ) , err )
}
for _ , ainfo := range ainfos {
addr , err := ainfo . DialArgs ( version )
if err != nil {
return httpHeads , xerrors . Errorf ( "could not get DialArgs: %w" , err )
}
httpHeads = append ( httpHeads , HttpHead { addr : addr , header : ainfo . AuthHeader ( ) } )
2021-03-05 20:08:14 +00:00
}
2021-07-27 19:46:02 +00:00
if IsVeryVerbose {
2022-09-27 16:08:04 +00:00
_ , _ = fmt . Fprintf ( ctx . App . Writer , "using raw API %s endpoint: %s\n" , version , httpHeads [ 0 ] . addr )
2021-07-27 13:25:28 +00:00
}
2022-09-27 16:08:04 +00:00
return httpHeads , nil
}
2023-10-16 15:28:58 +00:00
func GetRawAPIMultiV2 ( ctx * cli . Context , ainfoCfg [ ] string , version string ) ( [ ] HttpHead , error ) {
var httpHeads [ ] HttpHead
if len ( ainfoCfg ) == 0 {
2023-11-13 22:23:29 +00:00
return httpHeads , xerrors . Errorf ( "could not get API info: none configured. \nConsider getting base.toml with './lotus-provider config get base >/tmp/base.toml' \nthen adding \n[APIs] \n ChainApiInfo = [\" result_from lotus auth api-info --perm=admin \"]\n and updating it with './lotus-provider config set /tmp/base.toml'" )
2023-10-16 15:28:58 +00:00
}
for _ , i := range ainfoCfg {
ainfo := ParseApiInfo ( i )
addr , err := ainfo . DialArgs ( version )
if err != nil {
return httpHeads , xerrors . Errorf ( "could not get DialArgs: %w" , err )
}
httpHeads = append ( httpHeads , HttpHead { addr : addr , header : ainfo . AuthHeader ( ) } )
}
if IsVeryVerbose {
_ , _ = fmt . Fprintf ( ctx . App . Writer , "using raw API %s endpoint: %s\n" , version , httpHeads [ 0 ] . addr )
}
return httpHeads , nil
}
2022-09-27 16:08:04 +00:00
func GetRawAPI ( ctx * cli . Context , t repo . RepoType , version string ) ( string , http . Header , error ) {
heads , err := GetRawAPIMulti ( ctx , t , version )
if err != nil {
return "" , nil , err
}
if len ( heads ) > 1 {
log . Warnf ( "More than 1 header received when expecting only one" )
}
return heads [ 0 ] . addr , heads [ 0 ] . header , nil
2021-03-05 20:08:14 +00:00
}
2021-07-29 11:37:29 +00:00
func GetCommonAPI ( ctx * cli . Context ) ( api . CommonNet , jsonrpc . ClientCloser , error ) {
2021-03-05 20:08:14 +00:00
ti , ok := ctx . App . Metadata [ "repoType" ]
if ! ok {
2021-07-29 11:37:29 +00:00
log . Errorf ( "unknown repo type, are you sure you want to use GetCommonAPI?" )
2022-02-16 11:26:41 +00:00
ti = repo . FullNode
2021-03-05 20:08:14 +00:00
}
t , ok := ti . ( repo . RepoType )
if ! ok {
log . Errorf ( "repoType type does not match the type of repo.RepoType" )
}
if tn , ok := ctx . App . Metadata [ "testnode-storage" ] ; ok {
return tn . ( api . StorageMiner ) , func ( ) { } , nil
}
if tn , ok := ctx . App . Metadata [ "testnode-full" ] ; ok {
return tn . ( api . FullNode ) , func ( ) { } , nil
}
2021-03-23 18:15:44 +00:00
addr , headers , err := GetRawAPI ( ctx , t , "v0" )
2021-03-05 20:08:14 +00:00
if err != nil {
return nil , nil , err
}
2021-03-25 14:39:48 +00:00
return client . NewCommonRPCV0 ( ctx . Context , addr , headers )
2021-03-05 20:08:14 +00:00
}
2021-04-01 12:17:22 +00:00
func GetFullNodeAPI ( ctx * cli . Context ) ( v0api . FullNode , jsonrpc . ClientCloser , error ) {
2022-02-09 19:46:51 +00:00
// use the mocked API in CLI unit tests, see cli/mocks_test.go for mock definition
2022-02-08 16:15:45 +00:00
if mock , ok := ctx . App . Metadata [ "test-full-api" ] ; ok {
return & v0api . WrapperV1Full { FullNode : mock . ( v1api . FullNode ) } , func ( ) { } , nil
}
2021-03-05 20:08:14 +00:00
if tn , ok := ctx . App . Metadata [ "testnode-full" ] ; ok {
2021-04-05 19:34:03 +00:00
return & v0api . WrapperV1Full { FullNode : tn . ( v1api . FullNode ) } , func ( ) { } , nil
2021-03-05 20:08:14 +00:00
}
2022-02-16 11:26:41 +00:00
addr , headers , err := GetRawAPI ( ctx , repo . FullNode , "v0" )
2021-03-05 20:08:14 +00:00
if err != nil {
return nil , nil , err
}
2021-07-27 19:46:02 +00:00
if IsVeryVerbose {
2021-07-27 13:25:28 +00:00
_ , _ = fmt . Fprintln ( ctx . App . Writer , "using full node API v0 endpoint:" , addr )
}
2021-08-12 17:09:43 +00:00
return client . NewFullNodeRPCV0 ( ctx . Context , addr , headers )
2021-03-05 20:08:14 +00:00
}
2022-10-18 19:53:42 +00:00
type contextKey string
2022-10-04 16:49:09 +00:00
// Not thread safe
func OnSingleNode ( ctx context . Context ) context . Context {
2022-10-18 19:53:42 +00:00
return context . WithValue ( ctx , contextKey ( "retry-node" ) , new ( * int ) )
2022-10-04 16:49:09 +00:00
}
2022-09-27 16:08:04 +00:00
func FullNodeProxy [ T api . FullNode ] ( ins [ ] T , outstr * api . FullNodeStruct ) {
outs := api . GetInternalStructs ( outstr )
var rins [ ] reflect . Value
for _ , in := range ins {
2022-10-17 02:52:22 +00:00
rins = append ( rins , reflect . ValueOf ( in ) )
2022-09-27 16:08:04 +00:00
}
for _ , out := range outs {
2022-10-17 20:13:30 +00:00
rProxyInternal := reflect . ValueOf ( out ) . Elem ( )
2022-09-27 16:08:04 +00:00
2022-10-17 20:13:30 +00:00
for f := 0 ; f < rProxyInternal . NumField ( ) ; f ++ {
field := rProxyInternal . Type ( ) . Field ( f )
2022-09-27 16:08:04 +00:00
var fns [ ] reflect . Value
for _ , rin := range rins {
fns = append ( fns , rin . MethodByName ( field . Name ) )
}
2022-10-17 20:13:30 +00:00
rProxyInternal . Field ( f ) . Set ( reflect . MakeFunc ( field . Type , func ( args [ ] reflect . Value ) ( results [ ] reflect . Value ) {
2022-09-28 15:07:05 +00:00
errorsToRetry := [ ] error { & jsonrpc . RPCConnectionError { } , & jsonrpc . ErrClient { } }
initialBackoff , err := time . ParseDuration ( "1s" )
if err != nil {
return nil
}
2022-10-05 15:32:24 +00:00
2022-09-28 15:07:05 +00:00
ctx := args [ 0 ] . Interface ( ) . ( context . Context )
2022-10-05 15:32:24 +00:00
curr := - 1
// for calls that need to be performed on the same node
// primarily for miner when calling create block and submit block subsequently
2022-10-18 19:53:42 +00:00
key := contextKey ( "retry-node" )
if ctx . Value ( key ) != nil {
if ( * ctx . Value ( key ) . ( * * int ) ) == nil {
* ctx . Value ( key ) . ( * * int ) = & curr
2022-10-05 15:32:24 +00:00
} else {
2022-10-18 19:53:42 +00:00
curr = * * ctx . Value ( key ) . ( * * int ) - 1
2022-10-05 15:32:24 +00:00
}
}
total := len ( rins )
2022-11-25 21:44:43 +00:00
result , _ := retry . Retry ( ctx , 5 , initialBackoff , errorsToRetry , func ( ) ( [ ] reflect . Value , error ) {
2022-10-05 15:32:24 +00:00
curr = ( curr + 1 ) % total
2022-09-28 15:07:05 +00:00
2022-10-05 15:32:24 +00:00
result := fns [ curr ] . Call ( args )
2022-09-28 15:07:05 +00:00
if result [ len ( result ) - 1 ] . IsNil ( ) {
return result , nil
}
e := result [ len ( result ) - 1 ] . Interface ( ) . ( error )
return result , e
} )
return result
2022-09-27 16:08:04 +00:00
} ) )
}
}
}
2022-11-14 20:46:58 +00:00
func GetFullNodeAPIV1Single ( ctx * cli . Context ) ( v1api . FullNode , jsonrpc . ClientCloser , error ) {
2021-04-05 11:47:10 +00:00
if tn , ok := ctx . App . Metadata [ "testnode-full" ] ; ok {
return tn . ( v1api . FullNode ) , func ( ) { } , nil
}
2022-02-16 11:26:41 +00:00
addr , headers , err := GetRawAPI ( ctx , repo . FullNode , "v1" )
2021-04-05 11:47:10 +00:00
if err != nil {
return nil , nil , err
}
2021-07-27 19:46:02 +00:00
if IsVeryVerbose {
2021-07-27 13:25:28 +00:00
_ , _ = fmt . Fprintln ( ctx . App . Writer , "using full node API v1 endpoint:" , addr )
}
2021-08-11 20:40:14 +00:00
v1API , closer , err := client . NewFullNodeRPCV1 ( ctx . Context , addr , headers )
if err != nil {
return nil , nil , err
}
v , err := v1API . Version ( ctx . Context )
if err != nil {
return nil , nil , err
}
if ! v . APIVersion . EqMajorMinor ( api . FullAPIVersion1 ) {
return nil , nil , xerrors . Errorf ( "Remote API version didn't match (expected %s, remote %s)" , api . FullAPIVersion1 , v . APIVersion )
}
return v1API , closer , nil
2021-04-05 11:47:10 +00:00
}
2023-01-16 14:28:55 +00:00
type GetFullNodeOptions struct {
ethSubHandler api . EthSubscriber
}
type GetFullNodeOption func ( * GetFullNodeOptions )
func FullNodeWithEthSubscribtionHandler ( sh api . EthSubscriber ) GetFullNodeOption {
return func ( opts * GetFullNodeOptions ) {
opts . ethSubHandler = sh
}
}
func GetFullNodeAPIV1 ( ctx * cli . Context , opts ... GetFullNodeOption ) ( v1api . FullNode , jsonrpc . ClientCloser , error ) {
2022-09-27 16:08:04 +00:00
if tn , ok := ctx . App . Metadata [ "testnode-full" ] ; ok {
return tn . ( v1api . FullNode ) , func ( ) { } , nil
}
2023-01-16 14:28:55 +00:00
var options GetFullNodeOptions
for _ , opt := range opts {
opt ( & options )
}
var rpcOpts [ ] jsonrpc . Option
if options . ethSubHandler != nil {
rpcOpts = append ( rpcOpts , jsonrpc . WithClientHandler ( "Filecoin" , options . ethSubHandler ) , jsonrpc . WithClientHandlerAlias ( "eth_subscription" , "Filecoin.EthSubscription" ) )
}
2022-09-27 16:08:04 +00:00
heads , err := GetRawAPIMulti ( ctx , repo . FullNode , "v1" )
if err != nil {
return nil , nil , err
}
if IsVeryVerbose {
_ , _ = fmt . Fprintln ( ctx . App . Writer , "using full node API v1 endpoint:" , heads [ 0 ] . addr )
}
var fullNodes [ ] api . FullNode
var closers [ ] jsonrpc . ClientCloser
for _ , head := range heads {
2023-01-26 14:20:49 +00:00
v1api , closer , err := client . NewFullNodeRPCV1 ( ctx . Context , head . addr , head . header , rpcOpts ... )
2022-09-27 16:08:04 +00:00
if err != nil {
2022-10-17 02:52:22 +00:00
log . Warnf ( "Not able to establish connection to node with addr: " , head . addr )
continue
2022-09-27 16:08:04 +00:00
}
fullNodes = append ( fullNodes , v1api )
closers = append ( closers , closer )
}
2022-10-17 02:52:22 +00:00
// When running in cluster mode and trying to establish connections to multiple nodes, fail
2023-10-16 15:28:58 +00:00
// if less than 2 lotus nodes are actually running
if len ( heads ) > 1 && len ( fullNodes ) < 2 {
return nil , nil , xerrors . Errorf ( "Not able to establish connection to more than a single node" )
}
finalCloser := func ( ) {
for _ , c := range closers {
c ( )
}
}
var v1API api . FullNodeStruct
FullNodeProxy ( fullNodes , & v1API )
v , err := v1API . Version ( ctx . Context )
if err != nil {
return nil , nil , err
}
if ! v . APIVersion . EqMajorMinor ( api . FullAPIVersion1 ) {
return nil , nil , xerrors . Errorf ( "Remote API version didn't match (expected %s, remote %s)" , api . FullAPIVersion1 , v . APIVersion )
}
return & v1API , finalCloser , nil
}
func GetFullNodeAPIV1LotusProvider ( ctx * cli . Context , ainfoCfg [ ] string , opts ... GetFullNodeOption ) ( v1api . FullNode , jsonrpc . ClientCloser , error ) {
if tn , ok := ctx . App . Metadata [ "testnode-full" ] ; ok {
return tn . ( v1api . FullNode ) , func ( ) { } , nil
}
var options GetFullNodeOptions
for _ , opt := range opts {
opt ( & options )
}
var rpcOpts [ ] jsonrpc . Option
if options . ethSubHandler != nil {
rpcOpts = append ( rpcOpts , jsonrpc . WithClientHandler ( "Filecoin" , options . ethSubHandler ) , jsonrpc . WithClientHandlerAlias ( "eth_subscription" , "Filecoin.EthSubscription" ) )
}
heads , err := GetRawAPIMultiV2 ( ctx , ainfoCfg , "v1" )
if err != nil {
return nil , nil , err
}
if IsVeryVerbose {
_ , _ = fmt . Fprintln ( ctx . App . Writer , "using full node API v1 endpoint:" , heads [ 0 ] . addr )
}
var fullNodes [ ] api . FullNode
var closers [ ] jsonrpc . ClientCloser
for _ , head := range heads {
v1api , closer , err := client . NewFullNodeRPCV1 ( ctx . Context , head . addr , head . header , rpcOpts ... )
if err != nil {
2023-10-18 21:47:00 +00:00
log . Warnf ( "Not able to establish connection to node with addr: %s" , head . addr )
2023-10-16 15:28:58 +00:00
continue
}
fullNodes = append ( fullNodes , v1api )
closers = append ( closers , closer )
}
// When running in cluster mode and trying to establish connections to multiple nodes, fail
2022-10-17 02:52:22 +00:00
// if less than 2 lotus nodes are actually running
if len ( heads ) > 1 && len ( fullNodes ) < 2 {
return nil , nil , xerrors . Errorf ( "Not able to establish connection to more than a single node" )
}
2022-09-27 16:08:04 +00:00
finalCloser := func ( ) {
for _ , c := range closers {
c ( )
}
}
var v1API api . FullNodeStruct
FullNodeProxy ( fullNodes , & v1API )
v , err := v1API . Version ( ctx . Context )
if err != nil {
return nil , nil , err
}
if ! v . APIVersion . EqMajorMinor ( api . FullAPIVersion1 ) {
return nil , nil , xerrors . Errorf ( "Remote API version didn't match (expected %s, remote %s)" , api . FullAPIVersion1 , v . APIVersion )
}
return & v1API , finalCloser , nil
}
2021-03-05 20:08:14 +00:00
type GetStorageMinerOptions struct {
PreferHttp bool
}
type GetStorageMinerOption func ( * GetStorageMinerOptions )
func StorageMinerUseHttp ( opts * GetStorageMinerOptions ) {
opts . PreferHttp = true
}
func GetStorageMinerAPI ( ctx * cli . Context , opts ... GetStorageMinerOption ) ( api . StorageMiner , jsonrpc . ClientCloser , error ) {
var options GetStorageMinerOptions
for _ , opt := range opts {
opt ( & options )
}
if tn , ok := ctx . App . Metadata [ "testnode-storage" ] ; ok {
return tn . ( api . StorageMiner ) , func ( ) { } , nil
}
2022-02-16 11:26:41 +00:00
addr , headers , err := GetRawAPI ( ctx , repo . StorageMiner , "v0" )
2021-03-05 20:08:14 +00:00
if err != nil {
return nil , nil , err
}
if options . PreferHttp {
u , err := url . Parse ( addr )
if err != nil {
return nil , nil , xerrors . Errorf ( "parsing miner api URL: %w" , err )
}
switch u . Scheme {
case "ws" :
u . Scheme = "http"
case "wss" :
u . Scheme = "https"
}
addr = u . String ( )
}
2021-07-27 19:46:02 +00:00
if IsVeryVerbose {
2021-07-27 13:25:28 +00:00
_ , _ = fmt . Fprintln ( ctx . App . Writer , "using miner API v0 endpoint:" , addr )
}
2021-03-25 14:39:48 +00:00
return client . NewStorageMinerRPCV0 ( ctx . Context , addr , headers )
2021-03-05 20:08:14 +00:00
}
2021-03-23 12:42:56 +00:00
func GetWorkerAPI ( ctx * cli . Context ) ( api . Worker , jsonrpc . ClientCloser , error ) {
2022-02-16 11:26:41 +00:00
addr , headers , err := GetRawAPI ( ctx , repo . Worker , "v0" )
2021-03-05 20:08:14 +00:00
if err != nil {
return nil , nil , err
}
2021-07-27 19:46:02 +00:00
if IsVeryVerbose {
2021-07-27 13:25:28 +00:00
_ , _ = fmt . Fprintln ( ctx . App . Writer , "using worker API v0 endpoint:" , addr )
}
2021-03-25 14:39:48 +00:00
return client . NewWorkerRPCV0 ( ctx . Context , addr , headers )
2021-03-05 20:08:14 +00:00
}
2021-07-29 11:37:29 +00:00
func GetMarketsAPI ( ctx * cli . Context ) ( api . StorageMiner , jsonrpc . ClientCloser , error ) {
2021-07-29 12:21:55 +00:00
// to support lotus-miner cli tests.
if tn , ok := ctx . App . Metadata [ "testnode-storage" ] ; ok {
return tn . ( api . StorageMiner ) , func ( ) { } , nil
}
2022-02-16 11:26:41 +00:00
addr , headers , err := GetRawAPI ( ctx , repo . Markets , "v0" )
2021-07-29 11:37:29 +00:00
if err != nil {
return nil , nil , err
}
if IsVeryVerbose {
_ , _ = fmt . Fprintln ( ctx . App . Writer , "using markets API v0 endpoint:" , addr )
}
// the markets node is a specialised miner's node, supporting only the
// markets API, which is a subset of the miner API. All non-markets
// operations will error out with "unsupported".
return client . NewStorageMinerRPCV0 ( ctx . Context , addr , headers )
}
2021-03-23 12:42:56 +00:00
func GetGatewayAPI ( ctx * cli . Context ) ( api . Gateway , jsonrpc . ClientCloser , error ) {
2022-02-16 11:26:41 +00:00
addr , headers , err := GetRawAPI ( ctx , repo . FullNode , "v1" )
2021-03-05 20:08:14 +00:00
if err != nil {
return nil , nil , err
}
2021-07-27 19:46:02 +00:00
if IsVeryVerbose {
2021-07-27 13:25:28 +00:00
_ , _ = fmt . Fprintln ( ctx . App . Writer , "using gateway API v1 endpoint:" , addr )
}
2021-04-05 19:34:03 +00:00
return client . NewGatewayRPCV1 ( ctx . Context , addr , headers )
2021-03-05 20:08:14 +00:00
}
2021-04-20 16:42:12 +00:00
func GetGatewayAPIV0 ( ctx * cli . Context ) ( v0api . Gateway , jsonrpc . ClientCloser , error ) {
2022-02-16 11:26:41 +00:00
addr , headers , err := GetRawAPI ( ctx , repo . FullNode , "v0" )
2021-04-20 16:42:12 +00:00
if err != nil {
return nil , nil , err
}
2021-07-27 19:46:02 +00:00
if IsVeryVerbose {
2021-07-27 13:25:28 +00:00
_ , _ = fmt . Fprintln ( ctx . App . Writer , "using gateway API v0 endpoint:" , addr )
}
2021-04-20 16:42:12 +00:00
return client . NewGatewayRPCV0 ( ctx . Context , addr , headers )
}
2021-03-05 20:08:14 +00:00
func DaemonContext ( cctx * cli . Context ) context . Context {
if mtCtx , ok := cctx . App . Metadata [ metadataTraceContext ] ; ok {
return mtCtx . ( context . Context )
}
return context . Background ( )
}
// ReqContext returns context for cli execution. Calling it for the first time
// installs SIGTERM handler that will close returned context.
// Not safe for concurrent execution.
func ReqContext ( cctx * cli . Context ) context . Context {
tCtx := DaemonContext ( cctx )
ctx , done := context . WithCancel ( tCtx )
sigChan := make ( chan os . Signal , 2 )
go func ( ) {
<- sigChan
done ( )
} ( )
signal . Notify ( sigChan , syscall . SIGTERM , syscall . SIGINT , syscall . SIGHUP )
return ctx
}