// Code generated by protoc-gen-twirp v3.0.0
// source: code.justin.tv/rhys/nursery/ext/power_v1/power.proto
// DO NOT EDIT!

/*
Package power_v1 is a generated twirp stub package.
This code was generated with code.justin.tv/common/twirp/protoc-gen-twirp v3.0.0.

It is generated from these files:
	code.justin.tv/rhys/nursery/ext/power_v1/power.proto
*/
package power_v1

import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api"

import bytes "bytes"
import strconv "strconv"
import context "golang.org/x/net/context"
import chitin "code.justin.tv/common/chitin"
import ctxhttp "golang.org/x/net/context/ctxhttp"
import http "net/http"
import ioutil "io/ioutil"
import jsonpb "github.com/golang/protobuf/jsonpb"
import log "log"
import proto1 "github.com/golang/protobuf/proto"
import twirp "code.justin.tv/common/twirp"

// Imports only used by utility functions:
import io "io"
import strings "strings"
import json "encoding/json"
import url "net/url"

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// ===============
// Power Interface
// ===============

type Power interface {
	GetStatus(context.Context, *GetStatusRequest) (*GetStatusResponse, error)

	GetPowerState(context.Context, *GetPowerStateRequest) (*GetPowerStateResponse, error)

	SetPowerState(context.Context, *SetPowerStateRequest) (*SetPowerStateResponse, error)

	GetFruInfo(context.Context, *GetFruInfoRequest) (*GetFruInfoResponse, error)

	SetBootDevice(context.Context, *SetBootDeviceRequest) (*SetBootDeviceResponse, error)
}

// =============
// Power Clients
// =============

type powerProtobufClient struct {
	urlBase string
	client  *http.Client
}

// NewPowerProtobufClient creates a Protobuf client that implements the Power interface.
// It communicates using protobuf messages and can be configured with a custom http.Client.
func NewPowerProtobufClient(addr string, client *http.Client) Power {
	return &powerProtobufClient{
		urlBase: urlBase(addr),
		client:  client,
	}
}

func (c *powerProtobufClient) GetStatus(ctx context.Context, in *GetStatusRequest) (*GetStatusResponse, error) {
	var err error
	bodyBytes, err := proto1.Marshal(in)
	if err != nil {
		return nil, clientError("failed to marshal proto request", err)
	}
	body := bytes.NewBuffer(bodyBytes)
	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	url := c.urlBase + PowerPathPrefix + "GetStatus"
	req, err := newRequest(ctx, url, body, "application/protobuf")
	if err != nil {
		return nil, clientError("could not build request", err)
	}

	resp, err := ctxhttp.Do(ctx, c.client, req)
	if err != nil {
		return nil, clientError("failed to do request", err)
	}
	defer closebody(resp.Body)

	if resp.StatusCode != 200 {
		return nil, unmarshalErrorFromJSONResponse(resp.Body)
	}

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, clientError("failed to read response body", err)
	}

	if err = done(ctx); err != nil {
		return nil, clientError("failed to read response because context was done", err)
	}

	respContent := new(GetStatusResponse)
	if err = proto1.Unmarshal(respBody, respContent); err != nil {
		return nil, clientError("failed to unmarshal proto response", err)
	}

	return respContent, nil
}

func (c *powerProtobufClient) GetPowerState(ctx context.Context, in *GetPowerStateRequest) (*GetPowerStateResponse, error) {
	var err error
	bodyBytes, err := proto1.Marshal(in)
	if err != nil {
		return nil, clientError("failed to marshal proto request", err)
	}
	body := bytes.NewBuffer(bodyBytes)
	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	url := c.urlBase + PowerPathPrefix + "GetPowerState"
	req, err := newRequest(ctx, url, body, "application/protobuf")
	if err != nil {
		return nil, clientError("could not build request", err)
	}

	resp, err := ctxhttp.Do(ctx, c.client, req)
	if err != nil {
		return nil, clientError("failed to do request", err)
	}
	defer closebody(resp.Body)

	if resp.StatusCode != 200 {
		return nil, unmarshalErrorFromJSONResponse(resp.Body)
	}

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, clientError("failed to read response body", err)
	}

	if err = done(ctx); err != nil {
		return nil, clientError("failed to read response because context was done", err)
	}

	respContent := new(GetPowerStateResponse)
	if err = proto1.Unmarshal(respBody, respContent); err != nil {
		return nil, clientError("failed to unmarshal proto response", err)
	}

	return respContent, nil
}

func (c *powerProtobufClient) SetPowerState(ctx context.Context, in *SetPowerStateRequest) (*SetPowerStateResponse, error) {
	var err error
	bodyBytes, err := proto1.Marshal(in)
	if err != nil {
		return nil, clientError("failed to marshal proto request", err)
	}
	body := bytes.NewBuffer(bodyBytes)
	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	url := c.urlBase + PowerPathPrefix + "SetPowerState"
	req, err := newRequest(ctx, url, body, "application/protobuf")
	if err != nil {
		return nil, clientError("could not build request", err)
	}

	resp, err := ctxhttp.Do(ctx, c.client, req)
	if err != nil {
		return nil, clientError("failed to do request", err)
	}
	defer closebody(resp.Body)

	if resp.StatusCode != 200 {
		return nil, unmarshalErrorFromJSONResponse(resp.Body)
	}

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, clientError("failed to read response body", err)
	}

	if err = done(ctx); err != nil {
		return nil, clientError("failed to read response because context was done", err)
	}

	respContent := new(SetPowerStateResponse)
	if err = proto1.Unmarshal(respBody, respContent); err != nil {
		return nil, clientError("failed to unmarshal proto response", err)
	}

	return respContent, nil
}

