Unverified Commit f6f6a656 authored by Steven Allen's avatar Steven Allen Committed by GitHub

Merge pull request #171 from ipfs/feat/fallback

fallback executor support
parents 1adb804f ca0ae174
...@@ -19,32 +19,20 @@ func main() { ...@@ -19,32 +19,20 @@ func main() {
panic(err) panic(err)
} }
req.Options["encoding"] = cmds.Text
// create http rpc client // create http rpc client
client := http.NewClient(":6798") client := http.NewClient(":6798")
// send request to server
res, err := client.Send(req)
if err != nil {
panic(err)
}
req.Options["encoding"] = cmds.Text
// create an emitter // create an emitter
re, err := cli.NewResponseEmitter(os.Stdout, os.Stderr, req) re, err := cli.NewResponseEmitter(os.Stdout, os.Stderr, req)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// copy received result into cli emitter // send request to server
if pr, ok := req.Command.PostRun[cmds.CLI]; ok { err = client.Execute(req, re, nil)
err = pr(res, re)
} else {
err = cmds.Copy(re, res)
}
if err != nil { if err != nil {
re.CloseWithError(err) panic(err)
} }
os.Exit(re.Status())
} }
...@@ -22,16 +22,12 @@ var OptionSkipMap = map[string]bool{ ...@@ -22,16 +22,12 @@ var OptionSkipMap = map[string]bool{
"api": true, "api": true,
} }
// Client is the commands HTTP client interface.
type Client interface {
Send(req *cmds.Request) (cmds.Response, error)
}
type client struct { type client struct {
serverAddress string serverAddress string
httpClient *http.Client httpClient *http.Client
ua string ua string
apiPrefix string apiPrefix string
fallback cmds.Executor
} }
type ClientOpt func(*client) type ClientOpt func(*client)
...@@ -48,7 +44,16 @@ func ClientWithAPIPrefix(apiPrefix string) ClientOpt { ...@@ -48,7 +44,16 @@ func ClientWithAPIPrefix(apiPrefix string) ClientOpt {
} }
} }
func NewClient(address string, opts ...ClientOpt) Client { // ClientWithFallback adds a fallback executor to the client.
//
// Note: This may run the PreRun function twice.
func ClientWithFallback(exe cmds.Executor) ClientOpt {
return func(c *client) {
c.fallback = exe
}
}
func NewClient(address string, opts ...ClientOpt) cmds.Executor {
if !strings.HasPrefix(address, "http://") { if !strings.HasPrefix(address, "http://") {
address = "http://" + address address = "http://" + address
} }
...@@ -69,6 +74,11 @@ func NewClient(address string, opts ...ClientOpt) Client { ...@@ -69,6 +74,11 @@ func NewClient(address string, opts ...ClientOpt) Client {
func (c *client) Execute(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error { func (c *client) Execute(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error {
cmd := req.Command cmd := req.Command
err := cmd.CheckArguments(req)
if err != nil {
return err
}
if cmd.PreRun != nil { if cmd.PreRun != nil {
err := cmd.PreRun(req, env) err := cmd.PreRun(req, env)
if err != nil { if err != nil {
...@@ -76,9 +86,13 @@ func (c *client) Execute(req *cmds.Request, re cmds.ResponseEmitter, env cmds.En ...@@ -76,9 +86,13 @@ func (c *client) Execute(req *cmds.Request, re cmds.ResponseEmitter, env cmds.En
} }
} }
res, err := c.Send(req) res, err := c.send(req)
if err != nil { if err != nil {
if isConnRefused(err) { if isConnRefused(err) {
if c.fallback != nil {
// XXX: this runs the PreRun twice
return c.fallback.Execute(req, re, env)
}
err = fmt.Errorf("cannot connect to the api. Is the daemon running? To run as a standalone CLI command remove the api file in `$IPFS_PATH/api`") err = fmt.Errorf("cannot connect to the api. Is the daemon running? To run as a standalone CLI command remove the api file in `$IPFS_PATH/api`")
} }
return err return err
...@@ -146,7 +160,7 @@ func (c *client) toHTTPRequest(req *cmds.Request) (*http.Request, error) { ...@@ -146,7 +160,7 @@ func (c *client) toHTTPRequest(req *cmds.Request) (*http.Request, error) {
return httpReq, nil return httpReq, nil
} }
func (c *client) Send(req *cmds.Request) (cmds.Response, error) { func (c *client) send(req *cmds.Request) (cmds.Response, error) {
if req.Context == nil { if req.Context == nil {
log.Warningf("no context set in request") log.Warningf("no context set in request")
req.Context = context.Background() req.Context = context.Background()
......
...@@ -44,7 +44,7 @@ func TestClientUserAgent(t *testing.T) { ...@@ -44,7 +44,7 @@ func TestClientUserAgent(t *testing.T) {
c := NewClient(tc.host, ClientWithUserAgent(tc.ua)).(*client) c := NewClient(tc.host, ClientWithUserAgent(tc.ua)).(*client)
c.httpClient = testClient c.httpClient = testClient
c.Send(r) c.send(r)
if !called { if !called {
t.Error("handler has not been called") t.Error("handler has not been called")
...@@ -84,7 +84,7 @@ func TestClientAPIPrefix(t *testing.T) { ...@@ -84,7 +84,7 @@ func TestClientAPIPrefix(t *testing.T) {
c := NewClient(tc.host, ClientWithAPIPrefix(tc.prefix)).(*client) c := NewClient(tc.host, ClientWithAPIPrefix(tc.prefix)).(*client)
c.httpClient = testClient c.httpClient = testClient
c.Send(r) c.send(r)
if !called { if !called {
t.Error("handler has not been called") t.Error("handler has not been called")
......
...@@ -99,7 +99,7 @@ func TestHTTP(t *testing.T) { ...@@ -99,7 +99,7 @@ func TestHTTP(t *testing.T) {
req.Files = tc.file req.Files = tc.file
} }
res, err := c.Send(req) res, err := c.(*client).send(req)
if tc.sendErr != nil { if tc.sendErr != nil {
if err == nil { if err == nil {
t.Fatalf("expected error %q but got nil", tc.sendErr) t.Fatalf("expected error %q but got nil", tc.sendErr)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment