Browse Source

Asana tasks.

master 0.1.0
ldf 3 years ago
parent
commit
bcb2d578c5
  1. 5
      cmd/conf/cfg.toml
  2. 32
      cmd/conf/log.yml
  3. 0
      cmd/log/asana.error
  4. 480
      cmd/log/asana.log
  5. 5
      go.mod
  6. 58
      go.sum
  7. 202
      module/attach/attachments.go
  8. 127
      module/story/stories.go
  9. 107
      module/task/task.go
  10. 16
      util/constant.go
  11. 184
      util/http.go

5
cmd/conf/cfg.toml

@ -0,0 +1,5 @@
[logger]
conf = "./conf/log.yml"
path = "./log/"
app_name = "asana"

32
cmd/conf/log.yml

@ -0,0 +1,32 @@
level: "info"
development: false
disableCaller: false
disableStacktrace: false
sampling:
encoding: "console"
# encoder
encoderConfig:
messageKey: "message"
levelKey: "level"
timeKey: "time"
nameKey: "logger"
callerKey: "caller"
stacktraceKey: "stacktrace"
lineEnding: ""
# levelEncoder: "capitalColor"
timeEncoder: "iso8601"
durationEncoder: "seconds"
callerEncoder: "short"
nameEncoder: ""
outputPaths:
# - "../logs/yuanex.log"
# - "./logs/yuanex.log"
- "stderr"
errorOutputPaths:
# - "../logs/yuanex.error"
# - "./logs/yuanex.error"
- "stderr"
initialFields:

0
cmd/log/asana.error

480
cmd/log/asana.log
File diff suppressed because it is too large
View File

5
go.mod

@ -0,0 +1,5 @@
module asana
go 1.15
require git.drinkme.beer/yinghe/log v0.1.3

58
go.sum

@ -0,0 +1,58 @@
git.drinkme.beer/yinghe/log v0.1.3 h1:QwHVLEqPo5nF/uucrmJJPSl9OXgjrx4JUzKieRfsOes=
git.drinkme.beer/yinghe/log v0.1.3/go.mod h1:4PAIGcEDUqVkKYSFQEN65+R6QWSsjvbfkIoEhGThGH8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

202
module/attach/attachments.go