func (c *powerProtobufClient) GetFruInfo(ctx context.Context, in *GetFruInfoRequest) (*GetFruInfoResponse, error) {
	var err error
	bodyBytes, err := proto1.Marshal(in)
	if err != nil {
		return nil, clientError("failed to marshal proto request", err)
	}
	body := bytes.NewBuffer(bodyBytes)
	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	url := c.urlBase + PowerPathPrefix + "GetFruInfo"
	req, err := newRequest(ctx, url, body, "application/protobuf")
	if err != nil {
		return nil, clientError("could not build request", err)
	}

	resp, err := ctxhttp.Do(ctx, c.client, req)
	if err != nil {
		return nil, clientError("failed to do request", err)
	}
	defer closebody(resp.Body)

	if resp.StatusCode != 200 {
		return nil, unmarshalErrorFromJSONResponse(resp.Body)
	}

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, clientError("failed to read response body", err)
	}

	if err = done(ctx); err != nil {
		return nil, clientError("failed to read response because context was done", err)
	}

	respContent := new(GetFruInfoResponse)
	if err = proto1.Unmarshal(respBody, respContent); err != nil {
		return nil, clientError("failed to unmarshal proto response", err)
	}

	return respContent, nil
}

func (c *powerProtobufClient) SetBootDevice(ctx context.Context, in *SetBootDeviceRequest) (*SetBootDeviceResponse, error) {
	var err error
	bodyBytes, err := proto1.Marshal(in)
	if err != nil {
		return nil, clientError("failed to marshal proto request", err)
	}
	body := bytes.NewBuffer(bodyBytes)
	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	url := c.urlBase + PowerPathPrefix + "SetBootDevice"
	req, err := newRequest(ctx, url, body, "application/protobuf")
	if err != nil {
		return nil, clientError("could not build request", err)
	}

	resp, err := ctxhttp.Do(ctx, c.client, req)
	if err != nil {
		return nil, clientError("failed to do request", err)
	}
	defer closebody(resp.Body)

	if resp.StatusCode != 200 {
		return nil, unmarshalErrorFromJSONResponse(resp.Body)
	}

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, clientError("failed to read response body", err)
	}

	if err = done(ctx); err != nil {
		return nil, clientError("failed to read response because context was done", err)
	}

	respContent := new(SetBootDeviceResponse)
	if err = proto1.Unmarshal(respBody, respContent); err != nil {
		return nil, clientError("failed to unmarshal proto response", err)
	}

	return respContent, nil
}

// NewPowerClient creates a Protobuf client that implements the Power interface.
// It is the same as NewPowerProtobufClient but pre-configured with a Chitin RoundTripper.
func NewPowerClient(addr string) Power {
	chitinRT, err := chitin.RoundTripper(context.Background(), http.DefaultTransport)
	if err != nil {
		panic("You are using a very old version of chitin, please upgrade!")
	}
	chitinClient := http.Client{Transport: chitinRT}
	return NewPowerProtobufClient(addr, &chitinClient)
}

type powerJSONClient struct {
	urlBase string
	client  *http.Client
}

// NewPowerJSONClient creates a JSON client that implements the Power interface.
// It communicates using JSON requests and responses instead of protobuf messages.
func NewPowerJSONClient(addr string, client *http.Client) Power {
	return &powerJSONClient{
		urlBase: urlBase(addr),
		client:  client,
	}
}

func (c *powerJSONClient) GetStatus(ctx context.Context, in *GetStatusRequest) (*GetStatusResponse, error) {
	var err error
	body := bytes.NewBuffer(nil)
	marshaler := &jsonpb.Marshaler{OrigName: true}
	if err = marshaler.Marshal(body, in); err != nil {
		return nil, clientError("failed to marshal json request", err)
	}
	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	url := c.urlBase + PowerPathPrefix + "GetStatus"
	req, err := newRequest(ctx, url, body, "application/json")
	if err != nil {
		return nil, clientError("could not build request", err)
	}

	resp, err := ctxhttp.Do(ctx, c.client, req)
	if err != nil {
		return nil, clientError("failed to do request", err)
	}
	defer closebody(resp.Body)

	if resp.StatusCode != 200 {
		return nil, unmarshalErrorFromJSONResponse(resp.Body)
	}

	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	respContent := new(GetStatusResponse)
	if err = jsonpb.Unmarshal(resp.Body, respContent); err != nil {
		return nil, clientError("failed to unmarshal json response", err)
	}

	return respContent, nil
}

