package httpx import ( "code.tczkiot.com/wlw/ai-agent/contract" "code.tczkiot.com/wlw/ai-agent/internal/pkg/errorsx" "code.tczkiot.com/wlw/ai-agent/internal/pkg/i18nx" "net/http" "sync" "github.com/gin-gonic/gin" "github.com/mlogclub/simple/sqls" "github.com/mlogclub/simple/web" ) type cursorData struct { results any cursor string hasMore bool } type pageData struct { results any paging *sqls.Paging } type cursorResult struct { Results any `json:"results"` Cursor string `json:"cursor"` HasMore bool `json:"has_more"` } type pageResult struct { Page *sqls.Paging `json:"page"` Results any `json:"results"` } type localizedError interface { Message(locale string) string } var ( responseWriterMu sync.RWMutex responseWriter contract.ResponseWriter ) func SetResponseWriter(writer contract.ResponseWriter) { responseWriterMu.Lock() defer responseWriterMu.Unlock() responseWriter = writer } func CursorData(results any, cursor string, hasMore bool) any { return cursorData{results: results, cursor: cursor, hasMore: hasMore} } func PageData(results any, paging *sqls.Paging) any { return pageData{results: results, paging: paging} } func WriteJSON(ctx *gin.Context, result any) { writeJSON(ctx, http.StatusOK, result) } func WriteHttpStatusJSON(ctx *gin.Context, statusCode int, result any) { writeJSON(ctx, statusCode, result) } func AbortJSON(ctx *gin.Context, statusCode int, result any) { writeJSON(ctx, statusCode, result) ctx.Abort() } func writeJSON(ctx *gin.Context, statusCode int, result any) { payload := buildJSONResult(ctx, result) responseWriterMu.RLock() writer := responseWriter responseWriterMu.RUnlock() if writer == nil { ctx.JSON(statusCode, payload) return } if err := writer(ctx.Writer, ctx.Request, contract.Response{ StatusCode: statusCode, ErrorCode: payload.ErrorCode, Message: payload.Message, Data: payload.Data, Success: payload.Success, }); err != nil { _ = ctx.Error(err) } } func buildJSONResult(ctx *gin.Context, result any) *web.JsonResult { switch value := result.(type) { case nil: return web.JsonSuccess() case *web.JsonResult: return value case web.JsonResult: return &value case *web.CodeError: return web.JsonError(value) case web.CodeError: return web.JsonError(&value) case *errorsx.I18nError: return value.JsonResult(i18nx.Locale(ctx)) case errorsx.I18nError: return value.JsonResult(i18nx.Locale(ctx)) case localizedError: return web.JsonErrorMsg(value.Message(i18nx.Locale(ctx))) case error: return web.JsonError(value) case cursorData: results := value.results if results == nil { results = []any{} } return web.JsonData(&cursorResult{ Results: results, Cursor: value.cursor, HasMore: value.hasMore, }) case pageData: results := value.results if results == nil { results = []any{} } return web.JsonData(&pageResult{ Page: value.paging, Results: results, }) case web.RspBuilder: return value.JsonResult() case *web.RspBuilder: return value.JsonResult() default: return web.JsonData(result) } }