github.com/storacha/go-ucanto@v0.7.2/transport/car/codec.go (about)

     1  package car
     2  
     3  import (
     4  	"net/http"
     5  	"strings"
     6  
     7  	"github.com/storacha/go-ucanto/core/message"
     8  	"github.com/storacha/go-ucanto/transport"
     9  	"github.com/storacha/go-ucanto/transport/car/request"
    10  	"github.com/storacha/go-ucanto/transport/car/response"
    11  	thttp "github.com/storacha/go-ucanto/transport/http"
    12  )
    13  
    14  type carOutbound struct{}
    15  
    16  func (oc *carOutbound) Encode(msg message.AgentMessage) (transport.HTTPRequest, error) {
    17  	return request.Encode(msg)
    18  }
    19  
    20  func (oc *carOutbound) Decode(res transport.HTTPResponse) (message.AgentMessage, error) {
    21  	return response.Decode(res)
    22  }
    23  
    24  var _ transport.OutboundCodec = (*carOutbound)(nil)
    25  
    26  func NewOutboundCodec() transport.OutboundCodec {
    27  	return &carOutbound{}
    28  }
    29  
    30  type carInboundAcceptCodec struct{}
    31  
    32  func (cic *carInboundAcceptCodec) Encoder() transport.ResponseEncoder {
    33  	return cic
    34  }
    35  
    36  func (cic *carInboundAcceptCodec) Decoder() transport.RequestDecoder {
    37  	return cic
    38  }
    39  
    40  func (cic *carInboundAcceptCodec) Encode(msg message.AgentMessage) (transport.HTTPResponse, error) {
    41  	return response.Encode(msg)
    42  }
    43  
    44  func (cic *carInboundAcceptCodec) Decode(req transport.HTTPRequest) (message.AgentMessage, error) {
    45  	return request.Decode(req)
    46  }
    47  
    48  type carInbound struct {
    49  	codec transport.InboundAcceptCodec
    50  }
    51  
    52  func (ic *carInbound) Accept(req transport.HTTPRequest) (transport.InboundAcceptCodec, transport.HTTPError) {
    53  	// TODO: select a decoder - we only support 1 ATM
    54  	contentType := req.Headers().Get("Content-Type")
    55  	if contentType != request.ContentType {
    56  		headers := http.Header{}
    57  		headers.Set("Accept", contentType)
    58  		return nil, thttp.NewHTTPError(
    59  			"The server cannot process the request because the payload format is not supported. Please check the content-type header and try again with a supported media type.",
    60  			http.StatusUnsupportedMediaType,
    61  			headers,
    62  		)
    63  	}
    64  
    65  	// TODO: select an encoder by desired preference (q=) - we only support 1 ATM
    66  	accept := req.Headers().Get("Accept")
    67  	if accept == "" {
    68  		accept = "*/*"
    69  	}
    70  	if accept != "*/*" && !strings.Contains(accept, contentType) {
    71  		headers := http.Header{}
    72  		headers.Set("Accept", contentType)
    73  		return nil, thttp.NewHTTPError(
    74  			"The requested resource cannot be served in the requested content type. Please specify a supported content type using the Accept header.",
    75  			http.StatusNotAcceptable,
    76  			headers,
    77  		)
    78  	}
    79  
    80  	return ic.codec, nil
    81  }
    82  
    83  var _ transport.InboundCodec = (*carInbound)(nil)
    84  
    85  func NewInboundCodec() transport.InboundCodec {
    86  	return &carInbound{codec: &carInboundAcceptCodec{}}
    87  }