func (c *powerJSONClient) GetPowerState(ctx context.Context, in *GetPowerStateRequest) (*GetPowerStateResponse, error) {
	var err error
	body := bytes.NewBuffer(nil)
	marshaler := &jsonpb.Marshaler{OrigName: true}
	if err = marshaler.Marshal(body, in); err != nil {
		return nil, clientError("failed to marshal json request", err)
	}
	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	url := c.urlBase + PowerPathPrefix + "GetPowerState"
	req, err := newRequest(ctx, url, body, "application/json")
	if err != nil {
		return nil, clientError("could not build request", err)
	}

	resp, err := ctxhttp.Do(ctx, c.client, req)
	if err != nil {
		return nil, clientError("failed to do request", err)
	}
	defer closebody(resp.Body)

	if resp.StatusCode != 200 {
		return nil, unmarshalErrorFromJSONResponse(resp.Body)
	}

	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	respContent := new(GetPowerStateResponse)
	if err = jsonpb.Unmarshal(resp.Body, respContent); err != nil {
		return nil, clientError("failed to unmarshal json response", err)
	}

	return respContent, nil
}

func (c *powerJSONClient) SetPowerState(ctx context.Context, in *SetPowerStateRequest) (*SetPowerStateResponse, error) {
	var err error
	body := bytes.NewBuffer(nil)
	marshaler := &jsonpb.Marshaler{OrigName: true}
	if err = marshaler.Marshal(body, in); err != nil {
		return nil, clientError("failed to marshal json request", err)
	}
	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	url := c.urlBase + PowerPathPrefix + "SetPowerState"
	req, err := newRequest(ctx, url, body, "application/json")
	if err != nil {
		return nil, clientError("could not build request", err)
	}

	resp, err := ctxhttp.Do(ctx, c.client, req)
	if err != nil {
		return nil, clientError("failed to do request", err)
	}
	defer closebody(resp.Body)

	if resp.StatusCode != 200 {
		return nil, unmarshalErrorFromJSONResponse(resp.Body)
	}

	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	respContent := new(SetPowerStateResponse)
	if err = jsonpb.Unmarshal(resp.Body, respContent); err != nil {
		return nil, clientError("failed to unmarshal json response", err)
	}

	return respContent, nil
}

func (c *powerJSONClient) GetFruInfo(ctx context.Context, in *GetFruInfoRequest) (*GetFruInfoResponse, error) {
	var err error
	body := bytes.NewBuffer(nil)
	marshaler := &jsonpb.Marshaler{OrigName: true}
	if err = marshaler.Marshal(body, in); err != nil {
		return nil, clientError("failed to marshal json request", err)
	}
	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	url := c.urlBase + PowerPathPrefix + "GetFruInfo"
	req, err := newRequest(ctx, url, body, "application/json")
	if err != nil {
		return nil, clientError("could not build request", err)
	}

	resp, err := ctxhttp.Do(ctx, c.client, req)
	if err != nil {
		return nil, clientError("failed to do request", err)
	}
	defer closebody(resp.Body)

	if resp.StatusCode != 200 {
		return nil, unmarshalErrorFromJSONResponse(resp.Body)
	}

	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	respContent := new(GetFruInfoResponse)
	if err = jsonpb.Unmarshal(resp.Body, respContent); err != nil {
		return nil, clientError("failed to unmarshal json response", err)
	}

	return respContent, nil
}

func (c *powerJSONClient) SetBootDevice(ctx context.Context, in *SetBootDeviceRequest) (*SetBootDeviceResponse, error) {
	var err error
	body := bytes.NewBuffer(nil)
	marshaler := &jsonpb.Marshaler{OrigName: true}
	if err = marshaler.Marshal(body, in); err != nil {
		return nil, clientError("failed to marshal json request", err)
	}
	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	url := c.urlBase + PowerPathPrefix + "SetBootDevice"
	req, err := newRequest(ctx, url, body, "application/json")
	if err != nil {
		return nil, clientError("could not build request", err)
	}

	resp, err := ctxhttp.Do(ctx, c.client, req)
	if err != nil {
		return nil, clientError("failed to do request", err)
	}
	defer closebody(resp.Body)

	if resp.StatusCode != 200 {
		return nil, unmarshalErrorFromJSONResponse(resp.Body)
	}

	if err = done(ctx); err != nil {
		return nil, clientError("aborted because context was done", err)
	}

	respContent := new(SetBootDeviceResponse)
	if err = jsonpb.Unmarshal(resp.Body, respContent); err != nil {
		return nil, clientError("failed to unmarshal json response", err)
	}

	return respContent, nil
}

// ====================
// Power Server Handler
// ====================

type powerServer struct {
	Power
	hooks     *twirp.ServerHooks
	ctxSource ContextSource
}

func NewPowerServer(svc Power, hooks *twirp.ServerHooks, ctxSrc ContextSource) http.Handler {
	if hooks == nil {
		hooks = twirp.NewServerHooks()
	}
	if ctxSrc == nil {
		ctxSrc = BackgroundContextSource
	}
	return &powerServer{svc, hooks, ctxSrc}
}

// PowerPathPrefix is used for all URL paths on a twirp Power server.
// Requests are always: POST PowerPathPrefix/method
// It can be used in an HTTP mux to route twirp requests along with non-twirp requests on other routes.
const PowerPathPrefix = "/twirp/code_justin_tv.rhys.nursery.ext.power.v1.Power/"

