func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command, cmd *cmds.Command) (cmds.Response, error) { log.Info(config.EnvDir, " ", req.InvocContext().ConfigRoot) var res cmds.Response err := req.SetRootContext(ctx) if err != nil { return nil, err } details, err := commandDetails(req.Path(), root) if err != nil { return nil, err } client, err := commandShouldRunOnDaemon(*details, req, root) if err != nil { return nil, err } err = callPreCommandHooks(ctx, *details, req, root) if err != nil { return nil, err } if cmd.PreRun != nil { err = cmd.PreRun(req) if err != nil { return nil, err } } if client != nil && !cmd.External { log.Debug("Executing command via API") res, err = client.Send(req) if err != nil { if isConnRefused(err) { err = repo.ErrApiNotRunning } return nil, err } } else { log.Debug("Executing command locally") err := req.SetRootContext(ctx) if err != nil { return nil, err } // Okay!!!!! NOW we can call the command. res = root.Call(req) } if cmd.PostRun != nil { cmd.PostRun(req, res) } return res, nil }
func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command, cmd *cmds.Command) (cmds.Response, error) { log.Info(config.EnvDir, " ", req.InvocContext().ConfigRoot) var res cmds.Response err := req.SetRootContext(ctx) if err != nil { return nil, err } details, err := commandDetails(req.Path(), root) if err != nil { return nil, err } log.Debug("looking for running daemon...") useDaemon, err := commandShouldRunOnDaemon(*details, req, root) if err != nil { return nil, err } err = callPreCommandHooks(ctx, *details, req, root) if err != nil { return nil, err } if cmd.PreRun != nil { err = cmd.PreRun(req) if err != nil { return nil, err } } if useDaemon { cfg, err := req.InvocContext().GetConfig() if err != nil { return nil, err } addr, err := ma.NewMultiaddr(cfg.Addresses.API) if err != nil { return nil, err } log.Infof("Executing command on daemon running at %s", addr) _, host, err := manet.DialArgs(addr) if err != nil { return nil, err } client := cmdsHttp.NewClient(host) res, err = client.Send(req) if err != nil { return nil, err } } else { log.Debug("Executing command locally") err := req.SetRootContext(ctx) if err != nil { return nil, err } // Okay!!!!! NOW we can call the command. res = root.Call(req) } if cmd.PostRun != nil { cmd.PostRun(req, res) } return res, nil }
func (c *client) Send(req cmds.Request) (cmds.Response, error) { if req.Context() == nil { log.Warningf("no context set in request") if err := req.SetRootContext(context.TODO()); err != nil { return nil, err } } // save user-provided encoding previousUserProvidedEncoding, found, err := req.Option(cmds.EncShort).String() if err != nil { return nil, err } // override with json to send to server req.SetOption(cmds.EncShort, cmds.JSON) // stream channel output req.SetOption(cmds.ChanOpt, "true") query, err := getQuery(req) if err != nil { return nil, err } var fileReader *MultiFileReader var reader io.Reader if req.Files() != nil { fileReader = NewMultiFileReader(req.Files(), true) reader = fileReader } path := strings.Join(req.Path(), "/") url := fmt.Sprintf(ApiUrlFormat, c.serverAddress, ApiPath, path, query) httpReq, err := http.NewRequest("POST", url, reader) if err != nil { return nil, err } // TODO extract string consts? if fileReader != nil { httpReq.Header.Set(contentTypeHeader, "multipart/form-data; boundary="+fileReader.Boundary()) } else { httpReq.Header.Set(contentTypeHeader, applicationOctetStream) } httpReq.Header.Set(uaHeader, config.ApiVersion) httpReq.Cancel = req.Context().Done() httpReq.Close = true httpRes, err := c.httpClient.Do(httpReq) if err != nil { return nil, err } // using the overridden JSON encoding in request res, err := getResponse(httpRes, req) if err != nil { return nil, err } if found && len(previousUserProvidedEncoding) > 0 { // reset to user provided encoding after sending request // NB: if user has provided an encoding but it is the empty string, // still leave it as JSON. req.SetOption(cmds.EncShort, previousUserProvidedEncoding) } return res, nil }
func (c *client) Send(req cmds.Request) (cmds.Response, error) { if req.Context() == nil { log.Warningf("no context set in request") if err := req.SetRootContext(context.TODO()); err != nil { return nil, err } } // save user-provided encoding previousUserProvidedEncoding, found, err := req.Option(cmds.EncShort).String() if err != nil { return nil, err } // override with json to send to server req.SetOption(cmds.EncShort, cmds.JSON) // stream channel output req.SetOption(cmds.ChanOpt, "true") query, err := getQuery(req) if err != nil { return nil, err } var fileReader *MultiFileReader var reader io.Reader if req.Files() != nil { fileReader = NewMultiFileReader(req.Files(), true) reader = fileReader } path := strings.Join(req.Path(), "/") url := fmt.Sprintf(ApiUrlFormat, c.serverAddress, ApiPath, path, query) httpReq, err := http.NewRequest("POST", url, reader) if err != nil { return nil, err } // TODO extract string consts? if fileReader != nil { httpReq.Header.Set(contentTypeHeader, "multipart/form-data; boundary="+fileReader.Boundary()) httpReq.Header.Set(contentDispHeader, "form-data: name=\"files\"") } else { httpReq.Header.Set(contentTypeHeader, applicationOctetStream) } httpReq.Header.Set(uaHeader, config.ApiVersion) ec := make(chan error, 1) rc := make(chan cmds.Response, 1) dc := req.Context().Done() go func() { httpRes, err := c.httpClient.Do(httpReq) if err != nil { ec <- err return } // using the overridden JSON encoding in request res, err := getResponse(httpRes, req) if err != nil { ec <- err return } rc <- res }() for { select { case <-dc: log.Debug("Context cancelled, cancelling HTTP request...") tr := http.DefaultTransport.(*http.Transport) tr.CancelRequest(httpReq) dc = nil // Wait for ec or rc case err := <-ec: return nil, err case res := <-rc: if found && len(previousUserProvidedEncoding) > 0 { // reset to user provided encoding after sending request // NB: if user has provided an encoding but it is the empty string, // still leave it as JSON. req.SetOption(cmds.EncShort, previousUserProvidedEncoding) } return res, nil } } }