5
5
"errors"
6
6
"fmt"
7
7
"io"
8
+ "io/ioutil"
8
9
"math/rand"
9
10
"os"
10
11
"os/signal"
@@ -23,6 +24,7 @@ import (
23
24
cmdsCli "github.com/ipfs/go-ipfs/commands/cli"
24
25
cmdsHttp "github.com/ipfs/go-ipfs/commands/http"
25
26
core "github.com/ipfs/go-ipfs/core"
27
+ coreCmds "github.com/ipfs/go-ipfs/core/commands"
26
28
config "github.com/ipfs/go-ipfs/repo/config"
27
29
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
28
30
eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog"
@@ -32,8 +34,12 @@ import (
32
34
// log is the command logger
33
35
var log = eventlog .Logger ("cmd/ipfs" )
34
36
35
- // signal to output help
36
- var errHelpRequested = errors .New ("Help Requested" )
37
+ var (
38
+ errHelpRequested = errors .New ("Help Requested" )
39
+ errApiNotRunning = errors .New ("api not running" )
40
+ errUnexpectedApiOutput = errors .New ("api returned unexpected output" )
41
+ errApiVersionMismatch = errors .New ("api version mismatch" )
42
+ )
37
43
38
44
const (
39
45
EnvEnableProfiling = "IPFS_PROF"
@@ -293,6 +299,9 @@ func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command, cmd
293
299
}
294
300
295
301
log .Debug ("looking for running daemon..." )
302
+
303
+ getApiClient (repoPath , apiAddrStr )
304
+
296
305
useDaemon , err := commandShouldRunOnDaemon (* details , req , root )
297
306
if err != nil {
298
307
return nil , err
@@ -571,3 +580,69 @@ func profileIfEnabled() (func(), error) {
571
580
}
572
581
return func () {}, nil
573
582
}
583
+
584
+ // getApiClient checks the repo, and the given options, checking for
585
+ // a running API service. if there is one, it returns a client.
586
+ // otherwise, it returns errApiNotRunning, or another error.
587
+ func getApiClient (repoPath , apiAddrStr string ) (* cmdsHttp.Client , error ) {
588
+ // parse given option
589
+ if apiAddrStr != "" {
590
+ addr , err = ma .NewMultiaddr (apiAddrStr )
591
+ } else { // get opt from file.
592
+ addr , err = fsrepo .APIAddr (repoPath )
593
+ }
594
+ if err != nil {
595
+ return nil , err
596
+ }
597
+
598
+ client , err := apiClientForAddr (addr )
599
+ if err != nil {
600
+ return nil , err
601
+ }
602
+
603
+ // make sure the api is actually running.
604
+ // this is slow, as it might mean an RTT to a remote server.
605
+ // TODO: optimize some way
606
+ if err := checkApiVersionMatch (client ); err != nil {
607
+ return nil , err
608
+ }
609
+
610
+ return client , nil
611
+ }
612
+
613
+ // apiVersionMatches checks whether the api server is running the
614
+ // same version of go-ipfs. for now, only the exact same version of
615
+ // client + server work. In the future, we should use semver for
616
+ // proper API versioning! \o/
617
+ func apiVersionMatches (client * cmdsHttp.Client ) (err error ) {
618
+ cmd := coreCmds .VersionCmd
619
+ req , err := cmds .NewRequest ([]string {"version" }, nil , nil , nil , cmd , nil )
620
+ if err != nil {
621
+ return err
622
+ }
623
+
624
+ res , err := client .Send (req )
625
+ if err != nil {
626
+ return err
627
+ }
628
+
629
+ ver , ok := res .Output ().(* coreCmds.VersionOutput )
630
+ if ! ok {
631
+ return errApiOutputErr
632
+ }
633
+
634
+ currv := config .CurrentVersionNumber
635
+ if ver .Version != currv {
636
+ return fmt .Errorf ("%s (%s != %s)" , errApiVersionMismatch , ver .Version , currv )
637
+ }
638
+ return nil
639
+ }
640
+
641
+ func apiClientForAddr (addr ma.Multiaddr ) (* cmdsHttp.Client , error ) {
642
+ _ , host , err := manet .DialArgs (addr )
643
+ if err != nil {
644
+ return false , err
645
+ }
646
+
647
+ return cmdsHttp .NewClient (host ), nil
648
+ }
0 commit comments