// PowerPathPrefixOld is used to handle requests from v2 Clients.
// If you are using an HTTP mux, please handle this routes as well to upgrade from v2 to v3.
const PowerPathPrefixOld = "/v2/code_justin_tv.rhys.nursery.ext.power.v1.Power/"

func (s *powerServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	ctx := s.ctxSource(resp, req)
	ctx = setServerName(ctx, "Power")
	ctx = setVersionFromPath(ctx, req.URL.Path)
	ctx = s.hooks.RequestReceived(ctx)

	if req.Method != "POST" {
		twerr := twirp.NotFoundError(fmt.Sprintf("unsupported method %q (only POST is allowed)", req.Method))
		twerr = twerr.WithMeta("twirp_invalid_route", req.Method+" "+req.URL.Path)
		s.serveError(ctx, resp, req, twerr)
		return
	}

	switch req.URL.Path {
	case PowerPathPrefix + "GetStatus", PowerPathPrefixOld + "GetStatus", "/v1/Power/GetStatus":
		s.serveGetStatus(ctx, resp, req)
		return
	case PowerPathPrefix + "GetPowerState", PowerPathPrefixOld + "GetPowerState", "/v1/Power/GetPowerState":
		s.serveGetPowerState(ctx, resp, req)
		return
	case PowerPathPrefix + "SetPowerState", PowerPathPrefixOld + "SetPowerState", "/v1/Power/SetPowerState":
		s.serveSetPowerState(ctx, resp, req)
		return
	case PowerPathPrefix + "GetFruInfo", PowerPathPrefixOld + "GetFruInfo", "/v1/Power/GetFruInfo":
		s.serveGetFruInfo(ctx, resp, req)
		return
	case PowerPathPrefix + "SetBootDevice", PowerPathPrefixOld + "SetBootDevice", "/v1/Power/SetBootDevice":
		s.serveSetBootDevice(ctx, resp, req)
		return
	default:
		twerr := twirp.NotFoundError(fmt.Sprintf("no handler for path %q", req.URL.Path))
		twerr = twerr.WithMeta("twirp_invalid_route", req.Method+" "+req.URL.Path)
		s.serveError(ctx, resp, req, twerr)
		return
	}
}

// Make HTTP response from an error.
// If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err)
func (s *powerServer) serveError(ctx context.Context, resp http.ResponseWriter, req *http.Request, err error) {
	// When handling v2 client requests, serve backwards-compatible error responses
	if version := getVersion(ctx); version == "v1" || version == "v2" {
		s.serveErrorV1V2(ctx, resp, req, err)
	} else {
		s.serveErrorV3Plus(ctx, resp, req, err)
	}
}

