go/grpshuffle_client/lib/http.go (201 lines of code) (raw):
package grpshuffle_client
import (
"encoding/json"
"fmt"
"github.com/korosuke613/grpshuffle/go/grpshuffle"
"google.golang.org/grpc/health/grpc_health_v1"
"log"
"net/http"
"strconv"
"strings"
"time"
)
// HttpResponse is response http server for grpshuffle-client
type HttpResponse struct {
Status int `json:"status"`
Msg string `json:"msg"`
Result interface{} `json:"result"`
}
type ResponseFormat string
const (
FormatJson = "json"
FormatJsonPretty = "json-pretty"
FormatReadable = "readable"
)
func (r *ResponseFormat) checkType() error {
switch *r {
case FormatJson:
case FormatJsonPretty:
case FormatReadable:
default:
return fmt.Errorf("fmt parameter allows %v, %v and %v", FormatJson, FormatJsonPretty, FormatReadable)
}
return nil
}
// HttpServe is serve http server for grpshuffle-client
func HttpServe(port int) {
addr := fmt.Sprintf(":%v", port)
http.HandleFunc("/shuffle", shuffleHandler)
http.HandleFunc("/", healthHandler)
log.Printf("Launch grpshuffle-client http server %v...", port)
log.Fatal(http.ListenAndServe(addr, logger(http.DefaultServeMux)))
}
func shuffleHandler(writer http.ResponseWriter, request *http.Request) {
conn, err := Connect(Host, Port, NoTLS)
if err != nil {
newErrorResponse(writer, 500, "Internal Server Error")
return
}
defer CloseConnect(conn)
format := ResponseFormat(request.FormValue("fmt"))
if format != "" {
err = format.checkType()
if err != nil {
newErrorResponse(writer, 400, err.Error())
return
}
}
rawDivide := request.FormValue("divide")
if rawDivide == "" {
newErrorResponse(writer, 400, "divide parameter is required")
return
}
divide, err := strconv.Atoi(rawDivide)
if err != nil {
newErrorResponse(writer, 400, "divide parameter allows numbers")
return
}
groupName := request.FormValue("groupName")
if groupName == "" {
groupName = "Group"
}
rawTargets := request.FormValue("targets")
if rawTargets == "" {
newErrorResponse(writer, 400, "targets parameter is required")
return
}
targets := strings.Split(rawTargets, ",")
cc := grpshuffle.NewComputeClient(conn)
result, err := Shuffle(&cc, uint64(divide), targets)
if err != nil {
newErrorResponse(writer, 504, "Gateway Timeout")
log.Print(err)
return
}
var res []byte
switch format {
case FormatJson:
{
res, err = json.Marshal(HttpResponse{
Status: 200,
Msg: "Ok",
Result: result,
})
if err != nil {
log.Print(err)
return
}
}
case FormatJsonPretty:
{
res, err = json.MarshalIndent(HttpResponse{
Status: 200,
Msg: "Ok",
Result: result,
}, "", " ")
if err != nil {
log.Print(err)
return
}
}
case FormatReadable:
{
var prettyResponse string
for i, combination := range result {
var targetsString string
for _, target := range combination.Targets {
if targetsString == "" {
targetsString = target
} else {
targetsString = fmt.Sprintf("%v, %v", targetsString, target)
}
}
groupNumber := i + 1 // It is for humans, so start at 1.
prettyResponse = fmt.Sprintf("%v%v %v: %v\n", prettyResponse, groupName, groupNumber, targetsString)
}
res = []byte(prettyResponse)
}
default:
{
res, err = json.Marshal(HttpResponse{
Status: 200,
Msg: "Ok",
Result: result,
})
if err != nil {
log.Print(err)
return
}
}
}
_, err = writer.Write(res)
if err != nil {
log.Print(err)
return
}
}
func healthHandler(writer http.ResponseWriter, _ *http.Request) {
conn, err := Connect(Host, Port, NoTLS)
if err != nil {
newErrorResponse(writer, 500, "Internal Server Error")
return
}
defer CloseConnect(conn)
hc := grpc_health_v1.NewHealthClient(conn)
result, err := HealthCheck(&hc)
if err != nil {
newErrorResponse(writer, 504, "Gateway Timeout")
log.Print(err)
return
}
res, err := json.Marshal(HttpResponse{
Status: 200,
Msg: "Ok",
Result: result,
})
if err != nil {
log.Print(err)
return
}
_, err = writer.Write(res)
if err != nil {
log.Print(err)
return
}
}
func newErrorResponse(writer http.ResponseWriter, statusCode int, msg string) {
writer.WriteHeader(statusCode)
res, err := json.Marshal(HttpResponse{
Status: statusCode,
Msg: msg,
Result: nil,
})
if err != nil {
log.Print(err)
return
}
_, err = writer.Write(res)
if err != nil {
log.Print(err)
return
}
}
func logger(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rAddr := r.RemoteAddr
method := r.Method
path := r.URL
fmt.Printf("%v remote: %s [%s] %s\n",
time.Now().Format("2006-01-02 15:04:05"),
rAddr, method, path)
h.ServeHTTP(w, r)
})
}