spark-server/internal/pkg/reply/reply.go
2026-09-18 14:50:41 +08:00

107 lines
2.4 KiB
Go

package reply
import (
"context"
"encoding/json"
"spark-server/internal/pkg/errs"
"spark-server/internal/pkg/i18n"
"spark-server/internal/pkg/reqctx"
)
// Envelope is the unified HTTP and TCP response body: {"code":"","msg":"","request_id":"","data":{}}.
type Envelope struct {
Code string `json:"code"`
Msg string `json:"msg"`
RequestID string `json:"request_id"`
Data json.RawMessage `json:"data"`
}
func Stamp(ctx context.Context, env Envelope) Envelope {
return StampID(env, reqctx.RequestID(ctx))
}
func StampID(env Envelope, requestID string) Envelope {
env.RequestID = requestID
return env
}
func OK(data any) Envelope {
return Envelope{Code: errs.OK.Code, Msg: errs.OK.Msg, Data: marshalData(data)}
}
func Fail(code, msg string) Envelope {
if code == "" {
code = errs.ErrInner.Code
}
if msg == "" {
msg = errs.ErrInner.Msg
}
return Envelope{Code: code, Msg: msg, Data: json.RawMessage("{}")}
}
func FailData(code, msg string, data any) Envelope {
env := Fail(code, msg)
env.Data = marshalData(data)
return env
}
func FromError(err error) Envelope {
return FromErrorLang(i18n.Default, err)
}
func FromContext(ctx context.Context, err error) Envelope {
return Stamp(ctx, FromErrorLang(reqctx.Lang(ctx), err))
}
func FromErrorLang(lang i18n.Lang, err error) Envelope {
if err == nil {
return OK(nil)
}
if app, ok := errs.AsAppError(err); ok {
return Fail(app.Code, publicMsg(lang, app))
}
return Fail(errs.ErrInner.Code, i18n.ErrorMsg(lang, errs.ErrInner.Code))
}
func publicMsg(lang i18n.Lang, app *errs.AppError) string {
if app.CustomMsg() {
return app.Msg
}
return i18n.ErrorMsg(lang, app.Code)
}
func Marshal(env Envelope) ([]byte, error) {
return json.Marshal(env)
}
func MustMarshal(env Envelope) []byte {
b, err := Marshal(env)
if err != nil {
b, _ = json.Marshal(Fail(errs.ErrInner.Code, errs.ErrInner.Msg))
}
return b
}
func Unmarshal(body []byte) (Envelope, error) {
var env Envelope
if err := json.Unmarshal(body, &env); err != nil {
return Envelope{}, errs.ErrInvalidFrame.WithInnerMsg(err.Error())
}
if len(env.Data) == 0 {
env.Data = json.RawMessage("{}")
}
return env, nil
}
func marshalData(data any) json.RawMessage {
if data == nil {
return json.RawMessage("{}")
}
b, err := json.Marshal(data)
if err != nil || len(b) == 0 || string(b) == "null" {
return json.RawMessage("{}")
}
return b
}