@ -0,0 +1,202 @@
package attach
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/textproto"
"os"
"strings"
"git.drinkme.beer/yinghe/log"
"asana/util"
)
const (
URI = "/api/1.0/tasks/%s/attachments"
)
type Request struct {
Body io.Reader
TaskID string
Name string
Path string
PAToken string
TicketID string
}
type Data struct {
Response Response `json:"data"`
}
type Response struct {
ID string `json:"gid"`
ResourceType string `json:"resource_type"`
Name string `json:"name"`
// ResourceSubtype - asana, dropbox, gdrive, onedrive, box, and external
ResourceSubtype string `json:"resource_subtype"`
}
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
func escapeQuotes(s string) string {
return quoteEscaper.Replace(s)
}
// Create - upload attachments
func (r Request) Create() (resp *Response, err error) {
var (
tempPath string
data struct {
Response Response `json:"data"`
}
)
tempPath = "./static/" + r.Name
// TODO
err = download(r.Path, tempPath)
if nil != err {
return nil, err
}
attachments, _ := os.Open(tempPath)
defer func() {
err := attachments.Close()
if nil != err {
log.Errorf("failed to close temporary file: %s", err.Error())
}
err = os.Remove(tempPath)
if nil != err {
log.Errorf("failed to remove temporary file: %s", err.Error())
}
}()
// Step 1. Try to determine the contentType.
contentType, body, err := fDetectContentType(attachments)
if nil != err {
log.Errorf("failed to detect content type: %s", err.Error())
return
}
if nil == body {
log.Errorf("empty attachment")
return nil, errors.New("generating attachment failed")
}
// Step 2:
// Initiate and then make the upload.
prc, pwc := io.Pipe()
mpartW := multipart.NewWriter(pwc)
go func() {
defer func() {
_ = mpartW.Close()
_ = pwc.Close()
}()
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition",
fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
escapeQuotes("file"), escapeQuotes(r.Name)))
//h.Set("Content-Type", "application/octet-stream")
log.Infof("Content-Type: %s", contentType)
h.Set("Content-Type", contentType)
formFile, err := mpartW.CreatePart(h)
//formFile, err := mpartW.CreateFormFile("file", r.Name)
if err != nil {
return
}
_, _ = io.Copy(formFile, body)
//writeStringField(mpartW, "Content-Type", contentType)
//writeStringField(mpartW, "resource_subtype", "asana")
//writeStringField(mpartW, "name", "20210811065901")
}()
fullURL := fmt.Sprintf("%s/api/1.0/tasks/%s/attachments", util.AsanaHost, r.TaskID)
req, err := http.NewRequest("POST", fullURL, prc)
if err != nil {
log.Errorf("failed to build attachment request: %s", err.Error())
return nil, err
}
req.Header.Set("Content-Type", mpartW.FormDataContentType())
req.Header.Set("Authorization", r.PAToken)
buf, err := util.Request(req)
if nil != err {
return nil, err
}
err = json.Unmarshal(buf, &data)
if nil != err {
log.Errorf("[%s][%s]failed to upload attachments: %s", r.TicketID, r.TaskID, err.Error())
return nil, err
}
return &data.Response, err
}
func fDetectContentType(r io.Reader) (string, io.Reader, error) {
if r == nil {
return "", nil, errors.New("empty attachments")
}
seeker, seekable := r.(io.Seeker)
sniffBuf := make([]byte, 512)
n, err := io.ReadAtLeast(r, sniffBuf, 1)
if err != nil {
log.Errorf(err.Error())
return "", nil, err
}
contentType := http.DetectContentType(sniffBuf)
needsRepad := !seekable
if seekable {
if _, err = seeker.Seek(int64(-n), io.SeekCurrent); err != nil {
// Since we failed to rewind it, mark it as needing repad
needsRepad = true
}
}
if needsRepad {
r = io.MultiReader(bytes.NewReader(sniffBuf), r)
}
return contentType, r, nil
}
func writeStringField(w *multipart.Writer, key, value string) {
fw, err := w.CreateFormField(key)
if err == nil {
_, _ = io.WriteString(fw, value)
}
}
var (
errValidation = errors.New("invalid request")
)
func download(src, filename string) error {
if "" == src || "" == filename {
return errValidation
}
f, err := os.Create(filename)
if nil != err {
log.Errorf("failed to create attachments")
return errors.New("failed to create file")
}
defer f.Close()
//defer os.Remove(filename)
resp, err := http.Get(src)
if nil != err {
log.Infof("download report failed: %s", err.Error())
return err
}
defer resp.Body.Close()
_, err = io.Copy(f, resp.Body)
return err
}

127
module/story/stories.go

@ -0,0 +1,127 @@
package story
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"git.drinkme.beer/yinghe/log"
"asana/util"
)
const (
URI = "/api/1.0/tasks/%s/stories"
)
type Data struct {
Request Request `json:"data"`
}
type Request struct {
HtmlText string `json:"html_text,omitempty"`
Text string `json:"text"`
StickerName string `json:"sticker_name,omitempty"`
IsPinned bool `json:"is_pinned"`
taskID string
ticketID string
paToken string
}
func (r *Request) GetTaskID() string {
return r.taskID
}
func (r *Request) SetTaskID(id string) {
r.taskID = id
}
func (r *Request) GetTicketID() string {
return r.ticketID
}
func (r *Request) SetTicketID(id string) {
r.ticketID = id
}
func (r *Request) GetPAToken() string {
return r.paToken
}
func (r *Request) SetPAToken(token string) {
r.paToken = token
}
type Response struct {
ID string `json:"gid"`
ResourceType string `json:"resource_type"`
Type string `json:"type"`
Text string `json:"text"`
// IsPinned Conditional
// Whether the story should be pinned on the resource.
IsPinned bool `json:"is_pinned"`
StickerName string `json:"sticker_name,omitempty"`
}
func (r Request) validate() error {
if "" == r.taskID {
log.Errorf("task id is empty")
return errors.New("task id is empty")
}
return nil
}
// Create comments on task
func (r Request) Create() (resp *Response, err error) {
var (
reqData Data
respData struct {
Response Response `json:"data"`
}
)
if err = r.validate(); nil != err {
return
}
resp = new(Response)
headers := make(map[string]string)
headers["Authorization"] = r.paToken
headers["Content-Type"] = util.ContentType
reqData.Request = r
buf, err := json.Marshal(&reqData)
if nil != err {
log.Errorf("failed to generate comment request: %s", err.Error())
return
}
log.Infof("request: %s", string(buf))
client := util.NewHttpClient(util.AsanaHost, fmt.Sprintf(URI, r.taskID), util.HttpPostMethod, buf)
client.Headers = headers
err = client.Request()
if nil != err {
log.Errorf("failed to create new task comment: %s", err.Error())
return
}
log.Infof("response status: %d", client.HTTPStatus)
if http.StatusCreated != client.HTTPStatus {
log.Errorf("unexpected response")
err = errors.New("unexpected response")
return
}
err = json.Unmarshal(client.Body, &respData)
if nil != err {
log.Errorf("illegal comment result: %s", err.Error())
return
}
resp = &respData.Response
log.Infof("[%s]new comment ID:%s", r.taskID, resp.ID)
return
}

