Skip to content

Commit

Permalink
Merge f482bb5 into 0f3b849
Browse files Browse the repository at this point in the history
  • Loading branch information
donutloop committed Mar 4, 2018
2 parents 0f3b849 + f482bb5 commit 8a15c4c
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 100 deletions.
59 changes: 59 additions & 0 deletions framework/transport/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/donutloop/xservice/framework/errors"
"github.com/donutloop/xservice/framework/hooks"
"github.com/donutloop/xservice/framework/xcontext"
"github.com/donutloop/xservice/framework/xhttp"
"github.com/gogo/protobuf/jsonpb"
"github.com/gogo/protobuf/proto"
"io"
Expand Down Expand Up @@ -403,3 +404,61 @@ func CallError(ctx context.Context, h *hooks.ServerHooks, err errors.Error) cont

// LogErrorFunc logs critical errors
type LogErrorFunc func(format string, args ...interface{})

func EncodeJSONResponse(ctx context.Context, resp http.ResponseWriter, content proto.Message) error {
buff := new(bytes.Buffer)
marshaler := &jsonpb.Marshaler{OrigName: true}
if err := marshaler.Marshal(buff, content); err != nil {
err = errors.WrapErr(err, "failed to marshal json response")
return errors.InternalErrorWith(err)
}
respBytes := buff.Bytes()
resp.Header().Set(xhttp.ContentTypeHeader, xhttp.ApplicationJson)
if _, err := resp.Write(respBytes); err != nil {
err = errors.WrapErr(err, "error while writing response to client, but already sent response status code to 200")
return errors.InternalErrorWith(err)
}
resp.WriteHeader(http.StatusOK)
ctx = xcontext.WithStatusCode(ctx, http.StatusOK)
return nil
}

func DecodeJSONResponse(ctx context.Context, req *http.Request, message proto.Message) error {
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
if err := unmarshaler.Unmarshal(req.Body, message); err != nil {
err = errors.WrapErr(err, "failed to parse request json")
terr := errors.InternalErrorWith(err)
return terr
}
return nil
}

func EncodePROTOResponse(ctx context.Context, resp http.ResponseWriter, content proto.Message) error {
respBytes, err := proto.Marshal(content)
if err != nil {
err = errors.WrapErr(err, "failed to marshal proto response")
return errors.InternalErrorWith(err)
}
resp.Header().Set(xhttp.ContentTypeHeader, xhttp.ApplicationProtobuf)
if _, err := resp.Write(respBytes); err != nil {
err = errors.WrapErr(err, "error while writing response to client, but already sent response status code to 200")
return errors.InternalErrorWith(err)
}
resp.WriteHeader(http.StatusOK)
ctx = xcontext.WithStatusCode(ctx, http.StatusOK)
return nil
}

func DecodePROTOResponse(ctx context.Context, req *http.Request, content proto.Message) error {
buff, err := ioutil.ReadAll(req.Body)
if err != nil {
err = errors.WrapErr(err, "failed to read request proto")
return errors.InternalErrorWith(err)
}
err = proto.Unmarshal(buff, content)
if err != nil {
err = errors.WrapErr(err, "failed to parse request proto")
return errors.InternalErrorWith(err)
}
return nil
}
62 changes: 11 additions & 51 deletions generator/proto/go/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -792,36 +792,18 @@ func (a *API) generateServerServeMethod(contentType string, service *descriptor.

if contentType == ServeJSON {
serveMethod.DefNew("reqContent", types.NewUnsafeTypeReference(inputType))
serveMethod.DefShortVar("unmarshaler", "jsonpb.Unmarshaler{AllowUnknownFields: true}")
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("unmarshaler.Unmarshal"), []string{"req.Body", "reqContent"})
serveMethod.DefIfBegin("err", token.NEQ, "nil")
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("errors.WrapErr"), []string{"err", `"failed to parse request json"`})
serveMethod.DefAssginCall([]string{"terr"}, types.NewUnsafeTypeReference("errors.InternalErrorWith"), []string{"err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.logErrorFunc"), []string{`"%v"`, "err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.writeError"), []string{"ctx", "resp", "terr"})
serveMethod.Return()
serveMethod.CloseIf()
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("transport.DecodeJSONResponse"), []string{"ctx", "req", "reqContent"})
} else if contentType == ServeProtobuffer {
serveMethod.DefAssginCall([]string{"buff", "err"}, types.NewUnsafeTypeReference("ioutil.ReadAll"), []string{"req.Body"})
serveMethod.DefIfBegin("err", token.NEQ, "nil")
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("errors.WrapErr"), []string{"err", `"failed to read request proto"`})
serveMethod.DefAssginCall([]string{"terr"}, types.NewUnsafeTypeReference("errors.InternalErrorWith"), []string{"err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.logErrorFunc"), []string{`"%v"`, "err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.writeError"), []string{"ctx", "resp", "terr"})
serveMethod.Return()
serveMethod.CloseIf()
serveMethod.DefNew("reqContent", types.NewUnsafeTypeReference(inputType))
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("proto.Unmarshal"), []string{"buff", "reqContent"})
serveMethod.DefIfBegin("err", token.NEQ, "nil")
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("errors.WrapErr"), []string{"err", `"failed to parse request proto"`})
serveMethod.DefAssginCall([]string{"terr"}, types.NewUnsafeTypeReference("errors.InternalErrorWith"), []string{"err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.logErrorFunc"), []string{`"%v"`, "err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.writeError"), []string{"ctx", "resp", "terr"})
serveMethod.Return()
serveMethod.CloseIf()
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("transport.DecodePROTOResponse"), []string{"ctx", "req", "reqContent"})
} else {
return nil, errors.New("content type isn't supported")
}
serveMethod.DefIfBegin("err", token.NEQ, "nil")
serveMethod.Caller(types.NewUnsafeTypeReference("s.logErrorFunc"), []string{`"%v"`, "err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.writeError"), []string{"ctx", "resp", "err"})
serveMethod.Return()
serveMethod.CloseIf()

