126 lines
3.5 KiB
Go
126 lines
3.5 KiB
Go
package router
|
|
|
|
import (
|
|
"encoding/json"
|
|
"encoding/xml"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"shared-sqs/app/interfaces"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
sqs "shared-sqs/app/gosqs"
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
// New returns a new router
|
|
func New() http.Handler {
|
|
r := mux.NewRouter()
|
|
|
|
r.HandleFunc("/", actionHandler).Methods("GET", "POST")
|
|
r.HandleFunc("/health", health).Methods("GET")
|
|
r.HandleFunc("/{account}", actionHandler).Methods("GET", "POST")
|
|
r.HandleFunc("/queue/{queueName}", actionHandler).Methods("GET", "POST")
|
|
r.HandleFunc("/{account}/{queueName}", actionHandler).Methods("GET", "POST")
|
|
|
|
return r
|
|
}
|
|
|
|
func encodeResponse(w http.ResponseWriter, req *http.Request, statusCode int, body interfaces.AbstractResponseBody) {
|
|
protocol := resolveProtocol(req)
|
|
switch protocol {
|
|
case AwsJsonProtocol:
|
|
w.Header().Set("x-amzn-RequestId", body.GetRequestId())
|
|
w.Header().Set("Content-Type", "application/x-amz-json-1.0")
|
|
w.WriteHeader(statusCode)
|
|
if body.GetResult() == nil {
|
|
return
|
|
}
|
|
err := json.NewEncoder(w).Encode(body.GetResult())
|
|
if err != nil {
|
|
log.Errorf("Response Encoding Error: %v\nResponse: %+v", err, body)
|
|
http.Error(w, "General Error", http.StatusInternalServerError)
|
|
}
|
|
case AwsQueryProtocol:
|
|
w.Header().Set("Content-Type", "application/xml")
|
|
w.WriteHeader(statusCode)
|
|
result, err := xml.Marshal(body)
|
|
if err != nil {
|
|
log.Errorf("Response Encoding Error: %v\nResponse: %+v", err, body)
|
|
http.Error(w, "General Error", http.StatusInternalServerError)
|
|
}
|
|
_, _ = w.Write(result)
|
|
}
|
|
}
|
|
|
|
// routingTableV1 содержит только SQS actions — SNS удалён
|
|
var routingTableV1 = map[string]func(r *http.Request) (int, interfaces.AbstractResponseBody){
|
|
"CreateQueue": sqs.CreateQueueV1,
|
|
"ListQueues": sqs.ListQueuesV1,
|
|
"GetQueueAttributes": sqs.GetQueueAttributesV1,
|
|
"SetQueueAttributes": sqs.SetQueueAttributesV1,
|
|
"SendMessage": sqs.SendMessageV1,
|
|
"ReceiveMessage": sqs.ReceiveMessageV1,
|
|
"ChangeMessageVisibility": sqs.ChangeMessageVisibilityV1,
|
|
"DeleteMessage": sqs.DeleteMessageV1,
|
|
"GetQueueUrl": sqs.GetQueueUrlV1,
|
|
"PurgeQueue": sqs.PurgeQueueV1,
|
|
"DeleteQueue": sqs.DeleteQueueV1,
|
|
"SendMessageBatch": sqs.SendMessageBatchV1,
|
|
"DeleteMessageBatch": sqs.DeleteMessageBatchV1,
|
|
}
|
|
|
|
func health(w http.ResponseWriter, req *http.Request) {
|
|
w.WriteHeader(200)
|
|
fmt.Fprint(w, "OK")
|
|
}
|
|
|
|
func actionHandler(w http.ResponseWriter, req *http.Request) {
|
|
action := extractAction(req)
|
|
log.WithFields(
|
|
log.Fields{
|
|
"action": action,
|
|
"url": req.URL,
|
|
}).Debug("Handling URL request")
|
|
jsonFn, ok := routingTableV1[action]
|
|
if ok {
|
|
statusCode, responseBody := jsonFn(req)
|
|
encodeResponse(w, req, statusCode, responseBody)
|
|
return
|
|
}
|
|
log.Warnf("Bad Request - Action: %s", action)
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
io.WriteString(w, "Bad Request")
|
|
}
|
|
|
|
type AwsProtocol int
|
|
|
|
const (
|
|
AwsJsonProtocol AwsProtocol = iota
|
|
AwsQueryProtocol AwsProtocol = iota
|
|
)
|
|
|
|
// extractAction — извлекает Action из запроса (Query Protocol или JSON Protocol)
|
|
func extractAction(req *http.Request) string {
|
|
protocol := resolveProtocol(req)
|
|
switch protocol {
|
|
case AwsJsonProtocol:
|
|
action := req.Header.Get("X-Amz-Target")
|
|
return strings.Split(action, ".")[1]
|
|
case AwsQueryProtocol:
|
|
return req.FormValue("Action")
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// resolveProtocol — определяет протокол по Content-Type
|
|
func resolveProtocol(req *http.Request) AwsProtocol {
|
|
if req.Header.Get("Content-Type") == "application/x-amz-json-1.0" {
|
|
return AwsJsonProtocol
|
|
}
|
|
return AwsQueryProtocol
|
|
}
|