Skip to content

Commit

Permalink
fix(golang): support to generate io.Reader and io.ReadCloser (caiclou…
Browse files Browse the repository at this point in the history
  • Loading branch information
kdada authored and caicloud-bot committed Jul 4, 2018
1 parent 2a6a55b commit 660c862
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 27 deletions.
64 changes: 41 additions & 23 deletions rest/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func (c *Client) parseURL(url string) (*path, error) {
segment = segment[1 : len(segment)-1]
index := strings.Index(segment, ":")
if index > 0 {
segment = segment[1:index]
segment = segment[:index]
}
if _, ok := p.names[segment]; ok {
return nil, duplicatedPathParameter.Error(segment, p.path)
Expand Down Expand Up @@ -348,7 +348,15 @@ func (r *Request) request(ctx context.Context) (*http.Request, error) {
return req, nil
}

func (r *Request) finish(ctx context.Context, req *http.Request, resp *http.Response) error {
func (r *Request) finish(ctx context.Context, req *http.Request, resp *http.Response) (err error) {
reader := &autocloser{resp.Body}
defer func() {
if err != nil {
e := reader.Close()
// Ignore error.
_ = e
}
}()
// Fill headers.
if r.meta != nil {
for k, v := range resp.Header {
Expand All @@ -371,38 +379,34 @@ func (r *Request) finish(ctx context.Context, req *http.Request, resp *http.Resp
return invalidContentType.Error(ct, r.path.String(), err.Error())
}
switch target := r.data.(type) {
case *io.Reader:
*target = reader
case *io.ReadCloser:
*target = resp.Body
*target = reader
case *[]byte:
data, err := ioutil.ReadAll(resp.Body)
if err == nil {
err = resp.Body.Close()
}
data, err := ioutil.ReadAll(reader)
if err != nil {
return unreadableBody.Error(r.path.String(), err.Error())
}
*target = data
case *string:
data, err := ioutil.ReadAll(resp.Body)
if err == nil {
err = resp.Body.Close()
}
data, err := ioutil.ReadAll(reader)
if err != nil {
return unreadableBody.Error(r.path.String(), err.Error())
}
*target = string(data)
}
switch contentType {
case definition.MIMEJSON:
if err := json.NewDecoder(resp.Body).Decode(r.data); err != nil {
return unreadableBody.Error(r.path.String(), err.Error())
}
case definition.MIMEXML:
if err := xml.NewDecoder(resp.Body).Decode(r.data); err != nil {
return unreadableBody.Error(r.path.String(), err.Error())
}
default:
return unrecognizedBody.Error(r.path.String(), err.Error())
switch contentType {
case definition.MIMEJSON:
if err := json.NewDecoder(reader).Decode(r.data); err != nil {
return unreadableBody.Error(r.path.String(), err.Error())
}
case definition.MIMEXML:
if err := xml.NewDecoder(reader).Decode(r.data); err != nil {
return unreadableBody.Error(r.path.String(), err.Error())
}
}
return unrecognizedBody.Error(r.path.String(), "no appropriate receiver")
}
}
} else {
Expand All @@ -411,7 +415,7 @@ func (r *Request) finish(ctx context.Context, req *http.Request, resp *http.Resp
return invalidContentType.Error(ct, r.path.String(), err.Error())
}
// Unmarshal body to error.
data, err := ioutil.ReadAll(resp.Body)
data, err := ioutil.ReadAll(reader)
if err != nil {
return unreadableBody.Error(r.path.String(), err.Error())
}
Expand All @@ -430,3 +434,17 @@ func (r *Request) finish(ctx context.Context, req *http.Request, resp *http.Resp
}
return nil
}

type autocloser struct {
io.ReadCloser
}

func (ac *autocloser) Read(p []byte) (n int, err error) {
count, err := ac.ReadCloser.Read(p)
if err == io.EOF {
if e := ac.ReadCloser.Close(); e != nil {
return count, e
}
}
return count, err
}
3 changes: 3 additions & 0 deletions utils/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ func (b *APIBuilder) Build() (*api.Definitions, error) {
}
}
}
if len(descriptors) <= 0 {
return nil, fmt.Errorf("can't find descriptors from %v", b.paths)
}
return b.runMain(descriptors, modifiers, b.root)
}

Expand Down
9 changes: 7 additions & 2 deletions utils/generators/golang/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ package {{ .Version }}
import (
"context"
{{- range .Functions }}
{{ range .Parameters }}{{ .Package }}{{ end }}
{{ range .Results }}{{ .Package }}{{ end }}
{{- end }}
rest "{{ .Rest }}"
)
Expand All @@ -131,7 +136,7 @@ func NewClient(cfg *rest.Config) (*Client, error) {
return &Client{client}, nil
}
// MustNewClient creates a new client or panic if an error occurs.
// MustNewClient creates a new client or panic if an error occurs.
func MustNewClient(cfg *rest.Config) *Client {
client, err := NewClient(cfg)
if err != nil {
Expand Down Expand Up @@ -231,7 +236,7 @@ func NewClient(cfg *rest.Config) (Interface, error) {
return c, nil
}
// MustNewClient creates a new client or panic if an error occurs.
// MustNewClient creates a new client or panic if an error occurs.
func MustNewClient(cfg *rest.Config) Interface {
return &Client{
{{- range .Pakcages }}
Expand Down
41 changes: 39 additions & 2 deletions utils/generators/golang/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package golang

import (
"fmt"
"path"
"reflect"
"regexp"
"sort"
Expand Down Expand Up @@ -149,13 +150,15 @@ type functionParameter struct {
Name string
ProposedName string
Typ string
Package string
Extensions []parameterExtension
}

type functionResult struct {
Destination string
ProposedName string
Typ string
Package string
Creator string
}

Expand Down Expand Up @@ -247,7 +250,7 @@ func (h *helper) Types() []Type {
return types
}

// Types returns functions which is required to generate.
// Functions returns functions which is required to generate.
func (h *helper) Functions() []function {
functionNames := map[string]int{}
functions := []function{}
Expand Down Expand Up @@ -314,6 +317,10 @@ func (h *helper) Functions() []function {
ProposedName: sigNames.proposeName(param.Name, param.Type),
Typ: h.namer.Name(param.Type),
}
alias, pkg := h.namer.Package(param.Type)
if pkg != "" {
p.Package = fmt.Sprintf(`%s "%s"`, alias, pkg)
}
if param.Source == definition.Body {
// Use first consumer as the name of body parameter.
p.Name = firstNonEmptyConsume
Expand Down Expand Up @@ -351,6 +358,10 @@ func (h *helper) Functions() []function {
ProposedName: sigNames.proposeName("", result.Type),
Typ: h.namer.Name(result.Type),
}
alias, pkg := h.namer.Package(result.Type)
if pkg != "" {
r.Package = fmt.Sprintf(`%s "%s"`, alias, pkg)
}
typ := h.definitions.Types[result.Type]
if typ.Kind == reflect.Ptr {
r.Creator = fmt.Sprintf("new(%s)", h.namer.Name(typ.Elem))
Expand Down Expand Up @@ -437,13 +448,17 @@ func (n *nameContainer) deconstruct(name api.TypeName) string {
type typeNamer struct {
types map[api.TypeName]*api.Type
names map[api.TypeName]string
aliases map[string]int
packages map[string]string
comments map[api.TypeName]string
}

func newTypeNamer(types map[api.TypeName]*api.Type) (*typeNamer, error) {
n := &typeNamer{
types: types,
names: make(map[api.TypeName]string),
aliases: make(map[string]int),
packages: make(map[string]string),
comments: make(map[api.TypeName]string),
}
for tn := range n.types {
Expand Down Expand Up @@ -517,7 +532,17 @@ func (n *typeNamer) parse(tn api.TypeName) (string, error) {
case reflect.Struct, reflect.Func:
name, comments = n.reconcileNameAndComments(typ.Name, typ.Comments)
case reflect.Interface:
name, comments = n.reconcileNameAndComments(typ.Name, typ.Comments)
alias := n.packages[typ.PkgPath]
if alias == "" {
alias = path.Base(typ.PkgPath)
index := n.aliases[alias]
n.aliases[alias]++
if index > 0 {
alias += strconv.Itoa(index)
}
}
n.packages[typ.PkgPath] = alias
name = fmt.Sprintf("%s.%s", alias, typ.Name)
default:
return "", fmt.Errorf("can't generate a name for type %s", tn)
}
Expand Down Expand Up @@ -549,6 +574,18 @@ func (n *typeNamer) Name(tn api.TypeName) string {
return name
}

func (n *typeNamer) Package(tn api.TypeName) (alias string, pkg string) {
typ, ok := n.types[tn]
if !ok {
panic(fmt.Errorf("can't find type %s", tn))
}
alias, ok = n.packages[typ.PkgPath]
if !ok {
return "", ""
}
return alias, typ.PkgPath
}

func (n *typeNamer) Comments(tn api.TypeName) string {
comments, ok := n.comments[tn]
if !ok {
Expand Down

0 comments on commit 660c862

Please sign in to comment.