2018-01-21 15:22:13 +00:00
|
|
|
// Code generated by protoc-gen-twirp v5.0.0, DO NOT EDIT.
|
|
|
|
// source: route.proto
|
|
|
|
|
|
|
|
/*
|
2018-01-21 16:22:10 +00:00
|
|
|
Package proto is a generated twirp stub package.
|
2018-01-21 15:22:13 +00:00
|
|
|
This code was generated with github.com/twitchtv/twirp/protoc-gen-twirp v5.0.0.
|
|
|
|
|
|
|
|
It is generated from these files:
|
|
|
|
route.proto
|
|
|
|
*/
|
2018-01-21 16:22:10 +00:00
|
|
|
package proto
|
2018-01-21 15:22:13 +00:00
|
|
|
|
|
|
|
import bytes "bytes"
|
|
|
|
import context "context"
|
|
|
|
import fmt "fmt"
|
|
|
|
import ioutil "io/ioutil"
|
|
|
|
import log "log"
|
|
|
|
import http "net/http"
|
|
|
|
|
|
|
|
import jsonpb "github.com/golang/protobuf/jsonpb"
|
|
|
|
import proto "github.com/golang/protobuf/proto"
|
|
|
|
import twirp "github.com/twitchtv/twirp"
|
|
|
|
import ctxsetters "github.com/twitchtv/twirp/ctxsetters"
|
|
|
|
|
|
|
|
// Imports only used by utility functions:
|
|
|
|
import io "io"
|
|
|
|
import strconv "strconv"
|
|
|
|
import json "encoding/json"
|
|
|
|
import url "net/url"
|
|
|
|
|
|
|
|
// ================
|
|
|
|
// Routes Interface
|
|
|
|
// ================
|
|
|
|
|
|
|
|
// Routes lets users manage and manipulate http routes.
|
|
|
|
type Routes interface {
|
|
|
|
// Get fetches a single route based on the Host or ID.
|
|
|
|
Get(context.Context, *GetRouteRequest) (*Route, error)
|
|
|
|
|
|
|
|
// GetAll fetches all of the routes that the user owns.
|
|
|
|
GetAll(context.Context, *Nil) (*GetAllRoutesResponse, error)
|
|
|
|
|
|
|
|
// Put creates a new route based on user-supplied details.
|
|
|
|
Put(context.Context, *Route) (*Route, error)
|
|
|
|
|
|
|
|
// Delete removes a route.
|
|
|
|
Delete(context.Context, *Route) (*Nil, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ======================
|
|
|
|
// Routes Protobuf Client
|
|
|
|
// ======================
|
|
|
|
|
|
|
|
type routesProtobufClient struct {
|
|
|
|
urlBase string
|
|
|
|
client *http.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewRoutesProtobufClient creates a Protobuf client that implements the Routes interface.
|
|
|
|
// It communicates using protobuf messages and can be configured with a custom http.Client.
|
|
|
|
func NewRoutesProtobufClient(addr string, client *http.Client) Routes {
|
|
|
|
return &routesProtobufClient{
|
|
|
|
urlBase: urlBase(addr),
|
|
|
|
client: withoutRedirects(client),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *routesProtobufClient) Get(ctx context.Context, in *GetRouteRequest) (*Route, error) {
|
|
|
|
url := c.urlBase + RoutesPathPrefix + "Get"
|
|
|
|
out := new(Route)
|
|
|
|
err := doProtoRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *routesProtobufClient) GetAll(ctx context.Context, in *Nil) (*GetAllRoutesResponse, error) {
|
|
|
|
url := c.urlBase + RoutesPathPrefix + "GetAll"
|
|
|
|
out := new(GetAllRoutesResponse)
|
|
|
|
err := doProtoRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *routesProtobufClient) Put(ctx context.Context, in *Route) (*Route, error) {
|
|
|
|
url := c.urlBase + RoutesPathPrefix + "Put"
|
|
|
|
out := new(Route)
|
|
|
|
err := doProtoRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *routesProtobufClient) Delete(ctx context.Context, in *Route) (*Nil, error) {
|
|
|
|
url := c.urlBase + RoutesPathPrefix + "Delete"
|
|
|
|
out := new(Nil)
|
|
|
|
err := doProtoRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// ==================
|
|
|
|
// Routes JSON Client
|
|
|
|
// ==================
|
|
|
|
|
|
|
|
type routesJSONClient struct {
|
|
|
|
urlBase string
|
|
|
|
client *http.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewRoutesJSONClient creates a JSON client that implements the Routes interface.
|
|
|
|
// It communicates using JSON requests and responses instead of protobuf messages.
|
|
|
|
func NewRoutesJSONClient(addr string, client *http.Client) Routes {
|
|
|
|
return &routesJSONClient{
|
|
|
|
urlBase: urlBase(addr),
|
|
|
|
client: withoutRedirects(client),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *routesJSONClient) Get(ctx context.Context, in *GetRouteRequest) (*Route, error) {
|
|
|
|
url := c.urlBase + RoutesPathPrefix + "Get"
|
|
|
|
out := new(Route)
|
|
|
|
err := doJSONRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *routesJSONClient) GetAll(ctx context.Context, in *Nil) (*GetAllRoutesResponse, error) {
|
|
|
|
url := c.urlBase + RoutesPathPrefix + "GetAll"
|
|
|
|
out := new(GetAllRoutesResponse)
|
|
|
|
err := doJSONRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *routesJSONClient) Put(ctx context.Context, in *Route) (*Route, error) {
|
|
|
|
url := c.urlBase + RoutesPathPrefix + "Put"
|
|
|
|
out := new(Route)
|
|
|
|
err := doJSONRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *routesJSONClient) Delete(ctx context.Context, in *Route) (*Nil, error) {
|
|
|
|
url := c.urlBase + RoutesPathPrefix + "Delete"
|
|
|
|
out := new(Nil)
|
|
|
|
err := doJSONRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// =====================
|
|
|
|
// Routes Server Handler
|
|
|
|
// =====================
|
|
|
|
|
|
|
|
type routesServer struct {
|
|
|
|
Routes
|
|
|
|
hooks *twirp.ServerHooks
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewRoutesServer(svc Routes, hooks *twirp.ServerHooks) TwirpServer {
|
|
|
|
return &routesServer{
|
|
|
|
Routes: svc,
|
|
|
|
hooks: hooks,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeError writes an HTTP response with a valid Twirp error format, and triggers hooks.
|
|
|
|
// If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err)
|
|
|
|
func (s *routesServer) writeError(ctx context.Context, resp http.ResponseWriter, err error) {
|
|
|
|
writeError(ctx, resp, err, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
// RoutesPathPrefix is used for all URL paths on a twirp Routes server.
|
|
|
|
// Requests are always: POST RoutesPathPrefix/method
|
|
|
|
// It can be used in an HTTP mux to route twirp requests along with non-twirp requests on other routes.
|
2018-01-21 16:22:10 +00:00
|
|
|
const RoutesPathPrefix = "/twirp/xeserv.us.route.Routes/"
|
2018-01-21 15:22:13 +00:00
|
|
|
|
|
|
|
func (s *routesServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
|
|
|
|
ctx := req.Context()
|
2018-01-21 16:22:10 +00:00
|
|
|
ctx = ctxsetters.WithPackageName(ctx, "xeserv.us.route")
|
2018-01-21 15:22:13 +00:00
|
|
|
ctx = ctxsetters.WithServiceName(ctx, "Routes")
|
|
|
|
ctx = ctxsetters.WithResponseWriter(ctx, resp)
|
|
|
|
|
|
|
|
var err error
|
|
|
|
ctx, err = callRequestReceived(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.Method != "POST" {
|
|
|
|
msg := fmt.Sprintf("unsupported method %q (only POST is allowed)", req.Method)
|
|
|
|
err = badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch req.URL.Path {
|
2018-01-21 16:22:10 +00:00
|
|
|
case "/twirp/xeserv.us.route.Routes/Get":
|
2018-01-21 15:22:13 +00:00
|
|
|
s.serveGet(ctx, resp, req)
|
|
|
|
return
|
2018-01-21 16:22:10 +00:00
|
|
|
case "/twirp/xeserv.us.route.Routes/GetAll":
|
2018-01-21 15:22:13 +00:00
|
|
|
s.serveGetAll(ctx, resp, req)
|
|
|
|
return
|
2018-01-21 16:22:10 +00:00
|
|
|
case "/twirp/xeserv.us.route.Routes/Put":
|
2018-01-21 15:22:13 +00:00
|
|
|
s.servePut(ctx, resp, req)
|
|
|
|
return
|
2018-01-21 16:22:10 +00:00
|
|
|
case "/twirp/xeserv.us.route.Routes/Delete":
|
2018-01-21 15:22:13 +00:00
|
|
|
s.serveDelete(ctx, resp, req)
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("no handler for path %q", req.URL.Path)
|
|
|
|
err = badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) serveGet(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
switch req.Header.Get("Content-Type") {
|
|
|
|
case "application/json":
|
|
|
|
s.serveGetJSON(ctx, resp, req)
|
|
|
|
case "application/protobuf":
|
|
|
|
s.serveGetProtobuf(ctx, resp, req)
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
|
|
|
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, twerr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) serveGetJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Get")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
reqContent := new(GetRouteRequest)
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request json")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Route
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Get(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Route and nil error while calling Get. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal json response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(buf.Bytes()); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) serveGetProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Get")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
buf, err := ioutil.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to read request body")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqContent := new(GetRouteRequest)
|
|
|
|
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request proto")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Route
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Get(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Route and nil error while calling Get. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
respBytes, err := proto.Marshal(respContent)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal proto response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/protobuf")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(respBytes); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) serveGetAll(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
switch req.Header.Get("Content-Type") {
|
|
|
|
case "application/json":
|
|
|
|
s.serveGetAllJSON(ctx, resp, req)
|
|
|
|
case "application/protobuf":
|
|
|
|
s.serveGetAllProtobuf(ctx, resp, req)
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
|
|
|
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, twerr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) serveGetAllJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "GetAll")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
reqContent := new(Nil)
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request json")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *GetAllRoutesResponse
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.GetAll(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *GetAllRoutesResponse and nil error while calling GetAll. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal json response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(buf.Bytes()); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) serveGetAllProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "GetAll")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
buf, err := ioutil.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to read request body")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqContent := new(Nil)
|
|
|
|
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request proto")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *GetAllRoutesResponse
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.GetAll(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *GetAllRoutesResponse and nil error while calling GetAll. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
respBytes, err := proto.Marshal(respContent)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal proto response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/protobuf")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(respBytes); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) servePut(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
switch req.Header.Get("Content-Type") {
|
|
|
|
case "application/json":
|
|
|
|
s.servePutJSON(ctx, resp, req)
|
|
|
|
case "application/protobuf":
|
|
|
|
s.servePutProtobuf(ctx, resp, req)
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
|
|
|
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, twerr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) servePutJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Put")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
reqContent := new(Route)
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request json")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Route
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Put(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Route and nil error while calling Put. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal json response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(buf.Bytes()); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) servePutProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Put")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
buf, err := ioutil.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to read request body")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqContent := new(Route)
|
|
|
|
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request proto")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Route
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Put(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Route and nil error while calling Put. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
respBytes, err := proto.Marshal(respContent)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal proto response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/protobuf")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(respBytes); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) serveDelete(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
switch req.Header.Get("Content-Type") {
|
|
|
|
case "application/json":
|
|
|
|
s.serveDeleteJSON(ctx, resp, req)
|
|
|
|
case "application/protobuf":
|
|
|
|
s.serveDeleteProtobuf(ctx, resp, req)
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
|
|
|
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, twerr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) serveDeleteJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Delete")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
reqContent := new(Route)
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request json")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Nil
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Delete(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Nil and nil error while calling Delete. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal json response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(buf.Bytes()); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) serveDeleteProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Delete")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
buf, err := ioutil.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to read request body")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqContent := new(Route)
|
|
|
|
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request proto")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Nil
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Delete(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Nil and nil error while calling Delete. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
respBytes, err := proto.Marshal(respContent)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal proto response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/protobuf")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(respBytes); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) ServiceDescriptor() ([]byte, int) {
|
|
|
|
return twirpFileDescriptor0, 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *routesServer) ProtocGenTwirpVersion() string {
|
|
|
|
return "v5.0.0"
|
|
|
|
}
|
|
|
|
|
|
|
|
// ================
|
|
|
|
// Tokens Interface
|
|
|
|
// ================
|
|
|
|
|
|
|
|
// Tokens lets a user manage the database authentication tokens.
|
|
|
|
type Tokens interface {
|
|
|
|
Get(context.Context, *GetTokenRequest) (*Token, error)
|
|
|
|
|
|
|
|
GetAll(context.Context, *Nil) (*TokenSet, error)
|
|
|
|
|
|
|
|
Put(context.Context, *Token) (*Token, error)
|
|
|
|
|
|
|
|
Delete(context.Context, *Token) (*Nil, error)
|
|
|
|
|
|
|
|
Deactivate(context.Context, *Token) (*Nil, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ======================
|
|
|
|
// Tokens Protobuf Client
|
|
|
|
// ======================
|
|
|
|
|
|
|
|
type tokensProtobufClient struct {
|
|
|
|
urlBase string
|
|
|
|
client *http.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewTokensProtobufClient creates a Protobuf client that implements the Tokens interface.
|
|
|
|
// It communicates using protobuf messages and can be configured with a custom http.Client.
|
|
|
|
func NewTokensProtobufClient(addr string, client *http.Client) Tokens {
|
|
|
|
return &tokensProtobufClient{
|
|
|
|
urlBase: urlBase(addr),
|
|
|
|
client: withoutRedirects(client),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *tokensProtobufClient) Get(ctx context.Context, in *GetTokenRequest) (*Token, error) {
|
|
|
|
url := c.urlBase + TokensPathPrefix + "Get"
|
|
|
|
out := new(Token)
|
|
|
|
err := doProtoRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *tokensProtobufClient) GetAll(ctx context.Context, in *Nil) (*TokenSet, error) {
|
|
|
|
url := c.urlBase + TokensPathPrefix + "GetAll"
|
|
|
|
out := new(TokenSet)
|
|
|
|
err := doProtoRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *tokensProtobufClient) Put(ctx context.Context, in *Token) (*Token, error) {
|
|
|
|
url := c.urlBase + TokensPathPrefix + "Put"
|
|
|
|
out := new(Token)
|
|
|
|
err := doProtoRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *tokensProtobufClient) Delete(ctx context.Context, in *Token) (*Nil, error) {
|
|
|
|
url := c.urlBase + TokensPathPrefix + "Delete"
|
|
|
|
out := new(Nil)
|
|
|
|
err := doProtoRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *tokensProtobufClient) Deactivate(ctx context.Context, in *Token) (*Nil, error) {
|
|
|
|
url := c.urlBase + TokensPathPrefix + "Deactivate"
|
|
|
|
out := new(Nil)
|
|
|
|
err := doProtoRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// ==================
|
|
|
|
// Tokens JSON Client
|
|
|
|
// ==================
|
|
|
|
|
|
|
|
type tokensJSONClient struct {
|
|
|
|
urlBase string
|
|
|
|
client *http.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewTokensJSONClient creates a JSON client that implements the Tokens interface.
|
|
|
|
// It communicates using JSON requests and responses instead of protobuf messages.
|
|
|
|
func NewTokensJSONClient(addr string, client *http.Client) Tokens {
|
|
|
|
return &tokensJSONClient{
|
|
|
|
urlBase: urlBase(addr),
|
|
|
|
client: withoutRedirects(client),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *tokensJSONClient) Get(ctx context.Context, in *GetTokenRequest) (*Token, error) {
|
|
|
|
url := c.urlBase + TokensPathPrefix + "Get"
|
|
|
|
out := new(Token)
|
|
|
|
err := doJSONRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *tokensJSONClient) GetAll(ctx context.Context, in *Nil) (*TokenSet, error) {
|
|
|
|
url := c.urlBase + TokensPathPrefix + "GetAll"
|
|
|
|
out := new(TokenSet)
|
|
|
|
err := doJSONRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *tokensJSONClient) Put(ctx context.Context, in *Token) (*Token, error) {
|
|
|
|
url := c.urlBase + TokensPathPrefix + "Put"
|
|
|
|
out := new(Token)
|
|
|
|
err := doJSONRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *tokensJSONClient) Delete(ctx context.Context, in *Token) (*Nil, error) {
|
|
|
|
url := c.urlBase + TokensPathPrefix + "Delete"
|
|
|
|
out := new(Nil)
|
|
|
|
err := doJSONRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *tokensJSONClient) Deactivate(ctx context.Context, in *Token) (*Nil, error) {
|
|
|
|
url := c.urlBase + TokensPathPrefix + "Deactivate"
|
|
|
|
out := new(Nil)
|
|
|
|
err := doJSONRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// =====================
|
|
|
|
// Tokens Server Handler
|
|
|
|
// =====================
|
|
|
|
|
|
|
|
type tokensServer struct {
|
|
|
|
Tokens
|
|
|
|
hooks *twirp.ServerHooks
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewTokensServer(svc Tokens, hooks *twirp.ServerHooks) TwirpServer {
|
|
|
|
return &tokensServer{
|
|
|
|
Tokens: svc,
|
|
|
|
hooks: hooks,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeError writes an HTTP response with a valid Twirp error format, and triggers hooks.
|
|
|
|
// If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err)
|
|
|
|
func (s *tokensServer) writeError(ctx context.Context, resp http.ResponseWriter, err error) {
|
|
|
|
writeError(ctx, resp, err, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TokensPathPrefix is used for all URL paths on a twirp Tokens server.
|
|
|
|
// Requests are always: POST TokensPathPrefix/method
|
|
|
|
// It can be used in an HTTP mux to route twirp requests along with non-twirp requests on other routes.
|
2018-01-21 16:22:10 +00:00
|
|
|
const TokensPathPrefix = "/twirp/xeserv.us.route.Tokens/"
|
2018-01-21 15:22:13 +00:00
|
|
|
|
|
|
|
func (s *tokensServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
|
|
|
|
ctx := req.Context()
|
2018-01-21 16:22:10 +00:00
|
|
|
ctx = ctxsetters.WithPackageName(ctx, "xeserv.us.route")
|
2018-01-21 15:22:13 +00:00
|
|
|
ctx = ctxsetters.WithServiceName(ctx, "Tokens")
|
|
|
|
ctx = ctxsetters.WithResponseWriter(ctx, resp)
|
|
|
|
|
|
|
|
var err error
|
|
|
|
ctx, err = callRequestReceived(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.Method != "POST" {
|
|
|
|
msg := fmt.Sprintf("unsupported method %q (only POST is allowed)", req.Method)
|
|
|
|
err = badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch req.URL.Path {
|
2018-01-21 16:22:10 +00:00
|
|
|
case "/twirp/xeserv.us.route.Tokens/Get":
|
2018-01-21 15:22:13 +00:00
|
|
|
s.serveGet(ctx, resp, req)
|
|
|
|
return
|
2018-01-21 16:22:10 +00:00
|
|
|
case "/twirp/xeserv.us.route.Tokens/GetAll":
|
2018-01-21 15:22:13 +00:00
|
|
|
s.serveGetAll(ctx, resp, req)
|
|
|
|
return
|
2018-01-21 16:22:10 +00:00
|
|
|
case "/twirp/xeserv.us.route.Tokens/Put":
|
2018-01-21 15:22:13 +00:00
|
|
|
s.servePut(ctx, resp, req)
|
|
|
|
return
|
2018-01-21 16:22:10 +00:00
|
|
|
case "/twirp/xeserv.us.route.Tokens/Delete":
|
2018-01-21 15:22:13 +00:00
|
|
|
s.serveDelete(ctx, resp, req)
|
|
|
|
return
|
2018-01-21 16:22:10 +00:00
|
|
|
case "/twirp/xeserv.us.route.Tokens/Deactivate":
|
2018-01-21 15:22:13 +00:00
|
|
|
s.serveDeactivate(ctx, resp, req)
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("no handler for path %q", req.URL.Path)
|
|
|
|
err = badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveGet(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
switch req.Header.Get("Content-Type") {
|
|
|
|
case "application/json":
|
|
|
|
s.serveGetJSON(ctx, resp, req)
|
|
|
|
case "application/protobuf":
|
|
|
|
s.serveGetProtobuf(ctx, resp, req)
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
|
|
|
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, twerr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveGetJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Get")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
reqContent := new(GetTokenRequest)
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request json")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Token
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Get(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Token and nil error while calling Get. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal json response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(buf.Bytes()); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveGetProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Get")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
buf, err := ioutil.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to read request body")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqContent := new(GetTokenRequest)
|
|
|
|
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request proto")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Token
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Get(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Token and nil error while calling Get. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
respBytes, err := proto.Marshal(respContent)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal proto response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/protobuf")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(respBytes); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveGetAll(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
switch req.Header.Get("Content-Type") {
|
|
|
|
case "application/json":
|
|
|
|
s.serveGetAllJSON(ctx, resp, req)
|
|
|
|
case "application/protobuf":
|
|
|
|
s.serveGetAllProtobuf(ctx, resp, req)
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
|
|
|
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, twerr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveGetAllJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "GetAll")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
reqContent := new(Nil)
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request json")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *TokenSet
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.GetAll(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *TokenSet and nil error while calling GetAll. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal json response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(buf.Bytes()); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveGetAllProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "GetAll")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
buf, err := ioutil.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to read request body")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqContent := new(Nil)
|
|
|
|
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request proto")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *TokenSet
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.GetAll(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *TokenSet and nil error while calling GetAll. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
respBytes, err := proto.Marshal(respContent)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal proto response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/protobuf")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(respBytes); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) servePut(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
switch req.Header.Get("Content-Type") {
|
|
|
|
case "application/json":
|
|
|
|
s.servePutJSON(ctx, resp, req)
|
|
|
|
case "application/protobuf":
|
|
|
|
s.servePutProtobuf(ctx, resp, req)
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
|
|
|
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, twerr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) servePutJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Put")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
reqContent := new(Token)
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request json")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Token
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Put(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Token and nil error while calling Put. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal json response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(buf.Bytes()); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) servePutProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Put")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
buf, err := ioutil.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to read request body")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqContent := new(Token)
|
|
|
|
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request proto")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Token
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Put(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Token and nil error while calling Put. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
respBytes, err := proto.Marshal(respContent)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal proto response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/protobuf")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(respBytes); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveDelete(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
switch req.Header.Get("Content-Type") {
|
|
|
|
case "application/json":
|
|
|
|
s.serveDeleteJSON(ctx, resp, req)
|
|
|
|
case "application/protobuf":
|
|
|
|
s.serveDeleteProtobuf(ctx, resp, req)
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
|
|
|
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, twerr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveDeleteJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Delete")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
reqContent := new(Token)
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request json")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Nil
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Delete(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Nil and nil error while calling Delete. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal json response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(buf.Bytes()); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveDeleteProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Delete")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
buf, err := ioutil.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to read request body")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqContent := new(Token)
|
|
|
|
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request proto")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Nil
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Delete(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Nil and nil error while calling Delete. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
respBytes, err := proto.Marshal(respContent)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal proto response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/protobuf")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(respBytes); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveDeactivate(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
switch req.Header.Get("Content-Type") {
|
|
|
|
case "application/json":
|
|
|
|
s.serveDeactivateJSON(ctx, resp, req)
|
|
|
|
case "application/protobuf":
|
|
|
|
s.serveDeactivateProtobuf(ctx, resp, req)
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
|
|
|
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, twerr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveDeactivateJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Deactivate")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
reqContent := new(Token)
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request json")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Nil
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Deactivate(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Nil and nil error while calling Deactivate. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal json response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(buf.Bytes()); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) serveDeactivateProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Deactivate")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
buf, err := ioutil.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to read request body")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqContent := new(Token)
|
|
|
|
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request proto")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Nil
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Deactivate(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Nil and nil error while calling Deactivate. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
respBytes, err := proto.Marshal(respContent)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal proto response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/protobuf")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(respBytes); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) ServiceDescriptor() ([]byte, int) {
|
|
|
|
return twirpFileDescriptor0, 1
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *tokensServer) ProtocGenTwirpVersion() string {
|
|
|
|
return "v5.0.0"
|
|
|
|
}
|
|
|
|
|
|
|
|
// ==================
|
|
|
|
// Backends Interface
|
|
|
|
// ==================
|
|
|
|
|
|
|
|
type Backends interface {
|
|
|
|
List(context.Context, *BackendSelector) (*BackendList, error)
|
|
|
|
|
|
|
|
Kill(context.Context, *BackendID) (*Nil, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ========================
|
|
|
|
// Backends Protobuf Client
|
|
|
|
// ========================
|
|
|
|
|
|
|
|
type backendsProtobufClient struct {
|
|
|
|
urlBase string
|
|
|
|
client *http.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewBackendsProtobufClient creates a Protobuf client that implements the Backends interface.
|
|
|
|
// It communicates using protobuf messages and can be configured with a custom http.Client.
|
|
|
|
func NewBackendsProtobufClient(addr string, client *http.Client) Backends {
|
|
|
|
return &backendsProtobufClient{
|
|
|
|
urlBase: urlBase(addr),
|
|
|
|
client: withoutRedirects(client),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *backendsProtobufClient) List(ctx context.Context, in *BackendSelector) (*BackendList, error) {
|
|
|
|
url := c.urlBase + BackendsPathPrefix + "List"
|
|
|
|
out := new(BackendList)
|
|
|
|
err := doProtoRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *backendsProtobufClient) Kill(ctx context.Context, in *BackendID) (*Nil, error) {
|
|
|
|
url := c.urlBase + BackendsPathPrefix + "Kill"
|
|
|
|
out := new(Nil)
|
|
|
|
err := doProtoRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// ====================
|
|
|
|
// Backends JSON Client
|
|
|
|
// ====================
|
|
|
|
|
|
|
|
type backendsJSONClient struct {
|
|
|
|
urlBase string
|
|
|
|
client *http.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewBackendsJSONClient creates a JSON client that implements the Backends interface.
|
|
|
|
// It communicates using JSON requests and responses instead of protobuf messages.
|
|
|
|
func NewBackendsJSONClient(addr string, client *http.Client) Backends {
|
|
|
|
return &backendsJSONClient{
|
|
|
|
urlBase: urlBase(addr),
|
|
|
|
client: withoutRedirects(client),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *backendsJSONClient) List(ctx context.Context, in *BackendSelector) (*BackendList, error) {
|
|
|
|
url := c.urlBase + BackendsPathPrefix + "List"
|
|
|
|
out := new(BackendList)
|
|
|
|
err := doJSONRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *backendsJSONClient) Kill(ctx context.Context, in *BackendID) (*Nil, error) {
|
|
|
|
url := c.urlBase + BackendsPathPrefix + "Kill"
|
|
|
|
out := new(Nil)
|
|
|
|
err := doJSONRequest(ctx, c.client, url, in, out)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// =======================
|
|
|
|
// Backends Server Handler
|
|
|
|
// =======================
|
|
|
|
|
|
|
|
type backendsServer struct {
|
|
|
|
Backends
|
|
|
|
hooks *twirp.ServerHooks
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewBackendsServer(svc Backends, hooks *twirp.ServerHooks) TwirpServer {
|
|
|
|
return &backendsServer{
|
|
|
|
Backends: svc,
|
|
|
|
hooks: hooks,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeError writes an HTTP response with a valid Twirp error format, and triggers hooks.
|
|
|
|
// If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err)
|
|
|
|
func (s *backendsServer) writeError(ctx context.Context, resp http.ResponseWriter, err error) {
|
|
|
|
writeError(ctx, resp, err, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
// BackendsPathPrefix is used for all URL paths on a twirp Backends server.
|
|
|
|
// Requests are always: POST BackendsPathPrefix/method
|
|
|
|
// It can be used in an HTTP mux to route twirp requests along with non-twirp requests on other routes.
|
2018-01-21 16:22:10 +00:00
|
|
|
const BackendsPathPrefix = "/twirp/xeserv.us.route.Backends/"
|
2018-01-21 15:22:13 +00:00
|
|
|
|
|
|
|
func (s *backendsServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
|
|
|
|
ctx := req.Context()
|
2018-01-21 16:22:10 +00:00
|
|
|
ctx = ctxsetters.WithPackageName(ctx, "xeserv.us.route")
|
2018-01-21 15:22:13 +00:00
|
|
|
ctx = ctxsetters.WithServiceName(ctx, "Backends")
|
|
|
|
ctx = ctxsetters.WithResponseWriter(ctx, resp)
|
|
|
|
|
|
|
|
var err error
|
|
|
|
ctx, err = callRequestReceived(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.Method != "POST" {
|
|
|
|
msg := fmt.Sprintf("unsupported method %q (only POST is allowed)", req.Method)
|
|
|
|
err = badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch req.URL.Path {
|
2018-01-21 16:22:10 +00:00
|
|
|
case "/twirp/xeserv.us.route.Backends/List":
|
2018-01-21 15:22:13 +00:00
|
|
|
s.serveList(ctx, resp, req)
|
|
|
|
return
|
2018-01-21 16:22:10 +00:00
|
|
|
case "/twirp/xeserv.us.route.Backends/Kill":
|
2018-01-21 15:22:13 +00:00
|
|
|
s.serveKill(ctx, resp, req)
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("no handler for path %q", req.URL.Path)
|
|
|
|
err = badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *backendsServer) serveList(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
switch req.Header.Get("Content-Type") {
|
|
|
|
case "application/json":
|
|
|
|
s.serveListJSON(ctx, resp, req)
|
|
|
|
case "application/protobuf":
|
|
|
|
s.serveListProtobuf(ctx, resp, req)
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
|
|
|
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, twerr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *backendsServer) serveListJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "List")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
reqContent := new(BackendSelector)
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request json")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *BackendList
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.List(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *BackendList and nil error while calling List. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal json response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(buf.Bytes()); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *backendsServer) serveListProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "List")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
buf, err := ioutil.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to read request body")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqContent := new(BackendSelector)
|
|
|
|
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request proto")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *BackendList
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.List(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *BackendList and nil error while calling List. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
respBytes, err := proto.Marshal(respContent)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal proto response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/protobuf")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(respBytes); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *backendsServer) serveKill(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
switch req.Header.Get("Content-Type") {
|
|
|
|
case "application/json":
|
|
|
|
s.serveKillJSON(ctx, resp, req)
|
|
|
|
case "application/protobuf":
|
|
|
|
s.serveKillProtobuf(ctx, resp, req)
|
|
|
|
default:
|
|
|
|
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
|
|
|
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
|
|
|
s.writeError(ctx, resp, twerr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *backendsServer) serveKillJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Kill")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
reqContent := new(BackendID)
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request json")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Nil
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Kill(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Nil and nil error while calling Kill. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal json response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(buf.Bytes()); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *backendsServer) serveKillProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
ctx = ctxsetters.WithMethodName(ctx, "Kill")
|
|
|
|
ctx, err = callRequestRouted(ctx, s.hooks)
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer closebody(req.Body)
|
|
|
|
buf, err := ioutil.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to read request body")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqContent := new(BackendID)
|
|
|
|
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
|
|
|
err = wrapErr(err, "failed to parse request proto")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call service method
|
|
|
|
var respContent *Nil
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
// In case of a panic, serve a 500 error and then panic.
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("Internal service panic"))
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
respContent, err = s.Kill(ctx, reqContent)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
s.writeError(ctx, resp, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respContent == nil {
|
|
|
|
s.writeError(ctx, resp, twirp.InternalError("received a nil *Nil and nil error while calling Kill. nil responses are not supported"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = callResponsePrepared(ctx, s.hooks)
|
|
|
|
|
|
|
|
respBytes, err := proto.Marshal(respContent)
|
|
|
|
if err != nil {
|
|
|
|
err = wrapErr(err, "failed to marshal proto response")
|
|
|
|
s.writeError(ctx, resp, twirp.InternalErrorWith(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
|
|
|
resp.Header().Set("Content-Type", "application/protobuf")
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
if _, err = resp.Write(respBytes); err != nil {
|
|
|
|
log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
|
|
|
|
}
|
|
|
|
callResponseSent(ctx, s.hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *backendsServer) ServiceDescriptor() ([]byte, int) {
|
|
|
|
return twirpFileDescriptor0, 2
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *backendsServer) ProtocGenTwirpVersion() string {
|
|
|
|
return "v5.0.0"
|
|
|
|
}
|
|
|
|
|
|
|
|
// =====
|
|
|
|
// Utils
|
|
|
|
// =====
|
|
|
|
|
|
|
|
// TwirpServer is the interface generated server structs will support: they're
|
|
|
|
// HTTP handlers with additional methods for accessing metadata about the
|
|
|
|
// service. Those accessors are a low-level API for building reflection tools.
|
|
|
|
// Most people can think of TwirpServers as just http.Handlers.
|
|
|
|
type TwirpServer interface {
|
|
|
|
http.Handler
|
|
|
|
// ServiceDescriptor returns gzipped bytes describing the .proto file that
|
|
|
|
// this service was generated from. Once unzipped, the bytes can be
|
|
|
|
// unmarshaled as a
|
|
|
|
// github.com/golang/protobuf/protoc-gen-go/descriptor.FileDescriptorProto.
|
|
|
|
//
|
|
|
|
// The returned integer is the index of this particular service within that
|
|
|
|
// FileDescriptorProto's 'Service' slice of ServiceDescriptorProtos. This is a
|
|
|
|
// low-level field, expected to be used for reflection.
|
|
|
|
ServiceDescriptor() ([]byte, int)
|
|
|
|
// ProtocGenTwirpVersion is the semantic version string of the version of
|
|
|
|
// twirp used to generate this file.
|
|
|
|
ProtocGenTwirpVersion() string
|
|
|
|
}
|
|
|
|
|
|
|
|
// done returns ctx.Err() if ctx.Done() indicates that the context done
|
|
|
|
func done(ctx context.Context) error {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return ctx.Err()
|
|
|
|
default:
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteError writes an HTTP response with a valid Twirp error format.
|
|
|
|
// If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err)
|
|
|
|
func WriteError(resp http.ResponseWriter, err error) {
|
|
|
|
writeError(context.Background(), resp, err, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeError writes Twirp errors in the response and triggers hooks.
|
|
|
|
func writeError(ctx context.Context, resp http.ResponseWriter, err error, hooks *twirp.ServerHooks) {
|
|
|
|
// Non-twirp errors are wrapped as Internal (default)
|
|
|
|
twerr, ok := err.(twirp.Error)
|
|
|
|
if !ok {
|
|
|
|
twerr = twirp.InternalErrorWith(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
statusCode := twirp.ServerHTTPStatusFromErrorCode(twerr.Code())
|
|
|
|
ctx = ctxsetters.WithStatusCode(ctx, statusCode)
|
|
|
|
ctx = callError(ctx, hooks, twerr)
|
|
|
|
|
|
|
|
resp.Header().Set("Content-Type", "application/json") // Error responses are always JSON (instead of protobuf)
|
|
|
|
resp.WriteHeader(statusCode) // HTTP response status code
|
|
|
|
|
|
|
|
respBody := marshalErrorToJSON(twerr)
|
|
|
|
_, err2 := resp.Write(respBody)
|
|
|
|
if err2 != nil {
|
|
|
|
log.Printf("unable to send error message %q: %s", twerr, err2)
|
|
|
|
}
|
|
|
|
|
|
|
|
callResponseSent(ctx, hooks)
|
|
|
|
}
|
|
|
|
|
|
|
|
// urlBase helps ensure that addr specifies a scheme. If it is unparsable
|
|
|
|
// as a URL, it returns addr unchanged.
|
|
|
|
func urlBase(addr string) string {
|
|
|
|
// If the addr specifies a scheme, use it. If not, default to
|
|
|
|
// http. If url.Parse fails on it, return it unchanged.
|
|
|
|
url, err := url.Parse(addr)
|
|
|
|
if err != nil {
|
|
|
|
return addr
|
|
|
|
}
|
|
|
|
if url.Scheme == "" {
|
|
|
|
url.Scheme = "http"
|
|
|
|
}
|
|
|
|
return url.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
// getCustomHTTPReqHeaders retrieves a copy of any headers that are set in
|
|
|
|
// a context through the twirp.WithHTTPRequestHeaders function.
|
|
|
|
// If there are no headers set, or if they have the wrong type, nil is returned.
|
|
|
|
func getCustomHTTPReqHeaders(ctx context.Context) http.Header {
|
|
|
|
header, ok := twirp.HTTPRequestHeaders(ctx)
|
|
|
|
if !ok || header == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
copied := make(http.Header)
|
|
|
|
for k, vv := range header {
|
|
|
|
if vv == nil {
|
|
|
|
copied[k] = nil
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
copied[k] = make([]string, len(vv))
|
|
|
|
copy(copied[k], vv)
|
|
|
|
}
|
|
|
|
return copied
|
|
|
|
}
|
|
|
|
|
|
|
|
// closebody closes a response or request body and just logs
|
|
|
|
// any error encountered while closing, since errors are
|
|
|
|
// considered very unusual.
|
|
|
|
func closebody(body io.Closer) {
|
|
|
|
if err := body.Close(); err != nil {
|
|
|
|
log.Printf("error closing body: %q", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// newRequest makes an http.Request from a client, adding common headers.
|
|
|
|
func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType string) (*http.Request, error) {
|
|
|
|
req, err := http.NewRequest("POST", url, reqBody)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
req = req.WithContext(ctx)
|
|
|
|
if customHeader := getCustomHTTPReqHeaders(ctx); customHeader != nil {
|
|
|
|
req.Header = customHeader
|
|
|
|
}
|
|
|
|
req.Header.Set("Content-Type", contentType)
|
|
|
|
req.Header.Set("Twirp-Version", "v5.0.0")
|
|
|
|
return req, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// JSON serialization for errors
|
|
|
|
type twerrJSON struct {
|
|
|
|
Code string `json:"code"`
|
|
|
|
Msg string `json:"msg"`
|
|
|
|
Meta map[string]string `json:"meta,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// marshalErrorToJSON returns JSON from a twirp.Error, that can be used as HTTP error response body.
|
|
|
|
// If serialization fails, it will use a descriptive Internal error instead.
|
|
|
|
func marshalErrorToJSON(twerr twirp.Error) []byte {
|
|
|
|
// make sure that msg is not too large
|
|
|
|
msg := twerr.Msg()
|
|
|
|
if len(msg) > 1e6 {
|
|
|
|
msg = msg[:1e6]
|
|
|
|
}
|
|
|
|
|
|
|
|
tj := twerrJSON{
|
|
|
|
Code: string(twerr.Code()),
|
|
|
|
Msg: msg,
|
|
|
|
Meta: twerr.MetaMap(),
|
|
|
|
}
|
|
|
|
|
|
|
|
buf, err := json.Marshal(&tj)
|
|
|
|
if err != nil {
|
|
|
|
buf = []byte("{\"type\": \"" + twirp.Internal + "\", \"msg\": \"There was an error but it could not be serialized into JSON\"}") // fallback
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf
|
|
|
|
}
|
|
|
|
|
|
|
|
// errorFromResponse builds a twirp.Error from a non-200 HTTP response.
|
|
|
|
// If the response has a valid serialized Twirp error, then it's returned.
|
|
|
|
// If not, the response status code is used to generate a similar twirp
|
|
|
|
// error. See twirpErrorFromIntermediary for more info on intermediary errors.
|
|
|
|
func errorFromResponse(resp *http.Response) twirp.Error {
|
|
|
|
statusCode := resp.StatusCode
|
|
|
|
statusText := http.StatusText(statusCode)
|
|
|
|
|
|
|
|
if isHTTPRedirect(statusCode) {
|
|
|
|
// Unexpected redirect: it must be an error from an intermediary.
|
|
|
|
// Twirp clients dont't follow redirects automatically, Twirp only handles
|
|
|
|
// POST requests, redirects should only happen on GET and HEAD requests.
|
|
|
|
location := resp.Header.Get("Location")
|
|
|
|
msg := fmt.Sprintf("unexpected HTTP status code %d %q received, Location=%q", statusCode, statusText, location)
|
|
|
|
return twirpErrorFromIntermediary(statusCode, msg, location)
|
|
|
|
}
|
|
|
|
|
|
|
|
respBodyBytes, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return clientError("failed to read server error response body", err)
|
|
|
|
}
|
|
|
|
var tj twerrJSON
|
|
|
|
if err := json.Unmarshal(respBodyBytes, &tj); err != nil {
|
|
|
|
// Invalid JSON response; it must be an error from an intermediary.
|
|
|
|
msg := fmt.Sprintf("Error from intermediary with HTTP status code %d %q", statusCode, statusText)
|
|
|
|
return twirpErrorFromIntermediary(statusCode, msg, string(respBodyBytes))
|
|
|
|
}
|
|
|
|
|
|
|
|
errorCode := twirp.ErrorCode(tj.Code)
|
|
|
|
if !twirp.IsValidErrorCode(errorCode) {
|
|
|
|
msg := "invalid type returned from server error response: " + tj.Code
|
|
|
|
return twirp.InternalError(msg)
|
|
|
|
}
|
|
|
|
|
|
|
|
twerr := twirp.NewError(errorCode, tj.Msg)
|
|
|
|
for k, v := range tj.Meta {
|
|
|
|
twerr = twerr.WithMeta(k, v)
|
|
|
|
}
|
|
|
|
return twerr
|
|
|
|
}
|
|
|
|
|
|
|
|
// twirpErrorFromIntermediary maps HTTP errors from non-twirp sources to twirp errors.
|
|
|
|
// The mapping is similar to gRPC: https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md.
|
|
|
|
// Returned twirp Errors have some additional metadata for inspection.
|
|
|
|
func twirpErrorFromIntermediary(status int, msg string, bodyOrLocation string) twirp.Error {
|
|
|
|
var code twirp.ErrorCode
|
|
|
|
if isHTTPRedirect(status) { // 3xx
|
|
|
|
code = twirp.Internal
|
|
|
|
} else {
|
|
|
|
switch status {
|
|
|
|
case 400: // Bad Request
|
|
|
|
code = twirp.Internal
|
|
|
|
case 401: // Unauthorized
|
|
|
|
code = twirp.Unauthenticated
|
|
|
|
case 403: // Forbidden
|
|
|
|
code = twirp.PermissionDenied
|
|
|
|
case 404: // Not Found
|
|
|
|
code = twirp.BadRoute
|
|
|
|
case 429, 502, 503, 504: // Too Many Requests, Bad Gateway, Service Unavailable, Gateway Timeout
|
|
|
|
code = twirp.Unavailable
|
|
|
|
default: // All other codes
|
|
|
|
code = twirp.Unknown
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
twerr := twirp.NewError(code, msg)
|
|
|
|
twerr = twerr.WithMeta("http_error_from_intermediary", "true") // to easily know if this error was from intermediary
|
|
|
|
twerr = twerr.WithMeta("status_code", strconv.Itoa(status))
|
|
|
|
if isHTTPRedirect(status) {
|
|
|
|
twerr = twerr.WithMeta("location", bodyOrLocation)
|
|
|
|
} else {
|
|
|
|
twerr = twerr.WithMeta("body", bodyOrLocation)
|
|
|
|
}
|
|
|
|
return twerr
|
|
|
|
}
|
|
|
|
func isHTTPRedirect(status int) bool {
|
|
|
|
return status >= 300 && status <= 399
|
|
|
|
}
|
|
|
|
|
|
|
|
// wrappedError implements the github.com/pkg/errors.Causer interface, allowing errors to be
|
|
|
|
// examined for their root cause.
|
|
|
|
type wrappedError struct {
|
|
|
|
msg string
|
|
|
|
cause error
|
|
|
|
}
|
|
|
|
|
|
|
|
func wrapErr(err error, msg string) error { return &wrappedError{msg: msg, cause: err} }
|
|
|
|
func (e *wrappedError) Cause() error { return e.cause }
|
|
|
|
func (e *wrappedError) Error() string { return e.msg + ": " + e.cause.Error() }
|
|
|
|
|
|
|
|
// clientError adds consistency to errors generated in the client
|
|
|
|
func clientError(desc string, err error) twirp.Error {
|
|
|
|
return twirp.InternalErrorWith(wrapErr(err, desc))
|
|
|
|
}
|
|
|
|
|
|
|
|
// badRouteError is used when the twirp server cannot route a request
|
|
|
|
func badRouteError(msg string, method, url string) twirp.Error {
|
|
|
|
err := twirp.NewError(twirp.BadRoute, msg)
|
|
|
|
err = err.WithMeta("twirp_invalid_route", method+" "+url)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// The standard library will, by default, redirect requests (including POSTs) if it gets a 302 or
|
|
|
|
// 303 response, and also 301s in go1.8. It redirects by making a second request, changing the
|
|
|
|
// method to GET and removing the body. This produces very confusing error messages, so instead we
|
|
|
|
// set a redirect policy that always errors. This stops Go from executing the redirect.
|
|
|
|
//
|
|
|
|
// We have to be a little careful in case the user-provided http.Client has its own CheckRedirect
|
|
|
|
// policy - if so, we'll run through that policy first.
|
|
|
|
//
|
|
|
|
// Because this requires modifying the http.Client, we make a new copy of the client and return it.
|
|
|
|
func withoutRedirects(in *http.Client) *http.Client {
|
|
|
|
copy := *in
|
|
|
|
copy.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
|
|
|
if in.CheckRedirect != nil {
|
|
|
|
// Run the input's redirect if it exists, in case it has side effects, but ignore any error it
|
|
|
|
// returns, since we want to use ErrUseLastResponse.
|
|
|
|
err := in.CheckRedirect(req, via)
|
|
|
|
_ = err // Silly, but this makes sure generated code passes errcheck -blank, which some people use.
|
|
|
|
}
|
|
|
|
return http.ErrUseLastResponse
|
|
|
|
}
|
|
|
|
return ©
|
|
|
|
}
|
|
|
|
|
|
|
|
// doProtoRequest is common code to make a request to the remote twirp service.
|
|
|
|
func doProtoRequest(ctx context.Context, client *http.Client, url string, in, out proto.Message) error {
|
|
|
|
var err error
|
|
|
|
reqBodyBytes, err := proto.Marshal(in)
|
|
|
|
if err != nil {
|
|
|
|
return clientError("failed to marshal proto request", err)
|
|
|
|
}
|
|
|
|
reqBody := bytes.NewBuffer(reqBodyBytes)
|
|
|
|
if err = done(ctx); err != nil {
|
|
|
|
return clientError("aborted because context was done", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := newRequest(ctx, url, reqBody, "application/protobuf")
|
|
|
|
if err != nil {
|
|
|
|
return clientError("could not build request", err)
|
|
|
|
}
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return clientError("failed to do request", err)
|
|
|
|
}
|
|
|
|
defer closebody(resp.Body)
|
|
|
|
if err = done(ctx); err != nil {
|
|
|
|
return clientError("aborted because context was done", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
return errorFromResponse(resp)
|
|
|
|
}
|
|
|
|
|
|
|
|
respBodyBytes, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return clientError("failed to read response body", err)
|
|
|
|
}
|
|
|
|
if err = done(ctx); err != nil {
|
|
|
|
return clientError("aborted because context was done", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = proto.Unmarshal(respBodyBytes, out); err != nil {
|
|
|
|
return clientError("failed to unmarshal proto response", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// doJSONRequest is common code to make a request to the remote twirp service.
|
|
|
|
func doJSONRequest(ctx context.Context, client *http.Client, url string, in, out proto.Message) error {
|
|
|
|
var err error
|
|
|
|
reqBody := bytes.NewBuffer(nil)
|
|
|
|
marshaler := &jsonpb.Marshaler{OrigName: true}
|
|
|
|
if err = marshaler.Marshal(reqBody, in); err != nil {
|
|
|
|
return clientError("failed to marshal json request", err)
|
|
|
|
}
|
|
|
|
if err = done(ctx); err != nil {
|
|
|
|
return clientError("aborted because context was done", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := newRequest(ctx, url, reqBody, "application/json")
|
|
|
|
if err != nil {
|
|
|
|
return clientError("could not build request", err)
|
|
|
|
}
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return clientError("failed to do request", err)
|
|
|
|
}
|
|
|
|
defer closebody(resp.Body)
|
|
|
|
if err = done(ctx); err != nil {
|
|
|
|
return clientError("aborted because context was done", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
return errorFromResponse(resp)
|
|
|
|
}
|
|
|
|
|
|
|
|
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
|
|
|
if err = unmarshaler.Unmarshal(resp.Body, out); err != nil {
|
|
|
|
return clientError("failed to unmarshal json response", err)
|
|
|
|
}
|
|
|
|
if err = done(ctx); err != nil {
|
|
|
|
return clientError("aborted because context was done", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call twirp.ServerHooks.RequestReceived if the hook is available
|
|
|
|
func callRequestReceived(ctx context.Context, h *twirp.ServerHooks) (context.Context, error) {
|
|
|
|
if h == nil || h.RequestReceived == nil {
|
|
|
|
return ctx, nil
|
|
|
|
}
|
|
|
|
return h.RequestReceived(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call twirp.ServerHooks.RequestRouted if the hook is available
|
|
|
|
func callRequestRouted(ctx context.Context, h *twirp.ServerHooks) (context.Context, error) {
|
|
|
|
if h == nil || h.RequestRouted == nil {
|
|
|
|
return ctx, nil
|
|
|
|
}
|
|
|
|
return h.RequestRouted(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call twirp.ServerHooks.ResponsePrepared if the hook is available
|
|
|
|
func callResponsePrepared(ctx context.Context, h *twirp.ServerHooks) context.Context {
|
|
|
|
if h == nil || h.ResponsePrepared == nil {
|
|
|
|
return ctx
|
|
|
|
}
|
|
|
|
return h.ResponsePrepared(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call twirp.ServerHooks.ResponseSent if the hook is available
|
|
|
|
func callResponseSent(ctx context.Context, h *twirp.ServerHooks) {
|
|
|
|
if h == nil || h.ResponseSent == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
h.ResponseSent(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call twirp.ServerHooks.Error if the hook is available
|
|
|
|
func callError(ctx context.Context, h *twirp.ServerHooks, err twirp.Error) context.Context {
|
|
|
|
if h == nil || h.Error == nil {
|
|
|
|
return ctx
|
|
|
|
}
|
|
|
|
return h.Error(ctx, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var twirpFileDescriptor0 = []byte{
|
2018-01-21 16:22:10 +00:00
|
|
|
// 579 bytes of a gzipped FileDescriptorProto
|
|
|
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xc1, 0x6e, 0xd3, 0x40,
|
|
|
|
0x10, 0x8d, 0xed, 0xd8, 0x49, 0x27, 0x12, 0x41, 0xa3, 0xa8, 0x32, 0x81, 0x83, 0xb5, 0x12, 0x52,
|
|
|
|
0x4e, 0x16, 0x0a, 0x48, 0x85, 0x02, 0x87, 0x56, 0x81, 0x50, 0x81, 0x2a, 0xe4, 0x70, 0x82, 0x93,
|
|
|
|
0x1d, 0x8f, 0x54, 0xab, 0x26, 0x0e, 0xde, 0x75, 0x05, 0x5f, 0xc0, 0x95, 0x2b, 0x9f, 0xc2, 0xdf,
|
|
|
|
0x21, 0xcf, 0x6e, 0xda, 0x12, 0xc7, 0xa9, 0x38, 0x65, 0x66, 0xf6, 0xcd, 0xfa, 0xbd, 0xb7, 0x33,
|
|
|
|
0x81, 0x41, 0x59, 0x54, 0x8a, 0xc2, 0x75, 0x59, 0xa8, 0x02, 0x87, 0xdf, 0x49, 0x52, 0x79, 0x15,
|
|
|
|
0x56, 0x32, 0xe4, 0xb2, 0x70, 0xc1, 0x39, 0xcf, 0x72, 0xf1, 0x02, 0x86, 0x73, 0x52, 0x51, 0x5d,
|
|
|
|
0x8a, 0xe8, 0x5b, 0x45, 0x52, 0xe1, 0x21, 0x78, 0xd5, 0xaa, 0x92, 0x94, 0xfa, 0x56, 0x60, 0x4d,
|
|
|
|
0x0e, 0x22, 0x93, 0xe1, 0x3d, 0xb0, 0xb3, 0xd4, 0xb7, 0xb9, 0x66, 0x67, 0xa9, 0x78, 0x03, 0x2e,
|
|
|
|
0xf7, 0x99, 0x03, 0x6b, 0x73, 0x80, 0x3e, 0xf4, 0x96, 0x25, 0xc5, 0xaa, 0x28, 0x0d, 0x7a, 0x93,
|
|
|
|
0x22, 0x42, 0xf7, 0xa2, 0x90, 0xca, 0x77, 0xb8, 0xcc, 0xb1, 0x78, 0x0b, 0xa3, 0x39, 0xa9, 0x93,
|
|
|
|
0x3c, 0xe7, 0xcb, 0x64, 0x44, 0x72, 0x5d, 0xac, 0x24, 0x61, 0x08, 0x1e, 0x33, 0x95, 0xbe, 0x15,
|
|
|
|
0x38, 0x93, 0xc1, 0xf4, 0x30, 0xdc, 0x92, 0x10, 0x6a, 0xd6, 0x06, 0x25, 0xbe, 0x80, 0xfb, 0xa9,
|
|
|
|
0xb8, 0xa4, 0x55, 0x83, 0x0e, 0x42, 0x37, 0x29, 0xd2, 0x1f, 0x86, 0x0b, 0xc7, 0xb5, 0x46, 0xb9,
|
|
|
|
0x2c, 0xd6, 0x24, 0x7d, 0x27, 0x70, 0x6a, 0x8d, 0x3a, 0xab, 0xeb, 0xf1, 0x52, 0x65, 0x57, 0xe4,
|
|
|
|
0x77, 0x03, 0x6b, 0xd2, 0x8f, 0x4c, 0x26, 0x8e, 0xa1, 0xcf, 0x97, 0x2f, 0x48, 0xd5, 0xc4, 0x54,
|
|
|
|
0x1d, 0xb7, 0x13, 0x63, 0x68, 0x64, 0x50, 0xe2, 0x88, 0x2d, 0xd6, 0x35, 0x63, 0xf1, 0x08, 0x5c,
|
|
|
|
0x3e, 0x34, 0x2c, 0x75, 0xd2, 0x30, 0xf8, 0xb7, 0x05, 0xbd, 0xd3, 0x78, 0x79, 0x49, 0xab, 0xb4,
|
|
|
|
0x21, 0x6a, 0x04, 0x2e, 0x3f, 0xac, 0x81, 0xeb, 0xa4, 0x96, 0x5a, 0x49, 0x2a, 0x37, 0xfe, 0xd6,
|
|
|
|
0x71, 0x2d, 0x29, 0x2d, 0xbe, 0xc6, 0xd9, 0x8a, 0x25, 0x1d, 0x44, 0x26, 0xc3, 0xfb, 0xe0, 0xac,
|
|
|
|
0x2f, 0x32, 0xdf, 0x0d, 0xac, 0x89, 0x1d, 0xd5, 0xe1, 0xf5, 0xeb, 0x78, 0x37, 0xaf, 0xc3, 0xc3,
|
|
|
|
0x20, 0xe3, 0x24, 0x27, 0xbf, 0xa7, 0x0d, 0xd1, 0x99, 0xa8, 0x60, 0x60, 0xa8, 0x7d, 0xc8, 0xa4,
|
|
|
|
0xc2, 0x27, 0x60, 0x27, 0x92, 0xe9, 0x0d, 0xa6, 0x41, 0xc3, 0x0f, 0x83, 0x5c, 0x50, 0x4e, 0x4b,
|
|
|
|
0x55, 0x94, 0x91, 0x9d, 0x48, 0x7c, 0x06, 0xfd, 0x44, 0x97, 0xa5, 0x6f, 0xb3, 0x8f, 0x7e, 0x5b,
|
|
|
|
0x5f, 0x74, 0x8d, 0x14, 0xaf, 0x61, 0xb8, 0x75, 0xd9, 0x2d, 0x7d, 0xd6, 0x3f, 0xfa, 0x36, 0x5e,
|
|
|
|
0xd8, 0x37, 0x5e, 0x88, 0x87, 0x70, 0x60, 0xda, 0xcf, 0x66, 0xdb, 0x96, 0x4e, 0x7f, 0xda, 0xe0,
|
|
|
|
0xe9, 0x19, 0xc4, 0x13, 0x70, 0xe6, 0xa4, 0xb0, 0xa9, 0x64, 0x6b, 0x57, 0xc6, 0x2d, 0x43, 0x29,
|
|
|
|
0x3a, 0x38, 0x07, 0x4f, 0x8f, 0x35, 0x8e, 0x1a, 0x98, 0xf3, 0x2c, 0x1f, 0x3f, 0xde, 0x75, 0x77,
|
|
|
|
0x63, 0x0b, 0x44, 0x07, 0x8f, 0xc0, 0xf9, 0x58, 0x29, 0x6c, 0xf9, 0xd2, 0x1e, 0x06, 0xcf, 0xc1,
|
|
|
|
0x9b, 0x51, 0x4e, 0x8a, 0x5a, 0x7b, 0x77, 0x32, 0x13, 0x9d, 0xe9, 0x1f, 0x1b, 0x3c, 0x9e, 0xd7,
|
|
|
|
0xfd, 0x4e, 0xdc, 0x1e, 0xe9, 0x71, 0xcb, 0x16, 0x88, 0x0e, 0xbe, 0xbc, 0xc3, 0x89, 0x07, 0xbb,
|
|
|
|
0x3b, 0x17, 0xa4, 0xf6, 0xa9, 0x67, 0xcc, 0x9e, 0xaf, 0xee, 0x53, 0xaf, 0x7b, 0x5b, 0xd4, 0xe3,
|
|
|
|
0x2b, 0x80, 0x19, 0xf1, 0xde, 0xc7, 0xff, 0xdf, 0x3d, 0xfd, 0x65, 0x41, 0xdf, 0xcc, 0x98, 0xc4,
|
|
|
|
0x77, 0xd0, 0xe5, 0xf5, 0xb8, 0x73, 0x25, 0xc6, 0x8f, 0xda, 0x10, 0x75, 0xbf, 0xe8, 0xe0, 0x31,
|
|
|
|
0x74, 0xdf, 0x67, 0x79, 0x8e, 0xe3, 0x36, 0xdc, 0xd9, 0xac, 0x8d, 0xd2, 0x69, 0xef, 0xb3, 0xfe,
|
|
|
|
0x7b, 0x48, 0x3c, 0xfe, 0x79, 0xfa, 0x37, 0x00, 0x00, 0xff, 0xff, 0x0e, 0x50, 0x5f, 0x13, 0x1a,
|
|
|
|
0x06, 0x00, 0x00,
|
2018-01-21 15:22:13 +00:00
|
|
|
}
|