107
module/task/task.go

@ -0,0 +1,107 @@
package task
import (
"encoding/json"
"errors"
"net/http"
"git.drinkme.beer/yinghe/log"
"asana/util"
)
type Data struct {
Request Request `json:"data"`
}
type Request struct {
ResourceSubtype string `json:"resource_subtype"`
Assignee string `json:"assignee"`
Name string `json:"name"`
Completed bool `json:"completed"`
DueOn string `json:"due_on"`
Liked bool `json:"linked"`
// Notes refer to the content of each Ticket
Notes string `json:"notes"`
StartOn string `json:"start_on"`
CustomFields map[string]string `json:"custom_fields"`
Projects []string `json:"projects"`
Workspace string `json:"workspace"`
TicketID string `json:"-"`
TicketType string `json:"-"`
paToken string
}
func (r *Request) GetPAToken() string {
return r.paToken
}
func (r *Request) SetPAToken(token string) {
r.paToken = token
}
type Response struct {
ID string `json:"gid"`
Name string `json:"name"`
ResourceType string `json:"resource_type"`
AssigneeStatus string `json:"assignee_status"`
}
const (
URI = "/api/1.0/tasks"
ResourceSubtype = "default_task"
)
func (r Request) Create() (resp *Response, err error) {
var (
reqData Data
respData struct {
Response Response `json:"data"`
}
)
resp = new(Response)
headers := make(map[string]string)
headers["Authorization"] = r.paToken
headers["Content-Type"] = util.ContentType
if "" == r.ResourceSubtype {
r.ResourceSubtype = ResourceSubtype
}
reqData.Request = r
buf, err := json.Marshal(&reqData)
if nil != err {
log.Errorf("failed to generate task request: %s", err.Error())
return
}
log.Infof("request: %s", string(buf))
client := util.NewHttpClient(util.AsanaHost, URI, util.HttpPostMethod, buf)
client.Headers = headers
err = client.Request()
if nil != err {
log.Errorf("failed to create new Asana task: %s", err.Error())
return
}
log.Infof("response status: %d", client.HTTPStatus)
if http.StatusCreated != client.HTTPStatus {
log.Errorf("unexpected response")
err = errors.New("unexpected response")
return
}
err = json.Unmarshal(client.Body, &respData)
if nil != err {
log.Errorf("illegal task result: %s", err.Error())
return
}
resp = &respData.Response
log.Infof("[%s]new task ID:%s", r.TicketID, resp.ID)
return
}

16
util/constant.go

@ -0,0 +1,16 @@
package util
const (
AsanaHost = "https://app.asana.com"
ContentType = "application/json"
HttpGetMethod = "GET"
HttpPostMethod = "POST"
AsanaDateFormat = "2006-01-02"
)
var (
AsanaHeaders = make(map[string]string)
)

184
util/http.go

