mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
apply/make Travis's json-format branch prototype to work with latest restructured master; added StatusCode to JSONOutput server-function contract
This commit is contained in:
committed by
Denis Makogon
parent
b8d7154747
commit
b6b9b55ca9
@@ -36,6 +36,7 @@ type Protocol string
|
||||
const (
|
||||
Default Protocol = models.FormatDefault
|
||||
HTTP Protocol = models.FormatHTTP
|
||||
JSON Protocol = models.FormatJSON
|
||||
Empty Protocol = ""
|
||||
)
|
||||
|
||||
@@ -45,6 +46,8 @@ func (p *Protocol) UnmarshalJSON(b []byte) error {
|
||||
*p = Default
|
||||
case HTTP:
|
||||
*p = HTTP
|
||||
case JSON:
|
||||
*p = JSON
|
||||
default:
|
||||
return errInvalidProtocol
|
||||
}
|
||||
@@ -57,6 +60,8 @@ func (p Protocol) MarshalJSON() ([]byte, error) {
|
||||
return []byte(Default), nil
|
||||
case HTTP:
|
||||
return []byte(HTTP), nil
|
||||
case JSON:
|
||||
return []byte(JSON), nil
|
||||
}
|
||||
return nil, errInvalidProtocol
|
||||
}
|
||||
@@ -67,6 +72,8 @@ func New(p Protocol, in io.Writer, out io.Reader) ContainerIO {
|
||||
switch p {
|
||||
case HTTP:
|
||||
return &HTTPProtocol{in, out}
|
||||
case JSON:
|
||||
return &JSONProtocol{in, out}
|
||||
case Default, Empty:
|
||||
return &DefaultProtocol{}
|
||||
}
|
||||
|
||||
98
api/agent/protocol/json.go
Normal file
98
api/agent/protocol/json.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// JSONInput is what's sent into the function
|
||||
// All HTTP request headers should be set in env
|
||||
type JSONInput struct {
|
||||
RequestURL string `json:"request_url"`
|
||||
CallID string `json:"call_id"`
|
||||
Method string `json:"method"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
// JSONOutput function must return this format
|
||||
// StatusCode value must be a HTTP status code
|
||||
type JSONOutput struct {
|
||||
StatusCode int `json:"status"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
// JSONProtocol converts stdin/stdout streams from HTTP into JSON format.
|
||||
type JSONProtocol struct {
|
||||
in io.Writer
|
||||
out io.Reader
|
||||
}
|
||||
|
||||
func (p *JSONProtocol) IsStreamable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *JSONProtocol) Dispatch(w io.Writer, req *http.Request) error {
|
||||
reqURL := req.Header.Get("REQUEST_URL")
|
||||
method := req.Header.Get("METHOD")
|
||||
callID := req.Header.Get("CALL_ID")
|
||||
|
||||
// TODO content-length or chunked encoding
|
||||
var body bytes.Buffer
|
||||
if req.Body != nil {
|
||||
var dest io.Writer = &body
|
||||
|
||||
// TODO copy w/ ctx and check err
|
||||
io.Copy(dest, req.Body)
|
||||
}
|
||||
|
||||
// convert to JSON func format
|
||||
jin := &JSONInput{
|
||||
RequestURL: reqURL,
|
||||
Method: method,
|
||||
CallID: callID,
|
||||
Body: body.String(),
|
||||
}
|
||||
b, err := json.Marshal(jin)
|
||||
if err != nil {
|
||||
// this shouldn't happen
|
||||
return fmt.Errorf("error marshalling JSONInput: %v", err)
|
||||
}
|
||||
h.in.Write(b)
|
||||
|
||||
// TODO: put max size on how big the response can be so we don't blow up
|
||||
jout := &JSONOutput{}
|
||||
dec := json.NewDecoder(h.out)
|
||||
if err := dec.Decode(jout); err != nil {
|
||||
// TODO: how do we get an error back to the client??
|
||||
return fmt.Errorf("error unmarshalling JSONOutput: %v", err)
|
||||
}
|
||||
|
||||
// res := &http.Response{}
|
||||
// res.Body = strings.NewReader(jout.Body)
|
||||
// TODO: shouldn't we pass back the full response object or something so we can set some things on it here?
|
||||
// For instance, user could set response content type or what have you.
|
||||
//io.Copy(cfg.Stdout, strings.NewReader(jout.Body))
|
||||
|
||||
if rw, ok := w.(http.ResponseWriter); ok {
|
||||
b, err = json.Marshal(jout.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error unmarshalling JSONOutput.Body: %v", err)
|
||||
}
|
||||
rw.WriteHeader(jout.StatusCode)
|
||||
rw.Write(b) // TODO timeout
|
||||
} else {
|
||||
// logs can just copy the full thing in there, headers and all.
|
||||
b, err = json.Marshal(jout)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error unmarshalling JSONOutput: %v", err)
|
||||
}
|
||||
|
||||
w.Write(b) // TODO timeout
|
||||
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user