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":"","data":{}}. type Envelope struct { Code string `json:"code"` Msg string `json:"msg"` Data json.RawMessage `json:"data"` } 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 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 }