@ -0,0 +1,184 @@
package util
import (
"bufio"
"bytes"
"context"
"errors"
//"fmt"
"io/ioutil"
"net"
"net/http"
"time"
"git.drinkme.beer/yinghe/log"
)
// Network contains common configuration.
type Network struct {
Env string `toml:"env"`
Host []string `toml:"gateway"`
GatewayURL string
RequestTimeout time.Duration `toml:"request_timeout"`
ConnectTimeout time.Duration `toml:"connect_timeout"`
SocketTimeout time.Duration `toml:"socket_timeout"`
}
var network = Network{
RequestTimeout: 45 * time.Second,
ConnectTimeout: 45 * time.Second,
SocketTimeout: 55 * time.Second,
}
var client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, n, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(n, addr,
time.Second*network.RequestTimeout,
)
if err != nil {
return conn, err
}
conn.SetDeadline(time.Now().
Add(time.Second * network.ConnectTimeout))
return conn, err
},
ResponseHeaderTimeout: time.Second * network.SocketTimeout,
MaxConnsPerHost: 20,
IdleConnTimeout: 3 * time.Minute,
MaxIdleConns: 10,
//Proxy: func(_ *http.Request) (*url.URL, error) {
// return url.Parse("http://192.168.0.104:1087")
//},
},
}
func SetNetworkCfg(cfg Network) {
if 0 < cfg.RequestTimeout {
network.RequestTimeout = cfg.RequestTimeout
}
if 0 < cfg.ConnectTimeout {
network.ConnectTimeout = cfg.ConnectTimeout
}
if 0 < cfg.SocketTimeout {
network.SocketTimeout = cfg.SocketTimeout
}
}
type Body interface {
BuildRequest() []byte
}
type Client struct {
GatewayURL string
URI string
Headers map[string]string
Authorization string
Method string
HTTPStatus int
Body []byte // Indicates both Request Body & Response Body
TraceId interface{}
Buffer *bufio.Reader
}
func (c *Client) AddHeader(k, v string) {
c.Headers[k] = v
}
type Bytes []byte
func (self Bytes) BuildRequest() []byte {
return self
}
/*
url, uri, method, body
*/
func NewHttpClient(url, uri, m string, b []byte) *Client {
return &Client{
GatewayURL: url,
URI: uri,
Method: m,
Headers: make(map[string]string),
Body: b,
}
}
func (c *Client) BuildRequest(body Body) {
if nil == c.Body {
c.Body = make([]byte, 0, 1024)
}
c.Body = append(c.Body, body.BuildRequest()...)
}
func (c *Client) Request() (err error) {
log.Infof("request url: %s", c.GatewayURL+c.URI)
request, err := http.NewRequest(c.Method,
c.GatewayURL+c.URI,
bytes.NewReader(c.Body),
)
if err != nil {
log.Info("Post err occurs:", err.Error())
return
}
for k, v := range c.Headers {
request.Header.Set(k, v)
}
resp, err := client.Do(request)
if nil == resp {
log.Info("none response received")
err = errors.New("none response received")
return
}
defer resp.Body.Close()
c.HTTPStatus = resp.StatusCode
c.Body, err = ioutil.ReadAll(resp.Body)
log.Infof("response: %s", string(c.Body))
return
}
func Request(req *http.Request) ([]byte, error) {
var (
err error
body []byte
)
if nil == req {
log.Errorf("illegal request")
return nil, errors.New("illegal request")
}
log.Infof("%v", req)
resp, err := client.Do(req)
if nil == resp {
log.Info("none response received")
err = errors.New("none response received")
return nil, err
}
defer resp.Body.Close()
if http.StatusOK != resp.StatusCode {
if nil != resp.Body {
body, _ = ioutil.ReadAll(resp.Body)
log.Infof("response: %s", string(body))
}
log.Errorf("unexpected status: %d", resp.StatusCode)
return nil, errors.New("unexpected status")
}
body, err = ioutil.ReadAll(resp.Body)
if nil != err {
log.Errorf("invalid response body: %s", err.Error())
return nil, err
}
log.Infof("response: %s", string(body))
return body, nil
}
Loading…
Cancel
Save