package support import ( "encoding/json" "fmt" "net/http" "os" "strings" "git.fsdpf.net/go/contracts" "git.fsdpf.net/go/req" "github.com/gorilla/websocket" "github.com/samber/lo" ) type RawResponse struct { raw []byte } type JsonResponse struct { raw []byte } type MsgResponse struct { code int msg string } type ErrResponse struct { *MsgResponse stack []byte } type FileResponse struct { disposition string name string } var wsUpgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, } func (this RawResponse) Get(path ...string) req.GlobalParams { return lo.Ternary(len(path) == 0, req.NewGlobalParam(string(this.raw), nil), req.NewGlobalParam(string(this.raw), nil).Get(strings.Join(path, "."))) } func (this RawResponse) Send(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Upgrade") != "" && strings.ToLower(r.Header.Get("Upgrade")) == "websocket" { c, _ := wsUpgrader.Upgrade(w, r, nil) c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, string(this.raw))) c.Close() } else { w.Write(this.raw) } } func (this JsonResponse) Get(path ...string) req.GlobalParams { return lo.Ternary(len(path) == 0, req.NewGlobalParam(string(this.raw), nil), req.NewGlobalParam(string(this.raw), nil).Get(strings.Join(path, "."))) } func (this JsonResponse) Send(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Upgrade") != "" && strings.ToLower(r.Header.Get("Upgrade")) == "websocket" { c, _ := wsUpgrader.Upgrade(w, r, nil) c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, string(this.raw))) c.Close() } else { w.Header().Set("Content-Type", "application/json") w.Write(this.raw) } } func (this MsgResponse) Get(path ...string) req.GlobalParams { if resp, err := json.Marshal(map[string]any{ "code": this.code, "msg": this.msg, }); err == nil { return lo.Ternary(len(path) == 0, req.NewGlobalParam(string(resp), nil), req.NewGlobalParam(string(resp), nil).Get(strings.Join(path, "."))) } return nil } func (this MsgResponse) Send(w http.ResponseWriter, r *http.Request) { if resp, err := json.Marshal(this.Get().Value()); err == nil { (&JsonResponse{raw: resp}).Send(w, r) } else { HttpResponse(err).Send(w, r) } } func (this ErrResponse) Get(path ...string) req.GlobalParams { if resp, err := json.Marshal(map[string]any{ "code": this.code, "msg": this.msg, "error": string(this.stack), }); err == nil { return lo.Ternary(len(path) == 0, req.NewGlobalParam(string(resp), nil), req.NewGlobalParam(string(resp), nil).Get(strings.Join(path, "."))) } return nil } func (this ErrResponse) Send(w http.ResponseWriter, r *http.Request) { if resp, err := json.Marshal(this.Get().Value()); err == nil { (&JsonResponse{raw: resp}).Send(w, r) } else { HttpResponse(err).Send(w, r) } } func (this FileResponse) Get(path ...string) req.GlobalParams { if resp, err := json.Marshal(map[string]any{ "name": this.name, "disposition": this.disposition, }); err == nil { return lo.Ternary(len(path) == 0, req.NewGlobalParam(string(resp), nil), req.NewGlobalParam(string(resp), nil).Get(strings.Join(path, "."))) } return nil } func (this FileResponse) Send(w http.ResponseWriter, r *http.Request) { if this.Get("disposition").String() != "" { w.Header().Set("Content-Disposition", `attachment; filename="`+this.Get("disposition").String()+`"`) } if _, err := os.Stat(this.Get("name").String()); err != nil && os.IsNotExist(err) { w.WriteHeader(http.StatusNotFound) } else { http.ServeFile(w, r, this.Get("name").String()) } } func NewRawResponse(b []byte) req.HttpResponse { return &RawResponse{raw: b} } func NewJsonResponse(b []byte) req.HttpResponse { return &JsonResponse{raw: b} } func NewFileResponse(name string, disposition string) req.HttpResponse { return &FileResponse{name: name, disposition: disposition} } func NewMsgResponse(msg string, code int) req.HttpResponse { return &MsgResponse{msg: msg, code: code} } func NewErrResponse(err *contracts.Err) req.HttpResponse { return NewJsonResponse([]byte(fmt.Sprintf(`{"code": %d, "msg": %q}`, err.Code, err.Error()))) } func HttpResponse(data any) req.HttpResponse { var err error // fmt.Printf("%#v \n", data) switch v := data.(type) { case req.HttpResponse: return v case contracts.Errno: return NewMsgResponse(v.Error(), v.Code) case *contracts.Errno: return NewMsgResponse(v.Error(), v.Code) case contracts.Err: return NewErrResponse(&v) case *contracts.Err: return NewErrResponse(v) case error: err = v case []byte: if b, e := json.Marshal(map[string]any{ "code": contracts.OK.Code, "msg": contracts.OK.Msg, "data": json.RawMessage(v), }); e == nil { return &JsonResponse{raw: b} } else { err = e } default: if b, e := json.Marshal(map[string]any{ "code": contracts.OK.Code, "msg": contracts.OK.Msg, "data": v, }); e == nil { return &JsonResponse{raw: b} } else { err = e } } return NewErrResponse(contracts.NewErr(contracts.InternalServerError, err)) }