// v3+ error responses.
func (s *powerServer) serveErrorV3Plus(ctx context.Context, resp http.ResponseWriter, req *http.Request, err error) {
	// 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 = setStatusCode(ctx, statusCode)
	ctx = s.hooks.Error(ctx, 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)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

// v1/v2 backwards-compatible error responses.
// To make it easy to upgrade to v3, a v3 server keeps serving v2-style errors to v2 clients.
func (s *powerServer) serveErrorV1V2(ctx context.Context, resp http.ResponseWriter, req *http.Request, err error) {
	// Non-twirp errors are wrapped as Unknown 500 (default)
	twerr, ok := err.(twirp.Error)
	if !ok {
		twerr = twirp.NewError(twirp.Unknown, err.Error())
	}

	resp.Header().Set("Content-Type", "text/plain")

	// v2err.Retryable <= v3err.Meta("retryable")
	if twerr.Meta("retryable") != "" {
		resp.Header().Set("Twirp-Error-Retryable", "true")
	}

	// v2err.ErrorID <= v3err.Meta("v2_error_id") if present, otherwise v3err.Code()
	// or "unroutable" if generated from twirp router (NotFound with Meta("twirp_invalid_route"))
	var v2ErrorID string
	if twerr.Code() == twirp.NotFound && twerr.Meta("twirp_invalid_route") != "" {
		v2ErrorID = "unroutable" // as was generated by previous router
	} else if twerr.Meta("v2_error_id") != "" {
		v2ErrorID = twerr.Meta("v2_error_id")
	} else {
		v2ErrorID = string(twerr.Code()) // the string-format of v3 codes match v2 error ids for the most part: i.e. "not_found", "internal", "unknown", "canceled", etc.
	}
	resp.Header().Set("Twirp-ErrorID", v2ErrorID)

	// v2err.StatusCode <= v3err.Meta("v2_status_code") if present, otherwise same as in v3
	statusCode, err := strconv.Atoi(twerr.Meta("v2_status_code"))
	if err != nil {
		statusCode = twirp.ServerHTTPStatusFromErrorCode(twerr.Code()) // v3 it's the same as v2 for the most part: i.e. "not_found" is 404
	}
	ctx = setStatusCode(ctx, statusCode)
	ctx = s.hooks.Error(ctx, twerr)
	resp.WriteHeader(statusCode)

	msg := []byte(twerr.Msg())
	if len(msg) > 1e6 {
		msg = msg[:1e6]
	}
	_, err2 := resp.Write(msg)
	if err2 != nil {
		log.Printf("unable to send error message %q: %s", twerr, err2)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

func (s *powerServer) serveGetStatus(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	switch req.Header.Get("Content-Type") {
	case "application/json":
		s.serveGetStatusJSON(ctx, resp, req)
	case "application/protobuf":
		s.serveGetStatusProtobuf(ctx, resp, req)
	default:
		twerr := twirp.NotFoundError(fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")))
		twerr = twerr.WithMeta("twirp_invalid_route", req.Method+" "+req.URL.Path+" - Content-Type:"+req.Header.Get("Content-Type"))
		s.serveError(ctx, resp, req, twerr)
	}
}

func (s *powerServer) serveGetStatusJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	var err error
	ctx = setMethodName(ctx, "GetStatus")
	ctx = s.hooks.RequestRouted(ctx)

	defer closebody(req.Body)
	reqContent := new(GetStatusRequest)
	if err = jsonpb.Unmarshal(req.Body, reqContent); err != nil {
		msg := "failed to parse request json: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}

	// Call service method
	var respContent *GetStatusResponse
	func() {
		defer func() {
			// In case of a panic, serve a 500 error and then panic.
			if r := recover(); r != nil {
				s.serveError(ctx, resp, req, twirp.InternalError("Internal service panic"))
				panic(r)
			}
		}()
		respContent, err = s.GetStatus(ctx, reqContent)
	}()

	if err != nil {
		s.serveError(ctx, resp, req, err)
		return
	}
	if respContent == nil {
		s.serveError(ctx, resp, req, twirp.InternalError("received a nil *GetStatusResponse and nil error while calling GetStatus. nil responses are not supported"))
		return
	}

	ctx = s.hooks.ResponsePrepared(ctx)

	var buf bytes.Buffer
	marshaler := &jsonpb.Marshaler{OrigName: true}
	if err = marshaler.Marshal(&buf, respContent); err != nil {
		s.serveError(ctx, resp, req, twirp.InternalError("failed to marshal json response"))
		return
	}

	ctx = setStatusCode(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)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

func (s *powerServer) serveGetStatusProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	var err error
	ctx = setMethodName(ctx, "GetStatus")
	ctx = s.hooks.RequestRouted(ctx)

	defer closebody(req.Body)
	buf, err := ioutil.ReadAll(req.Body)
	if err != nil {
		msg := "unable to read request body: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}
	reqContent := new(GetStatusRequest)
	if err = proto1.Unmarshal(buf, reqContent); err != nil {
		msg := "failed to parse request proto: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}

	// Call service method
	var respContent *GetStatusResponse
	func() {
		defer func() {
			// In case of a panic, serve a 500 error and then panic.
			if r := recover(); r != nil {
				s.serveError(ctx, resp, req, twirp.InternalError("Internal service panic"))
				panic(r)
			}
		}()
		respContent, err = s.GetStatus(ctx, reqContent)
	}()

	if err != nil {
		s.serveError(ctx, resp, req, err)
		return
	}
	if respContent == nil {
		s.serveError(ctx, resp, req, twirp.InternalError("received a nil *GetStatusResponse and nil error while calling GetStatus. nil responses are not supported"))
		return
	}

	ctx = s.hooks.ResponsePrepared(ctx)

	respBytes, err := proto1.Marshal(respContent)
	if err != nil {
		s.serveError(ctx, resp, req, twirp.InternalError("failed to marshal proto response"))
		return
	}

	ctx = setStatusCode(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)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

func (s *powerServer) serveGetPowerState(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	switch req.Header.Get("Content-Type") {
	case "application/json":
		s.serveGetPowerStateJSON(ctx, resp, req)
	case "application/protobuf":
		s.serveGetPowerStateProtobuf(ctx, resp, req)
	default:
		twerr := twirp.NotFoundError(fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")))
		twerr = twerr.WithMeta("twirp_invalid_route", req.Method+" "+req.URL.Path+" - Content-Type:"+req.Header.Get("Content-Type"))
		s.serveError(ctx, resp, req, twerr)
	}
}

func (s *powerServer) serveGetPowerStateJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	var err error
	ctx = setMethodName(ctx, "GetPowerState")
	ctx = s.hooks.RequestRouted(ctx)

	defer closebody(req.Body)
	reqContent := new(GetPowerStateRequest)
	if err = jsonpb.Unmarshal(req.Body, reqContent); err != nil {
		msg := "failed to parse request json: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}

	// Call service method
	var respContent *GetPowerStateResponse
	func() {
		defer func() {
			// In case of a panic, serve a 500 error and then panic.
			if r := recover(); r != nil {
				s.serveError(ctx, resp, req, twirp.InternalError("Internal service panic"))
				panic(r)
			}
		}()
		respContent, err = s.GetPowerState(ctx, reqContent)
	}()

	if err != nil {
		s.serveError(ctx, resp, req, err)
		return
	}
	if respContent == nil {
		s.serveError(ctx, resp, req, twirp.InternalError("received a nil *GetPowerStateResponse and nil error while calling GetPowerState. nil responses are not supported"))
		return
	}

	ctx = s.hooks.ResponsePrepared(ctx)

	var buf bytes.Buffer
	marshaler := &jsonpb.Marshaler{OrigName: true}
	if err = marshaler.Marshal(&buf, respContent); err != nil {
		s.serveError(ctx, resp, req, twirp.InternalError("failed to marshal json response"))
		return
	}

	ctx = setStatusCode(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)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

func (s *powerServer) serveGetPowerStateProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	var err error
	ctx = setMethodName(ctx, "GetPowerState")
	ctx = s.hooks.RequestRouted(ctx)

	defer closebody(req.Body)
	buf, err := ioutil.ReadAll(req.Body)
	if err != nil {
		msg := "unable to read request body: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}
	reqContent := new(GetPowerStateRequest)
	if err = proto1.Unmarshal(buf, reqContent); err != nil {
		msg := "failed to parse request proto: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}

	// Call service method
	var respContent *GetPowerStateResponse
	func() {
		defer func() {
			// In case of a panic, serve a 500 error and then panic.
			if r := recover(); r != nil {
				s.serveError(ctx, resp, req, twirp.InternalError("Internal service panic"))
				panic(r)
			}
		}()
		respContent, err = s.GetPowerState(ctx, reqContent)
	}()

	if err != nil {
		s.serveError(ctx, resp, req, err)
		return
	}
	if respContent == nil {
		s.serveError(ctx, resp, req, twirp.InternalError("received a nil *GetPowerStateResponse and nil error while calling GetPowerState. nil responses are not supported"))
		return
	}

	ctx = s.hooks.ResponsePrepared(ctx)

	respBytes, err := proto1.Marshal(respContent)
	if err != nil {
		s.serveError(ctx, resp, req, twirp.InternalError("failed to marshal proto response"))
		return
	}

	ctx = setStatusCode(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)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

func (s *powerServer) serveSetPowerState(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	switch req.Header.Get("Content-Type") {
	case "application/json":
		s.serveSetPowerStateJSON(ctx, resp, req)
	case "application/protobuf":
		s.serveSetPowerStateProtobuf(ctx, resp, req)
	default:
		twerr := twirp.NotFoundError(fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")))
		twerr = twerr.WithMeta("twirp_invalid_route", req.Method+" "+req.URL.Path+" - Content-Type:"+req.Header.Get("Content-Type"))
		s.serveError(ctx, resp, req, twerr)
	}
}

func (s *powerServer) serveSetPowerStateJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	var err error
	ctx = setMethodName(ctx, "SetPowerState")
	ctx = s.hooks.RequestRouted(ctx)

	defer closebody(req.Body)
	reqContent := new(SetPowerStateRequest)
	if err = jsonpb.Unmarshal(req.Body, reqContent); err != nil {
		msg := "failed to parse request json: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}

	// Call service method
	var respContent *SetPowerStateResponse
	func() {
		defer func() {
			// In case of a panic, serve a 500 error and then panic.
			if r := recover(); r != nil {
				s.serveError(ctx, resp, req, twirp.InternalError("Internal service panic"))
				panic(r)
			}
		}()
		respContent, err = s.SetPowerState(ctx, reqContent)
	}()

	if err != nil {
		s.serveError(ctx, resp, req, err)
		return
	}
	if respContent == nil {
		s.serveError(ctx, resp, req, twirp.InternalError("received a nil *SetPowerStateResponse and nil error while calling SetPowerState. nil responses are not supported"))
		return
	}

	ctx = s.hooks.ResponsePrepared(ctx)

	var buf bytes.Buffer
	marshaler := &jsonpb.Marshaler{OrigName: true}
	if err = marshaler.Marshal(&buf, respContent); err != nil {
		s.serveError(ctx, resp, req, twirp.InternalError("failed to marshal json response"))
		return
	}

	ctx = setStatusCode(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)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

func (s *powerServer) serveSetPowerStateProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	var err error
	ctx = setMethodName(ctx, "SetPowerState")
	ctx = s.hooks.RequestRouted(ctx)

	defer closebody(req.Body)
	buf, err := ioutil.ReadAll(req.Body)
	if err != nil {
		msg := "unable to read request body: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}
	reqContent := new(SetPowerStateRequest)
	if err = proto1.Unmarshal(buf, reqContent); err != nil {
		msg := "failed to parse request proto: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}

	// Call service method
	var respContent *SetPowerStateResponse
	func() {
		defer func() {
			// In case of a panic, serve a 500 error and then panic.
			if r := recover(); r != nil {
				s.serveError(ctx, resp, req, twirp.InternalError("Internal service panic"))
				panic(r)
			}
		}()
		respContent, err = s.SetPowerState(ctx, reqContent)
	}()

	if err != nil {
		s.serveError(ctx, resp, req, err)
		return
	}
	if respContent == nil {
		s.serveError(ctx, resp, req, twirp.InternalError("received a nil *SetPowerStateResponse and nil error while calling SetPowerState. nil responses are not supported"))
		return
	}

	ctx = s.hooks.ResponsePrepared(ctx)

	respBytes, err := proto1.Marshal(respContent)
	if err != nil {
		s.serveError(ctx, resp, req, twirp.InternalError("failed to marshal proto response"))
		return
	}

	ctx = setStatusCode(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)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

func (s *powerServer) serveGetFruInfo(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	switch req.Header.Get("Content-Type") {
	case "application/json":
		s.serveGetFruInfoJSON(ctx, resp, req)
	case "application/protobuf":
		s.serveGetFruInfoProtobuf(ctx, resp, req)
	default:
		twerr := twirp.NotFoundError(fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")))
		twerr = twerr.WithMeta("twirp_invalid_route", req.Method+" "+req.URL.Path+" - Content-Type:"+req.Header.Get("Content-Type"))
		s.serveError(ctx, resp, req, twerr)
	}
}

func (s *powerServer) serveGetFruInfoJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	var err error
	ctx = setMethodName(ctx, "GetFruInfo")
	ctx = s.hooks.RequestRouted(ctx)

	defer closebody(req.Body)
	reqContent := new(GetFruInfoRequest)
	if err = jsonpb.Unmarshal(req.Body, reqContent); err != nil {
		msg := "failed to parse request json: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}

	// Call service method
	var respContent *GetFruInfoResponse
	func() {
		defer func() {
			// In case of a panic, serve a 500 error and then panic.
			if r := recover(); r != nil {
				s.serveError(ctx, resp, req, twirp.InternalError("Internal service panic"))
				panic(r)
			}
		}()
		respContent, err = s.GetFruInfo(ctx, reqContent)
	}()

	if err != nil {
		s.serveError(ctx, resp, req, err)
		return
	}
	if respContent == nil {
		s.serveError(ctx, resp, req, twirp.InternalError("received a nil *GetFruInfoResponse and nil error while calling GetFruInfo. nil responses are not supported"))
		return
	}

	ctx = s.hooks.ResponsePrepared(ctx)

	var buf bytes.Buffer
	marshaler := &jsonpb.Marshaler{OrigName: true}
	if err = marshaler.Marshal(&buf, respContent); err != nil {
		s.serveError(ctx, resp, req, twirp.InternalError("failed to marshal json response"))
		return
	}

	ctx = setStatusCode(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)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

func (s *powerServer) serveGetFruInfoProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	var err error
	ctx = setMethodName(ctx, "GetFruInfo")
	ctx = s.hooks.RequestRouted(ctx)

	defer closebody(req.Body)
	buf, err := ioutil.ReadAll(req.Body)
	if err != nil {
		msg := "unable to read request body: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}
	reqContent := new(GetFruInfoRequest)
	if err = proto1.Unmarshal(buf, reqContent); err != nil {
		msg := "failed to parse request proto: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}

	// Call service method
	var respContent *GetFruInfoResponse
	func() {
		defer func() {
			// In case of a panic, serve a 500 error and then panic.
			if r := recover(); r != nil {
				s.serveError(ctx, resp, req, twirp.InternalError("Internal service panic"))
				panic(r)
			}
		}()
		respContent, err = s.GetFruInfo(ctx, reqContent)
	}()

	if err != nil {
		s.serveError(ctx, resp, req, err)
		return
	}
	if respContent == nil {
		s.serveError(ctx, resp, req, twirp.InternalError("received a nil *GetFruInfoResponse and nil error while calling GetFruInfo. nil responses are not supported"))
		return
	}

	ctx = s.hooks.ResponsePrepared(ctx)

	respBytes, err := proto1.Marshal(respContent)
	if err != nil {
		s.serveError(ctx, resp, req, twirp.InternalError("failed to marshal proto response"))
		return
	}

	ctx = setStatusCode(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)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

func (s *powerServer) serveSetBootDevice(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	switch req.Header.Get("Content-Type") {
	case "application/json":
		s.serveSetBootDeviceJSON(ctx, resp, req)
	case "application/protobuf":
		s.serveSetBootDeviceProtobuf(ctx, resp, req)
	default:
		twerr := twirp.NotFoundError(fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")))
		twerr = twerr.WithMeta("twirp_invalid_route", req.Method+" "+req.URL.Path+" - Content-Type:"+req.Header.Get("Content-Type"))
		s.serveError(ctx, resp, req, twerr)
	}
}

func (s *powerServer) serveSetBootDeviceJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	var err error
	ctx = setMethodName(ctx, "SetBootDevice")
	ctx = s.hooks.RequestRouted(ctx)

	defer closebody(req.Body)
	reqContent := new(SetBootDeviceRequest)
	if err = jsonpb.Unmarshal(req.Body, reqContent); err != nil {
		msg := "failed to parse request json: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}

	// Call service method
	var respContent *SetBootDeviceResponse
	func() {
		defer func() {
			// In case of a panic, serve a 500 error and then panic.
			if r := recover(); r != nil {
				s.serveError(ctx, resp, req, twirp.InternalError("Internal service panic"))
				panic(r)
			}
		}()
		respContent, err = s.SetBootDevice(ctx, reqContent)
	}()

	if err != nil {
		s.serveError(ctx, resp, req, err)
		return
	}
	if respContent == nil {
		s.serveError(ctx, resp, req, twirp.InternalError("received a nil *SetBootDeviceResponse and nil error while calling SetBootDevice. nil responses are not supported"))
		return
	}

	ctx = s.hooks.ResponsePrepared(ctx)

	var buf bytes.Buffer
	marshaler := &jsonpb.Marshaler{OrigName: true}
	if err = marshaler.Marshal(&buf, respContent); err != nil {
		s.serveError(ctx, resp, req, twirp.InternalError("failed to marshal json response"))
		return
	}

	ctx = setStatusCode(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)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

func (s *powerServer) serveSetBootDeviceProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
	var err error
	ctx = setMethodName(ctx, "SetBootDevice")
	ctx = s.hooks.RequestRouted(ctx)

	defer closebody(req.Body)
	buf, err := ioutil.ReadAll(req.Body)
	if err != nil {
		msg := "unable to read request body: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}
	reqContent := new(SetBootDeviceRequest)
	if err = proto1.Unmarshal(buf, reqContent); err != nil {
		msg := "failed to parse request proto: " + err.Error()
		s.serveError(ctx, resp, req, twirp.InternalError(msg))
		return
	}

	// Call service method
	var respContent *SetBootDeviceResponse
	func() {
		defer func() {
			// In case of a panic, serve a 500 error and then panic.
			if r := recover(); r != nil {
				s.serveError(ctx, resp, req, twirp.InternalError("Internal service panic"))
				panic(r)
			}
		}()
		respContent, err = s.SetBootDevice(ctx, reqContent)
	}()

	if err != nil {
		s.serveError(ctx, resp, req, err)
		return
	}
	if respContent == nil {
		s.serveError(ctx, resp, req, twirp.InternalError("received a nil *SetBootDeviceResponse and nil error while calling SetBootDevice. nil responses are not supported"))
		return
	}

	ctx = s.hooks.ResponsePrepared(ctx)

	respBytes, err := proto1.Marshal(respContent)
	if err != nil {
		s.serveError(ctx, resp, req, twirp.InternalError("failed to marshal proto response"))
		return
	}

	ctx = setStatusCode(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)
	}
	ctx = s.hooks.ResponseSent(ctx)
}

// =====
// Utils
// =====

// A ContextSource establishes the base context for a Server.
type ContextSource func(http.ResponseWriter, *http.Request) context.Context

var BackgroundContextSource ContextSource = func(http.ResponseWriter, *http.Request) context.Context {
	return context.Background()
}

// 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
	}
}

// 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()
}

// setMethodName, setServerName, and setStatusCode are functions to
// expose internal state through contexts. The context keys hardcoded
// in here are not to be used on their own. Twirp provides accessor
// functions which will retrieve these values out and give them the
// correct type for you.
func setMethodName(ctx context.Context, name string) context.Context {
	return context.WithValue(ctx, "__tw_method_name", name)
}
func setServerName(ctx context.Context, name string) context.Context {
	return context.WithValue(ctx, "__tw_service_name", name)
}
func setStatusCode(ctx context.Context, code int) context.Context {
	return context.WithValue(ctx, "__tw_status_code", strconv.Itoa(code))
}

type privateContextKey int

var versionKey = new(privateContextKey)

// setVersionFromPath adds "v1", "v2" or "v3" to the context depending on the path.
func setVersionFromPath(ctx context.Context, path string) context.Context {
	var version string
	if strings.HasPrefix(path, "/v1/") {
		version = "v1"
	} else if strings.HasPrefix(path, "/v2/") {
		version = "v2"
	} else {
		version = "v3"
	}
	return context.WithValue(ctx, versionKey, version)
}

// getVersion returns the version number ("v1", "v2", "v3") or empty string if unset.
func getVersion(ctx context.Context) string {
	v, _ := ctx.Value(versionKey).(string)
	return v
}

// 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 := ctx.Value("__tw_request_header").(http.Header)
	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", "v3.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
}

// unmarshalErrorFromJSONResponse returns a twirp.Error from JSON data.
// If de-serialization fails, it returns a descriptive Internal error instead
func unmarshalErrorFromJSONResponse(body io.Reader) twirp.Error {
	data, err := ioutil.ReadAll(body)
	if err != nil {
		msg := "failed to read server error response body: " + err.Error()
		return twirp.InternalError(msg)
	}
	var tj twerrJSON
	err = json.Unmarshal(data, &tj)
	if err != nil {
		msg := "failed to unmarshal server error response: " + err.Error()
		return twirp.InternalError(msg)
	}
	code := twirp.ErrorCode(tj.Code)
	if !twirp.IsValidErrorCode(code) {
		msg := "invalid type returned from server error response: " + tj.Code
		return twirp.InternalError(msg)
	}

	twerr := twirp.NewError(code, tj.Msg)
	for k, v := range tj.Meta {
		twerr = twerr.WithMeta(k, v)
	}
	return twerr
}

// clientError adds consistency to errors generated in the client
func clientError(desc string, err error) twirp.Error {
	msg := desc + ": " + err.Error()
	return twirp.InternalError(msg)
}