serveMethod.DefNew("respContent", types.NewUnsafeTypeReference(outputType))
responseCallWrapper, _ := types.NewAnonymousGoFunc("responseCallWrapper", nil, nil)
Expand Down Expand Up @@ -853,36 +835,14 @@ func (a *API) generateServerServeMethod(contentType string, service *descriptor.

serveMethod.DefCall([]string{"ctx"}, types.NewUnsafeTypeReference("transport.CallResponsePrepared"), []string{"ctx", "s.hooks"})
if contentType == ServeJSON {
serveMethod.DefNew("buff", types.NewUnsafeTypeReference("bytes.Buffer"))
serveMethod.DefShortVar("marshaler", "&jsonpb.Marshaler{OrigName: true}")
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("marshaler.Marshal"), []string{"buff", "respContent"})
serveMethod.DefIfBegin("err", token.NEQ, "nil")
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("errors.WrapErr"), []string{"err", `"failed to marshal json response"`})
serveMethod.DefAssginCall([]string{"terr"}, types.NewUnsafeTypeReference("errors.InternalErrorWith"), []string{"err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.logErrorFunc"), []string{`"%v"`, "err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.writeError"), []string{"ctx", "resp", "terr"})
serveMethod.Return()
serveMethod.CloseIf()
serveMethod.DefAssginCall([]string{"respBytes"}, types.NewUnsafeTypeReference("buff.Bytes"), nil)
serveMethod.Caller(types.NewUnsafeTypeReference("req.Header.Set"), []string{"xhttp.ContentTypeHeader", "xhttp.ApplicationJson"})
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("transport.EncodeJSONResponse"), []string{"ctx", "resp", "respContent"})
} else if contentType == ServeProtobuffer {
serveMethod.DefAssginCall([]string{"respBytes", "err"}, types.NewUnsafeTypeReference("proto.Marshal"), []string{"respContent"})
serveMethod.DefIfBegin("err", token.NEQ, "nil")
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("errors.WrapErr"), []string{"err", `"failed to marshal json response"`})
serveMethod.DefAssginCall([]string{"terr"}, types.NewUnsafeTypeReference("errors.InternalErrorWith"), []string{"err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.logErrorFunc"), []string{`"%v"`, "err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.writeError"), []string{"ctx", "resp", "terr"})
serveMethod.Return()
serveMethod.CloseIf()
serveMethod.DefCall([]string{"err"}, types.NewUnsafeTypeReference("transport.EncodePROTOResponse"), []string{"ctx", "resp", "respContent"})
}

serveMethod.DefCall([]string{"ctx"}, types.NewUnsafeTypeReference("xcontext.WithStatusCode"), []string{"ctx", "http.StatusOK"})
serveMethod.Caller(types.NewUnsafeTypeReference("resp.WriteHeader"), []string{"http.StatusOK"})
serveMethod.DefCall([]string{"_", "err"}, types.NewUnsafeTypeReference("resp.Write"), []string{"respBytes"})

