package response import ( "bytes" "encoding/json" "log" "net/http" "strings" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) type bodyWriter struct { http.ResponseWriter status int buf bytes.Buffer } type responseData struct { Code int32 `json:"code"` Data any `json:"data"` Msg string `json:"msg"` } func (w *bodyWriter) WriteHeader(statusCode int) { w.status = statusCode } func (w *bodyWriter) Write(b []byte) (int, error) { return w.buf.Write(b) } func Wrap(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { bw := &bodyWriter{ResponseWriter: w, status: http.StatusOK} next(bw, r) log.Printf("raw json: %s", bw.status) ctrl := BaseController{} if bw.status != http.StatusOK { ctrl.Error(w, mapHTTPError(bw.status, bw.buf.String())) return } raw := bytes.TrimSpace(bw.buf.Bytes()) var data responseData if len(raw) > 0 { if err := json.Unmarshal(raw, &data); err != nil { ctrl.Fail(w) return } } ctrl.OutPut(w, data.Code, data.Data, data.Msg) } } func mapHTTPError(httpStatus int, body string) Error { msg := strings.TrimSpace(body) msg = strings.TrimPrefix(msg, "rpc error: ") if i := strings.Index(msg, "desc = "); i >= 0 { msg = strings.TrimSpace(msg[i+len("desc = "):]) } if msg == "" { msg = Fail.GetMsg() } switch httpStatus { case http.StatusBadRequest: return Define(ErrorMissingParams, msg) case http.StatusUnauthorized: return Define(ErrorNoLogin, msg) case http.StatusForbidden: return Define(ErrorAuthority, msg) case http.StatusNotFound: return Define(ErrorDataNotExist, msg) default: return Define(Fail, msg) } } func FromGRPC(err error) Error { if err == nil { return OK } st, ok := status.FromError(err) if !ok { return Define(Fail, err.Error()) } msg := st.Message() if msg == "" { msg = st.Code().String() } switch st.Code() { case codes.InvalidArgument: return Define(ErrorMissingParams, msg) case codes.Unauthenticated: return Define(ErrorNoLogin, msg) case codes.PermissionDenied: return Define(ErrorAuthority, msg) case codes.NotFound: return Define(ErrorDataNotExist, msg) case codes.AlreadyExists: return Define(ErrorDataIsExist, msg) default: return Define(Fail, msg) } }