package httpapi import ( "context" "encoding/json" "errors" "io" "net/http" "git.5iot.com/iotlcm-public/iotlcm-sms/internal/sms" ) const maxRequestBody = 1 << 20 type Sender interface { Send(ctx context.Context, config sms.Config, message sms.Message) (sms.Result, error) } type SendRequest struct { Config sms.Config `json:"config"` Params sms.Message `json:"params"` } type handler struct { sender Sender } func NewHandler(sender Sender) http.Handler { h := &handler{sender: sender} mux := http.NewServeMux() mux.HandleFunc("GET /healthz", h.health) mux.HandleFunc("POST /api/v1/sms/send", h.send) return mux } func (h *handler) health(w http.ResponseWriter, _ *http.Request) { writeJSON(w, http.StatusOK, map[string]string{"status": "ok"}) } func (h *handler) send(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, maxRequestBody) decoder := json.NewDecoder(r.Body) decoder.DisallowUnknownFields() var request SendRequest if err := decoder.Decode(&request); err != nil { writeJSON(w, http.StatusBadRequest, sms.Result{Code: 400, Message: "请求 JSON 无效: " + err.Error()}) return } if err := decoder.Decode(&struct{}{}); !errors.Is(err, io.EOF) { writeJSON(w, http.StatusBadRequest, sms.Result{Code: 400, Message: "请求体只能包含一个 JSON 对象"}) return } result, err := h.sender.Send(r.Context(), request.Config, request.Params) if err != nil { status := http.StatusBadGateway if errors.Is(err, sms.ErrInvalidRequest) || errors.Is(err, sms.ErrProviderNotFound) || errors.Is(err, sms.ErrSceneNotConfigured) { status = http.StatusBadRequest } writeJSON(w, status, result) return } writeJSON(w, http.StatusOK, result) } func writeJSON(w http.ResponseWriter, status int, value any) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(value) }