serveMethod.DefIfBegin("err", token.NEQ, "nil")
serveMethod.Caller(types.NewUnsafeTypeReference("s.logErrorFunc"), []string{`"error while writing response to client, but already sent response status code to 200: %s"`, "err"})
serveMethod.Caller(types.NewUnsafeTypeReference("resp.WriteHeader"), []string{"http.StatusInternalServerError"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.logErrorFunc"), []string{`"%v"`, "err"})
serveMethod.Caller(types.NewUnsafeTypeReference("s.writeError"), []string{"ctx", "resp", "err"})
serveMethod.Return()
serveMethod.CloseIf()

Expand Down
57 changes: 8 additions & 49 deletions integration_tests/api_hello_world/helloworld.proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@
package helloworld

import (
"bytes"
"context"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
Expand All @@ -23,8 +21,6 @@ import (
"github.com/donutloop/xservice/framework/transport"
"github.com/donutloop/xservice/framework/xcontext"
"github.com/donutloop/xservice/framework/xhttp"
jsonpb "github.com/golang/protobuf/jsonpb"
proto "github.com/golang/protobuf/proto"
)

// //[HelloWorldPathPrefix HelloWorld] is used for all URL paths on a %!s(MISSING) server.
Expand Down Expand Up @@ -141,13 +137,10 @@ func (s *helloWorldServer) serveHelloJSON(ctx context.Context, resp http.Respons
defer transport.Closebody(req.Body, s.logErrorFunc)

reqContent := new(HelloReq)
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
err = unmarshaler.Unmarshal(req.Body, reqContent)
err = transport.DecodeJSONResponse(ctx, req, reqContent)
if err != nil {
err = errors.WrapErr(err, "failed to parse request json")
terr := errors.InternalErrorWith(err)
s.logErrorFunc("%v", err)
s.writeError(ctx, resp, terr)
s.writeError(ctx, resp, err)
return
}
respContent := new(HelloResp)
Expand Down Expand Up @@ -176,24 +169,10 @@ func (s *helloWorldServer) serveHelloJSON(ctx context.Context, resp http.Respons
return
}
ctx = transport.CallResponsePrepared(ctx, s.hooks)
buff := new(bytes.Buffer)
marshaler := &jsonpb.Marshaler{OrigName: true}
err = marshaler.Marshal(buff, respContent)
err = transport.EncodeJSONResponse(ctx, resp, respContent)
if err != nil {
err = errors.WrapErr(err, "failed to marshal json response")
terr := errors.InternalErrorWith(err)
s.logErrorFunc("%v", err)
s.writeError(ctx, resp, terr)
return
}
respBytes := buff.Bytes()
req.Header.Set(xhttp.ContentTypeHeader, xhttp.ApplicationJson)
ctx = xcontext.WithStatusCode(ctx, http.StatusOK)
resp.WriteHeader(http.StatusOK)
_, err = resp.Write(respBytes)
if err != nil {
s.logErrorFunc("error while writing response to client, but already sent response status code to 200: %s", err)
resp.WriteHeader(http.StatusInternalServerError)
s.writeError(ctx, resp, err)
return
}
transport.CallResponseSent(ctx, s.hooks)
Expand All @@ -209,21 +188,11 @@ func (s *helloWorldServer) serveHelloProtobuffer(ctx context.Context, resp http.
}
defer transport.Closebody(req.Body, s.logErrorFunc)

buff, err := ioutil.ReadAll(req.Body)
if err != nil {
err = errors.WrapErr(err, "failed to read request proto")
terr := errors.InternalErrorWith(err)
s.logErrorFunc("%v", err)
s.writeError(ctx, resp, terr)
return
}
reqContent := new(HelloReq)
err = proto.Unmarshal(buff, reqContent)
err = transport.DecodePROTOResponse(ctx, req, reqContent)
if err != nil {
err = errors.WrapErr(err, "failed to parse request proto")
terr := errors.InternalErrorWith(err)
s.logErrorFunc("%v", err)
s.writeError(ctx, resp, terr)
s.writeError(ctx, resp, err)
return
}
respContent := new(HelloResp)
Expand Down Expand Up @@ -252,20 +221,10 @@ func (s *helloWorldServer) serveHelloProtobuffer(ctx context.Context, resp http.
return
}
ctx = transport.CallResponsePrepared(ctx, s.hooks)
respBytes, err := proto.Marshal(respContent)
err = transport.EncodePROTOResponse(ctx, resp, respContent)
if err != nil {
err = errors.WrapErr(err, "failed to marshal json response")
terr := errors.InternalErrorWith(err)
s.logErrorFunc("%v", err)
s.writeError(ctx, resp, terr)
return
}
ctx = xcontext.WithStatusCode(ctx, http.StatusOK)
resp.WriteHeader(http.StatusOK)
_, err = resp.Write(respBytes)
if err != nil {
s.logErrorFunc("error while writing response to client, but already sent response status code to 200: %s", err)
resp.WriteHeader(http.StatusInternalServerError)
s.writeError(ctx, resp, err)
return
}
transport.CallResponseSent(ctx, s.hooks)
Expand Down

0 comments on commit 8a15c4c

Please sign in to comment.