diff --git a/android/.idea/deploymentTargetSelector.xml b/android/.idea/deploymentTargetSelector.xml
new file mode 100644
index 0000000..b268ef3
--- /dev/null
+++ b/android/.idea/deploymentTargetSelector.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/.idea/other.xml b/android/.idea/other.xml
new file mode 100644
index 0000000..0d3a1fb
--- /dev/null
+++ b/android/.idea/other.xml
@@ -0,0 +1,263 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scnserver/TODO.md b/scnserver/TODO.md
index 82ca82a..31eef31 100644
--- a/scnserver/TODO.md
+++ b/scnserver/TODO.md
@@ -68,8 +68,6 @@
- cli app (?)
- - Use "github.com/glebarez/go-sqlite" instead of mattn3 (see ai-sig alarmserver)
-
#### FUTURE
- Remove compat, especially do not create compat id for every new message...
\ No newline at end of file
diff --git a/scnserver/api/ginext/cors.go b/scnserver/api/ginext/cors.go
deleted file mode 100644
index a4f638f..0000000
--- a/scnserver/api/ginext/cors.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package ginext
-
-import (
- "github.com/gin-gonic/gin"
- "net/http"
-)
-
-func CorsMiddleware() gin.HandlerFunc {
- return func(c *gin.Context) {
- c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
- c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
- c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
- c.Writer.Header().Set("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, PATCH, DELETE")
-
- if c.Request.Method == "OPTIONS" {
- c.AbortWithStatus(http.StatusOK)
- } else {
- c.Next()
- }
- }
-}
diff --git a/scnserver/api/ginext/gin.go b/scnserver/api/ginext/gin.go
deleted file mode 100644
index c41045d..0000000
--- a/scnserver/api/ginext/gin.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package ginext
-
-import (
- scn "blackforestbytes.com/simplecloudnotifier"
- "github.com/gin-gonic/gin"
-)
-
-var SuppressGinLogs = false
-
-func NewEngine(cfg scn.Config) *gin.Engine {
- engine := gin.New()
-
- engine.RedirectFixedPath = false
- engine.RedirectTrailingSlash = false
-
- if cfg.Cors {
- engine.Use(CorsMiddleware())
- }
-
- if cfg.GinDebug {
- ginlogger := gin.Logger()
- engine.Use(func(context *gin.Context) {
- if SuppressGinLogs {
- return
- }
- ginlogger(context)
- })
- }
-
- return engine
-}
diff --git a/scnserver/api/ginext/handler.go b/scnserver/api/ginext/handler.go
deleted file mode 100644
index 44662e6..0000000
--- a/scnserver/api/ginext/handler.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package ginext
-
-import (
- "github.com/gin-gonic/gin"
- "net/http"
-)
-
-func RedirectFound(newuri string) gin.HandlerFunc {
- return func(g *gin.Context) {
- g.Redirect(http.StatusFound, newuri)
- }
-}
-
-func RedirectTemporary(newuri string) gin.HandlerFunc {
- return func(g *gin.Context) {
- g.Redirect(http.StatusTemporaryRedirect, newuri)
- }
-}
-
-func RedirectPermanent(newuri string) gin.HandlerFunc {
- return func(g *gin.Context) {
- g.Redirect(http.StatusPermanentRedirect, newuri)
- }
-}
diff --git a/scnserver/api/ginresp/resp.go b/scnserver/api/ginresp/resp.go
index 0d40338..bb1b895 100644
--- a/scnserver/api/ginresp/resp.go
+++ b/scnserver/api/ginresp/resp.go
@@ -7,114 +7,43 @@ import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
json "gogs.mikescher.com/BlackForestBytes/goext/gojson"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"runtime/debug"
"strings"
)
-type HTTPResponse interface {
- Write(g *gin.Context)
- Statuscode() int
- BodyString() *string
- ContentType() string
+type cookieval struct {
+ name string
+ value string
+ maxAge int
+ path string
+ domain string
+ secure bool
+ httpOnly bool
}
-type jsonHTTPResponse struct {
- statusCode int
- data any
-}
-
-func (j jsonHTTPResponse) Write(g *gin.Context) {
- g.Render(j.statusCode, json.GoJsonRender{Data: j.data, NilSafeSlices: true, NilSafeMaps: true})
-}
-
-func (j jsonHTTPResponse) Statuscode() int {
- return j.statusCode
-}
-
-func (j jsonHTTPResponse) BodyString() *string {
- v, err := json.Marshal(j.data)
- if err != nil {
- return nil
- }
- return langext.Ptr(string(v))
-}
-
-func (j jsonHTTPResponse) ContentType() string {
- return "application/json"
-}
-
-type emptyHTTPResponse struct {
- statusCode int
-}
-
-func (j emptyHTTPResponse) Write(g *gin.Context) {
- g.Status(j.statusCode)
-}
-
-func (j emptyHTTPResponse) Statuscode() int {
- return j.statusCode
-}
-
-func (j emptyHTTPResponse) BodyString() *string {
- return nil
-}
-
-func (j emptyHTTPResponse) ContentType() string {
- return ""
-}
-
-type textHTTPResponse struct {
- statusCode int
- data string
-}
-
-func (j textHTTPResponse) Write(g *gin.Context) {
- g.String(j.statusCode, "%s", j.data)
-}
-
-func (j textHTTPResponse) Statuscode() int {
- return j.statusCode
-}
-
-func (j textHTTPResponse) BodyString() *string {
- return langext.Ptr(j.data)
-}
-
-func (j textHTTPResponse) ContentType() string {
- return "text/plain"
-}
-
-type dataHTTPResponse struct {
- statusCode int
- data []byte
- contentType string
-}
-
-func (j dataHTTPResponse) Write(g *gin.Context) {
- g.Data(j.statusCode, j.contentType, j.data)
-}
-
-func (j dataHTTPResponse) Statuscode() int {
- return j.statusCode
-}
-
-func (j dataHTTPResponse) BodyString() *string {
- return langext.Ptr(string(j.data))
-}
-
-func (j dataHTTPResponse) ContentType() string {
- return j.contentType
+type headerval struct {
+ Key string
+ Val string
}
type errorHTTPResponse struct {
statusCode int
data any
error error
+ headers []headerval
+ cookies []cookieval
}
func (j errorHTTPResponse) Write(g *gin.Context) {
+ for _, v := range j.headers {
+ g.Header(v.Key, v.Val)
+ }
+ for _, v := range j.cookies {
+ g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
+ }
g.JSON(j.statusCode, j.data)
}
@@ -122,7 +51,7 @@ func (j errorHTTPResponse) Statuscode() int {
return j.statusCode
}
-func (j errorHTTPResponse) BodyString() *string {
+func (j errorHTTPResponse) BodyString(g *gin.Context) *string {
v, err := json.Marshal(j.data)
if err != nil {
return nil
@@ -134,39 +63,41 @@ func (j errorHTTPResponse) ContentType() string {
return "application/json"
}
-func Status(sc int) HTTPResponse {
- return &emptyHTTPResponse{statusCode: sc}
+func (j errorHTTPResponse) WithHeader(k string, v string) ginext.HTTPResponse {
+ j.headers = append(j.headers, headerval{k, v})
+ return j
}
-func JSON(sc int, data any) HTTPResponse {
- return &jsonHTTPResponse{statusCode: sc, data: data}
+func (j errorHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) ginext.HTTPResponse {
+ j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
+ return j
}
-func Data(sc int, contentType string, data []byte) HTTPResponse {
- return &dataHTTPResponse{statusCode: sc, contentType: contentType, data: data}
+func (j errorHTTPResponse) IsSuccess() bool {
+ return false
}
-func Text(sc int, data string) HTTPResponse {
- return &textHTTPResponse{statusCode: sc, data: data}
+func (j errorHTTPResponse) Headers() []string {
+ return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
}
-func InternalError(e error) HTTPResponse {
+func InternalError(e error) ginext.HTTPResponse {
return createApiError(nil, "InternalError", 500, apierr.INTERNAL_EXCEPTION, 0, e.Error(), e)
}
-func APIError(g *gin.Context, status int, errorid apierr.APIError, msg string, e error) HTTPResponse {
+func APIError(g *gin.Context, status int, errorid apierr.APIError, msg string, e error) ginext.HTTPResponse {
return createApiError(g, "APIError", status, errorid, 0, msg, e)
}
-func SendAPIError(g *gin.Context, status int, errorid apierr.APIError, highlight apihighlight.ErrHighlight, msg string, e error) HTTPResponse {
+func SendAPIError(g *gin.Context, status int, errorid apierr.APIError, highlight apihighlight.ErrHighlight, msg string, e error) ginext.HTTPResponse {
return createApiError(g, "SendAPIError", status, errorid, highlight, msg, e)
}
-func NotImplemented(g *gin.Context) HTTPResponse {
+func NotImplemented(pctx ginext.PreContext) ginext.HTTPResponse {
return createApiError(g, "NotImplemented", 500, apierr.NOT_IMPLEMENTED, 0, "Not Implemented", nil)
}
-func createApiError(g *gin.Context, ident string, status int, errorid apierr.APIError, highlight apihighlight.ErrHighlight, msg string, e error) HTTPResponse {
+func createApiError(g *gin.Context, ident string, status int, errorid apierr.APIError, highlight apihighlight.ErrHighlight, msg string, e error) ginext.HTTPResponse {
reqUri := ""
if g != nil && g.Request != nil {
reqUri = g.Request.Method + " :: " + g.Request.RequestURI
@@ -207,6 +138,6 @@ func createApiError(g *gin.Context, ident string, status int, errorid apierr.API
}
}
-func CompatAPIError(errid int, msg string) HTTPResponse {
- return &jsonHTTPResponse{statusCode: 200, data: compatAPIError{Success: false, ErrorID: errid, Message: msg}}
+func CompatAPIError(errid int, msg string) ginext.HTTPResponse {
+ return ginext.JSON(200, compatAPIError{Success: false, ErrorID: errid, Message: msg})
}
diff --git a/scnserver/api/handler/apiChannel.go b/scnserver/api/handler/apiChannel.go
index 479b1be..754d2a0 100644
--- a/scnserver/api/handler/apiChannel.go
+++ b/scnserver/api/handler/apiChannel.go
@@ -8,7 +8,7 @@ import (
"database/sql"
"errors"
"fmt"
- "github.com/gin-gonic/gin"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/mathext"
"net/http"
@@ -37,7 +37,7 @@ import (
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/channels [GET]
-func (h APIHandler) ListChannels(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) ListChannels(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
@@ -50,6 +50,12 @@ func (h APIHandler) ListChannels(g *gin.Context) ginresp.HTTPResponse {
var u uri
var q query
+ ctx, g, errResp := pctx.URI(&u).Query(&q).Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
+
ctx, errResp := h.app.StartRequest(g, &u, &q, nil, nil)
if errResp != nil {
return *errResp
@@ -110,7 +116,7 @@ func (h APIHandler) ListChannels(g *gin.Context) ginresp.HTTPResponse {
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Channels: res}))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{Channels: res}))
}
// GetChannel swaggerdoc
@@ -129,14 +135,14 @@ func (h APIHandler) ListChannels(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/channels/{cid} [GET]
-func (h APIHandler) GetChannel(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) GetChannel(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
ChannelID models.ChannelID `uri:"cid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -154,7 +160,7 @@ func (h APIHandler) GetChannel(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, channel.JSON(true)))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, channel.JSON(true)))
}
// CreateChannel swaggerdoc
@@ -173,7 +179,7 @@ func (h APIHandler) GetChannel(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/channels [POST]
-func (h APIHandler) CreateChannel(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) CreateChannel(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
@@ -186,7 +192,7 @@ func (h APIHandler) CreateChannel(g *gin.Context) ginresp.HTTPResponse {
var u uri
var b body
- ctx, errResp := h.app.StartRequest(g, &u, nil, &b, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Body(&b).Start())
if errResp != nil {
return *errResp
}
@@ -247,11 +253,11 @@ func (h APIHandler) CreateChannel(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create subscription", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, channel.WithSubscription(langext.Ptr(sub)).JSON(true)))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, channel.WithSubscription(langext.Ptr(sub)).JSON(true)))
} else {
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, channel.WithSubscription(nil).JSON(true)))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, channel.WithSubscription(nil).JSON(true)))
}
@@ -277,7 +283,7 @@ func (h APIHandler) CreateChannel(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/channels/{cid} [PATCH]
-func (h APIHandler) UpdateChannel(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) UpdateChannel(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
ChannelID models.ChannelID `uri:"cid" binding:"entityid"`
@@ -290,7 +296,7 @@ func (h APIHandler) UpdateChannel(g *gin.Context) ginresp.HTTPResponse {
var u uri
var b body
- ctx, errResp := h.app.StartRequest(g, &u, nil, &b, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Body(&b).Start())
if errResp != nil {
return *errResp
}
@@ -367,7 +373,7 @@ func (h APIHandler) UpdateChannel(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query (updated) channel", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, channel.JSON(true)))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, channel.JSON(true)))
}
// ListChannelMessages swaggerdoc
@@ -391,7 +397,7 @@ func (h APIHandler) UpdateChannel(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/channels/{cid}/messages [GET]
-func (h APIHandler) ListChannelMessages(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) ListChannelMessages(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
ChannelUserID models.UserID `uri:"uid" binding:"entityid"`
ChannelID models.ChannelID `uri:"cid" binding:"entityid"`
@@ -410,7 +416,7 @@ func (h APIHandler) ListChannelMessages(g *gin.Context) ginresp.HTTPResponse {
var u uri
var q query
- ctx, errResp := h.app.StartRequest(g, &u, &q, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Query(&q).Start())
if errResp != nil {
return *errResp
}
@@ -455,5 +461,5 @@ func (h APIHandler) ListChannelMessages(g *gin.Context) ginresp.HTTPResponse {
res = langext.ArrMap(messages, func(v models.Message) models.MessageJSON { return v.FullJSON() })
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Messages: res, NextPageToken: npt.Token(), PageSize: pageSize}))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{Messages: res, NextPageToken: npt.Token(), PageSize: pageSize}))
}
diff --git a/scnserver/api/handler/apiClient.go b/scnserver/api/handler/apiClient.go
index 86161dd..b672789 100644
--- a/scnserver/api/handler/apiClient.go
+++ b/scnserver/api/handler/apiClient.go
@@ -6,7 +6,7 @@ import (
"blackforestbytes.com/simplecloudnotifier/models"
"database/sql"
"errors"
- "github.com/gin-gonic/gin"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"net/http"
)
@@ -25,7 +25,7 @@ import (
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/clients [GET]
-func (h APIHandler) ListClients(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) ListClients(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
@@ -34,7 +34,7 @@ func (h APIHandler) ListClients(g *gin.Context) ginresp.HTTPResponse {
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -51,7 +51,7 @@ func (h APIHandler) ListClients(g *gin.Context) ginresp.HTTPResponse {
res := langext.ArrMap(clients, func(v models.Client) models.ClientJSON { return v.JSON() })
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Clients: res}))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{Clients: res}))
}
// GetClient swaggerdoc
@@ -70,14 +70,14 @@ func (h APIHandler) ListClients(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/clients/{cid} [GET]
-func (h APIHandler) GetClient(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) GetClient(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
ClientID models.ClientID `uri:"cid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -95,7 +95,7 @@ func (h APIHandler) GetClient(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, client.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, client.JSON()))
}
// AddClient swaggerdoc
@@ -114,7 +114,7 @@ func (h APIHandler) GetClient(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/clients [POST]
-func (h APIHandler) AddClient(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) AddClient(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
@@ -128,7 +128,7 @@ func (h APIHandler) AddClient(g *gin.Context) ginresp.HTTPResponse {
var u uri
var b body
- ctx, errResp := h.app.StartRequest(g, &u, nil, &b, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Body(&b).Start())
if errResp != nil {
return *errResp
}
@@ -153,7 +153,7 @@ func (h APIHandler) AddClient(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create client in db", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, client.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, client.JSON()))
}
// DeleteClient swaggerdoc
@@ -172,14 +172,14 @@ func (h APIHandler) AddClient(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/clients/{cid} [DELETE]
-func (h APIHandler) DeleteClient(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) DeleteClient(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
ClientID models.ClientID `uri:"cid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -202,7 +202,7 @@ func (h APIHandler) DeleteClient(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to delete client", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, client.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, client.JSON()))
}
// UpdateClient swaggerdoc
@@ -225,7 +225,7 @@ func (h APIHandler) DeleteClient(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/clients/{cid} [PATCH]
-func (h APIHandler) UpdateClient(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) UpdateClient(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
ClientID models.ClientID `uri:"cid" binding:"entityid"`
@@ -239,7 +239,7 @@ func (h APIHandler) UpdateClient(g *gin.Context) ginresp.HTTPResponse {
var u uri
var b body
- ctx, errResp := h.app.StartRequest(g, &u, nil, &b, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Body(&b).Start())
if errResp != nil {
return *errResp
}
@@ -303,5 +303,5 @@ func (h APIHandler) UpdateClient(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query (updated) client", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, client.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, client.JSON()))
}
diff --git a/scnserver/api/handler/apiKeyToken.go b/scnserver/api/handler/apiKeyToken.go
index 646625b..636679e 100644
--- a/scnserver/api/handler/apiKeyToken.go
+++ b/scnserver/api/handler/apiKeyToken.go
@@ -6,7 +6,7 @@ import (
"blackforestbytes.com/simplecloudnotifier/models"
"database/sql"
"errors"
- "github.com/gin-gonic/gin"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"net/http"
)
@@ -27,7 +27,7 @@ import (
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/keys [GET]
-func (h APIHandler) ListUserKeys(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) ListUserKeys(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
@@ -36,7 +36,7 @@ func (h APIHandler) ListUserKeys(g *gin.Context) ginresp.HTTPResponse {
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -53,7 +53,7 @@ func (h APIHandler) ListUserKeys(g *gin.Context) ginresp.HTTPResponse {
res := langext.ArrMap(toks, func(v models.KeyToken) models.KeyTokenJSON { return v.JSON() })
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Keys: res}))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{Keys: res}))
}
// GetCurrentUserKey swaggerdoc
@@ -73,13 +73,13 @@ func (h APIHandler) ListUserKeys(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/keys/current [GET]
-func (h APIHandler) GetCurrentUserKey(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) GetCurrentUserKey(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -102,7 +102,7 @@ func (h APIHandler) GetCurrentUserKey(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, keytoken.JSON().WithToken(keytoken.Token)))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, keytoken.JSON().WithToken(keytoken.Token)))
}
// GetUserKey swaggerdoc
@@ -122,14 +122,14 @@ func (h APIHandler) GetCurrentUserKey(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/keys/{kid} [GET]
-func (h APIHandler) GetUserKey(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) GetUserKey(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
KeyID models.KeyTokenID `uri:"kid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -147,7 +147,7 @@ func (h APIHandler) GetUserKey(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, keytoken.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, keytoken.JSON()))
}
// UpdateUserKey swaggerdoc
@@ -168,7 +168,7 @@ func (h APIHandler) GetUserKey(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/keys/{kid} [PATCH]
-func (h APIHandler) UpdateUserKey(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) UpdateUserKey(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
KeyID models.KeyTokenID `uri:"kid" binding:"entityid"`
@@ -182,7 +182,7 @@ func (h APIHandler) UpdateUserKey(g *gin.Context) ginresp.HTTPResponse {
var u uri
var b body
- ctx, errResp := h.app.StartRequest(g, &u, nil, &b, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Body(&b).Start())
if errResp != nil {
return *errResp
}
@@ -245,7 +245,7 @@ func (h APIHandler) UpdateUserKey(g *gin.Context) ginresp.HTTPResponse {
keytoken.Channels = *b.Channels
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, keytoken.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, keytoken.JSON()))
}
// CreateUserKey swaggerdoc
@@ -265,7 +265,7 @@ func (h APIHandler) UpdateUserKey(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/keys [POST]
-func (h APIHandler) CreateUserKey(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) CreateUserKey(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
@@ -278,7 +278,7 @@ func (h APIHandler) CreateUserKey(g *gin.Context) ginresp.HTTPResponse {
var u uri
var b body
- ctx, errResp := h.app.StartRequest(g, &u, nil, &b, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Body(&b).Start())
if errResp != nil {
return *errResp
}
@@ -314,7 +314,7 @@ func (h APIHandler) CreateUserKey(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create keytoken in db", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, keytok.JSON().WithToken(token)))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, keytok.JSON().WithToken(token)))
}
// DeleteUserKey swaggerdoc
@@ -334,14 +334,14 @@ func (h APIHandler) CreateUserKey(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/keys/{kid} [DELETE]
-func (h APIHandler) DeleteUserKey(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) DeleteUserKey(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
KeyID models.KeyTokenID `uri:"kid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -368,5 +368,5 @@ func (h APIHandler) DeleteUserKey(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to delete client", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, client.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, client.JSON()))
}
diff --git a/scnserver/api/handler/apiMessage.go b/scnserver/api/handler/apiMessage.go
index b7fdfbc..10f8e47 100644
--- a/scnserver/api/handler/apiMessage.go
+++ b/scnserver/api/handler/apiMessage.go
@@ -3,6 +3,7 @@ package handler
import (
"database/sql"
"errors"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"net/http"
"strings"
"time"
@@ -11,7 +12,6 @@ import (
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
ct "blackforestbytes.com/simplecloudnotifier/db/cursortoken"
"blackforestbytes.com/simplecloudnotifier/models"
- "github.com/gin-gonic/gin"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/mathext"
)
@@ -34,7 +34,7 @@ import (
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/messages [GET]
-func (h APIHandler) ListMessages(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) ListMessages(pctx ginext.PreContext) ginext.HTTPResponse {
type query struct {
PageSize *int `json:"page_size" form:"page_size"`
NextPageToken *string `json:"next_page_token" form:"next_page_token"`
@@ -155,7 +155,7 @@ func (h APIHandler) ListMessages(g *gin.Context) ginresp.HTTPResponse {
res = langext.ArrMap(messages, func(v models.Message) models.MessageJSON { return v.FullJSON() })
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Messages: res, NextPageToken: npt.Token(), PageSize: pageSize}))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{Messages: res, NextPageToken: npt.Token(), PageSize: pageSize}))
}
// GetMessage swaggerdoc
@@ -176,13 +176,13 @@ func (h APIHandler) ListMessages(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/messages/{mid} [GET]
-func (h APIHandler) GetMessage(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) GetMessage(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
MessageID models.MessageID `uri:"mid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -204,7 +204,7 @@ func (h APIHandler) GetMessage(g *gin.Context) ginresp.HTTPResponse {
// or we subscribe (+confirmed) to the channel and have read/admin key
if ctx.CheckPermissionMessageRead(msg) {
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, msg.FullJSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, msg.FullJSON()))
}
if uid := ctx.GetPermissionUserID(); uid != nil && ctx.CheckPermissionUserRead(*uid) == nil {
@@ -222,7 +222,7 @@ func (h APIHandler) GetMessage(g *gin.Context) ginresp.HTTPResponse {
}
// => perm okay
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, msg.FullJSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, msg.FullJSON()))
}
return ginresp.APIError(g, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil)
@@ -244,13 +244,13 @@ func (h APIHandler) GetMessage(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/messages/{mid} [DELETE]
-func (h APIHandler) DeleteMessage(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) DeleteMessage(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
MessageID models.MessageID `uri:"mid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -282,5 +282,5 @@ func (h APIHandler) DeleteMessage(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to cancel deliveries", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, msg.FullJSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, msg.FullJSON()))
}
diff --git a/scnserver/api/handler/apiPreview.go b/scnserver/api/handler/apiPreview.go
index 43a415e..d1df9fa 100644
--- a/scnserver/api/handler/apiPreview.go
+++ b/scnserver/api/handler/apiPreview.go
@@ -6,7 +6,7 @@ import (
"blackforestbytes.com/simplecloudnotifier/models"
"database/sql"
"errors"
- "github.com/gin-gonic/gin"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"net/http"
)
@@ -25,13 +25,13 @@ import (
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/preview/users/{uid} [GET]
-func (h APIHandler) GetUserPreview(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) GetUserPreview(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -49,7 +49,7 @@ func (h APIHandler) GetUserPreview(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query user", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, user.JSONPreview()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, user.JSONPreview()))
}
// GetChannelPreview swaggerdoc
@@ -67,13 +67,13 @@ func (h APIHandler) GetUserPreview(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/preview/channels/{cid} [GET]
-func (h APIHandler) GetChannelPreview(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) GetChannelPreview(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
ChannelID models.ChannelID `uri:"cid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -91,7 +91,7 @@ func (h APIHandler) GetChannelPreview(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, channel.JSONPreview()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, channel.JSONPreview()))
}
// GetUserKeyPreview swaggerdoc
@@ -109,13 +109,13 @@ func (h APIHandler) GetChannelPreview(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/preview/keys/{kid} [GET]
-func (h APIHandler) GetUserKeyPreview(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) GetUserKeyPreview(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
KeyID models.KeyTokenID `uri:"kid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -133,5 +133,5 @@ func (h APIHandler) GetUserKeyPreview(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, keytoken.JSONPreview()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, keytoken.JSONPreview()))
}
diff --git a/scnserver/api/handler/apiSubscription.go b/scnserver/api/handler/apiSubscription.go
index a89fd3c..e88fffa 100644
--- a/scnserver/api/handler/apiSubscription.go
+++ b/scnserver/api/handler/apiSubscription.go
@@ -6,7 +6,7 @@ import (
"blackforestbytes.com/simplecloudnotifier/models"
"database/sql"
"errors"
- "github.com/gin-gonic/gin"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"net/http"
"strings"
@@ -47,7 +47,7 @@ import (
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/subscriptions [GET]
-func (h APIHandler) ListUserSubscriptions(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) ListUserSubscriptions(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
@@ -64,7 +64,7 @@ func (h APIHandler) ListUserSubscriptions(g *gin.Context) ginresp.HTTPResponse {
var u uri
var q query
- ctx, errResp := h.app.StartRequest(g, &u, &q, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Query(&q).Start())
if errResp != nil {
return *errResp
}
@@ -128,7 +128,7 @@ func (h APIHandler) ListUserSubscriptions(g *gin.Context) ginresp.HTTPResponse {
jsonres := langext.ArrMap(res, func(v models.Subscription) models.SubscriptionJSON { return v.JSON() })
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Subscriptions: jsonres}))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{Subscriptions: jsonres}))
}
// ListChannelSubscriptions swaggerdoc
@@ -147,7 +147,7 @@ func (h APIHandler) ListUserSubscriptions(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/channels/{cid}/subscriptions [GET]
-func (h APIHandler) ListChannelSubscriptions(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) ListChannelSubscriptions(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
ChannelID models.ChannelID `uri:"cid" binding:"entityid"`
@@ -157,7 +157,7 @@ func (h APIHandler) ListChannelSubscriptions(g *gin.Context) ginresp.HTTPRespons
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -182,7 +182,7 @@ func (h APIHandler) ListChannelSubscriptions(g *gin.Context) ginresp.HTTPRespons
res := langext.ArrMap(clients, func(v models.Subscription) models.SubscriptionJSON { return v.JSON() })
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Subscriptions: res}))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{Subscriptions: res}))
}
// GetSubscription swaggerdoc
@@ -201,14 +201,14 @@ func (h APIHandler) ListChannelSubscriptions(g *gin.Context) ginresp.HTTPRespons
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/subscriptions/{sid} [GET]
-func (h APIHandler) GetSubscription(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) GetSubscription(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
SubscriptionID models.SubscriptionID `uri:"sid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -229,7 +229,7 @@ func (h APIHandler) GetSubscription(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 404, apierr.SUBSCRIPTION_USER_MISMATCH, "Subscription not found", nil)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, subscription.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, subscription.JSON()))
}
// CancelSubscription swaggerdoc
@@ -248,14 +248,14 @@ func (h APIHandler) GetSubscription(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/subscriptions/{sid} [DELETE]
-func (h APIHandler) CancelSubscription(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) CancelSubscription(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
SubscriptionID models.SubscriptionID `uri:"sid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -281,7 +281,7 @@ func (h APIHandler) CancelSubscription(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to delete subscription", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, subscription.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, subscription.JSON()))
}
// CreateSubscription swaggerdoc
@@ -301,7 +301,7 @@ func (h APIHandler) CancelSubscription(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/subscriptions [POST]
-func (h APIHandler) CreateSubscription(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) CreateSubscription(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
@@ -317,7 +317,7 @@ func (h APIHandler) CreateSubscription(g *gin.Context) ginresp.HTTPResponse {
var u uri
var q query
var b body
- ctx, errResp := h.app.StartRequest(g, &u, &q, &b, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Query(&q).Body(&b).Start())
if errResp != nil {
return *errResp
}
@@ -378,7 +378,7 @@ func (h APIHandler) CreateSubscription(g *gin.Context) ginresp.HTTPResponse {
existingSub.Confirmed = true
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, existingSub.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, existingSub.JSON()))
}
sub, err := h.database.CreateSubscription(ctx, u.UserID, channel, channel.OwnerUserID == u.UserID)
@@ -386,7 +386,7 @@ func (h APIHandler) CreateSubscription(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create subscription", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, sub.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, sub.JSON()))
}
// UpdateSubscription swaggerdoc
@@ -406,7 +406,7 @@ func (h APIHandler) CreateSubscription(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid}/subscriptions/{sid} [PATCH]
-func (h APIHandler) UpdateSubscription(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) UpdateSubscription(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
SubscriptionID models.SubscriptionID `uri:"sid" binding:"entityid"`
@@ -417,7 +417,7 @@ func (h APIHandler) UpdateSubscription(g *gin.Context) ginresp.HTTPResponse {
var u uri
var b body
- ctx, errResp := h.app.StartRequest(g, &u, nil, &b, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Body(&b).Start())
if errResp != nil {
return *errResp
}
@@ -455,5 +455,5 @@ func (h APIHandler) UpdateSubscription(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query subscription", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, subscription.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, subscription.JSON()))
}
diff --git a/scnserver/api/handler/apiUser.go b/scnserver/api/handler/apiUser.go
index 30eccc1..2537ec2 100644
--- a/scnserver/api/handler/apiUser.go
+++ b/scnserver/api/handler/apiUser.go
@@ -7,8 +7,8 @@ import (
"database/sql"
"errors"
"fmt"
- "github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"net/http"
)
@@ -26,7 +26,7 @@ import (
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users [POST]
-func (h APIHandler) CreateUser(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) CreateUser(pctx ginext.PreContext) ginext.HTTPResponse {
type body struct {
FCMToken string `json:"fcm_token"`
ProToken *string `json:"pro_token"`
@@ -39,7 +39,7 @@ func (h APIHandler) CreateUser(g *gin.Context) ginresp.HTTPResponse {
}
var b body
- ctx, errResp := h.app.StartRequest(g, nil, nil, &b, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.Body(&b).Start())
if errResp != nil {
return *errResp
}
@@ -117,7 +117,7 @@ func (h APIHandler) CreateUser(g *gin.Context) ginresp.HTTPResponse {
log.Info().Msg(fmt.Sprintf("Sucessfully created new user %s (client: %v)", userobj.UserID, b.NoClient))
if b.NoClient {
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, userobj.JSONWithClients(make([]models.Client, 0), adminKey, sendKey, readKey)))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, userobj.JSONWithClients(make([]models.Client, 0), adminKey, sendKey, readKey)))
} else {
err := h.database.DeleteClientsByFCM(ctx, b.FCMToken)
if err != nil {
@@ -129,7 +129,7 @@ func (h APIHandler) CreateUser(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create client in db", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, userobj.JSONWithClients([]models.Client{client}, adminKey, sendKey, readKey)))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, userobj.JSONWithClients([]models.Client{client}, adminKey, sendKey, readKey)))
}
}
@@ -149,13 +149,13 @@ func (h APIHandler) CreateUser(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid} [GET]
-func (h APIHandler) GetUser(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) GetUser(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
var u uri
- ctx, errResp := h.app.StartRequest(g, &u, nil, nil, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Start())
if errResp != nil {
return *errResp
}
@@ -173,7 +173,7 @@ func (h APIHandler) GetUser(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query user", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, user.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, user.JSON()))
}
// UpdateUser swaggerdoc
@@ -195,7 +195,7 @@ func (h APIHandler) GetUser(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError "internal server error"
//
// @Router /api/v2/users/{uid} [PATCH]
-func (h APIHandler) UpdateUser(g *gin.Context) ginresp.HTTPResponse {
+func (h APIHandler) UpdateUser(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
UserID models.UserID `uri:"uid" binding:"entityid"`
}
@@ -206,7 +206,7 @@ func (h APIHandler) UpdateUser(g *gin.Context) ginresp.HTTPResponse {
var u uri
var b body
- ctx, errResp := h.app.StartRequest(g, &u, nil, &b, nil)
+ ctx, g, errResp := h.app.StartRequest(pctx.URI(&u).Body(&b).Start())
if errResp != nil {
return *errResp
}
@@ -261,5 +261,5 @@ func (h APIHandler) UpdateUser(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query (updated) user", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, user.JSON()))
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, user.JSON()))
}
diff --git a/scnserver/api/handler/common.go b/scnserver/api/handler/common.go
index a069d89..2f3d830 100644
--- a/scnserver/api/handler/common.go
+++ b/scnserver/api/handler/common.go
@@ -6,10 +6,10 @@ import (
"blackforestbytes.com/simplecloudnotifier/db/simplectx"
"blackforestbytes.com/simplecloudnotifier/logic"
"bytes"
- "context"
"errors"
"github.com/gin-gonic/gin"
- sqlite3 "github.com/mattn/go-sqlite3"
+ "github.com/mattn/go-sqlite3"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/timeext"
"net/http"
@@ -51,12 +51,18 @@ type pingResponseInfo struct {
// @Router /api/ping [put]
// @Router /api/ping [delete]
// @Router /api/ping [patch]
-func (h CommonHandler) Ping(g *gin.Context) ginresp.HTTPResponse {
+func (h CommonHandler) Ping(pctx ginext.PreContext) ginext.HTTPResponse {
+ ctx, g, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
+
buf := new(bytes.Buffer)
_, _ = buf.ReadFrom(g.Request.Body)
resuestBody := buf.String()
- return ginresp.JSON(http.StatusOK, pingResponse{
+ return ginext.JSON(http.StatusOK, pingResponse{
Message: "Pong",
Info: pingResponseInfo{
Method: g.Request.Method,
@@ -78,7 +84,7 @@ func (h CommonHandler) Ping(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError
//
// @Router /api/db-test [post]
-func (h CommonHandler) DatabaseTest(g *gin.Context) ginresp.HTTPResponse {
+func (h CommonHandler) DatabaseTest(pctx ginext.PreContext) ginext.HTTPResponse {
type response struct {
Success bool `json:"success"`
LibVersion string `json:"libVersion"`
@@ -86,8 +92,11 @@ func (h CommonHandler) DatabaseTest(g *gin.Context) ginresp.HTTPResponse {
SourceID string `json:"sourceID"`
}
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
- defer cancel()
+ ctx, _, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
libVersion, libVersionNumber, sourceID := sqlite3.Version()
@@ -96,7 +105,7 @@ func (h CommonHandler) DatabaseTest(g *gin.Context) ginresp.HTTPResponse {
return ginresp.InternalError(err)
}
- return ginresp.JSON(http.StatusOK, response{
+ return ginext.JSON(http.StatusOK, response{
Success: true,
LibVersion: libVersion,
LibVersionNumber: libVersionNumber,
@@ -114,13 +123,16 @@ func (h CommonHandler) DatabaseTest(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError
//
// @Router /api/health [get]
-func (h CommonHandler) Health(g *gin.Context) ginresp.HTTPResponse {
+func (h CommonHandler) Health(pctx ginext.PreContext) ginext.HTTPResponse {
type response struct {
Status string `json:"status"`
}
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
- defer cancel()
+ ctx, _, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
_, libVersionNumber, _ := sqlite3.Version()
@@ -161,7 +173,7 @@ func (h CommonHandler) Health(g *gin.Context) ginresp.HTTPResponse {
}
- return ginresp.JSON(http.StatusOK, response{Status: "ok"})
+ return ginext.JSON(http.StatusOK, response{Status: "ok"})
}
// Sleep swaggerdoc
@@ -177,7 +189,7 @@ func (h CommonHandler) Health(g *gin.Context) ginresp.HTTPResponse {
// @Failure 500 {object} ginresp.apiError
//
// @Router /api/sleep/{secs} [post]
-func (h CommonHandler) Sleep(g *gin.Context) ginresp.HTTPResponse {
+func (h CommonHandler) Sleep(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
Seconds float64 `uri:"secs"`
}
@@ -187,6 +199,12 @@ func (h CommonHandler) Sleep(g *gin.Context) ginresp.HTTPResponse {
Duration float64 `json:"duration"`
}
+ ctx, g, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
+
t0 := time.Now().Format(time.RFC3339Nano)
var u uri
@@ -198,15 +216,21 @@ func (h CommonHandler) Sleep(g *gin.Context) ginresp.HTTPResponse {
t1 := time.Now().Format(time.RFC3339Nano)
- return ginresp.JSON(http.StatusOK, response{
+ return ginext.JSON(http.StatusOK, response{
Start: t0,
End: t1,
Duration: u.Seconds,
})
}
-func (h CommonHandler) NoRoute(g *gin.Context) ginresp.HTTPResponse {
- return ginresp.JSON(http.StatusNotFound, gin.H{
+func (h CommonHandler) NoRoute(pctx ginext.PreContext) ginext.HTTPResponse {
+ ctx, g, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
+
+ return ginext.JSON(http.StatusNotFound, gin.H{
"": "================ ROUTE NOT FOUND ================",
"FullPath": g.FullPath(),
"Method": g.Request.Method,
diff --git a/scnserver/api/handler/compat.go b/scnserver/api/handler/compat.go
index 7074c38..7aa177c 100644
--- a/scnserver/api/handler/compat.go
+++ b/scnserver/api/handler/compat.go
@@ -11,8 +11,8 @@ import (
"database/sql"
"errors"
"fmt"
- "github.com/gin-gonic/gin"
"gogs.mikescher.com/BlackForestBytes/goext/dataext"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"net/http"
)
@@ -47,7 +47,7 @@ func NewCompatHandler(app *logic.Application) CompatHandler {
// @Failure 500 {object} ginresp.apiError
//
// @Router /send.php [POST]
-func (h CompatHandler) SendMessage(g *gin.Context) ginresp.HTTPResponse {
+func (h CompatHandler) SendMessage(pctx ginext.PreContext) ginext.HTTPResponse {
type combined struct {
UserID *int64 `json:"user_id" form:"user_id"`
UserKey *string `json:"user_key" form:"user_key"`
@@ -92,7 +92,7 @@ func (h CompatHandler) SendMessage(g *gin.Context) ginresp.HTTPResponse {
if errResp != nil {
return *errResp
} else {
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{
Success: true,
ErrorID: apierr.NO_ERROR,
ErrorHighlight: -1,
@@ -127,7 +127,7 @@ func (h CompatHandler) SendMessage(g *gin.Context) ginresp.HTTPResponse {
// @Failure default {object} ginresp.compatAPIError
//
// @Router /api/register.php [get]
-func (h CompatHandler) Register(g *gin.Context) ginresp.HTTPResponse {
+func (h CompatHandler) Register(pctx ginext.PreContext) ginext.HTTPResponse {
type query struct {
FCMToken *string `json:"fcm_token" form:"fcm_token"`
Pro *string `json:"pro" form:"pro"`
@@ -216,7 +216,7 @@ func (h CompatHandler) Register(g *gin.Context) ginresp.HTTPResponse {
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create userid", err)
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{
Success: true,
Message: "New user registered",
UserID: oldid,
@@ -245,7 +245,7 @@ func (h CompatHandler) Register(g *gin.Context) ginresp.HTTPResponse {
// @Failure default {object} ginresp.compatAPIError
//
// @Router /api/info.php [get]
-func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
+func (h CompatHandler) Info(pctx ginext.PreContext) ginext.HTTPResponse {
type query struct {
UserID *int64 `json:"user_id" form:"user_id"`
UserKey *string `json:"user_key" form:"user_key"`
@@ -321,7 +321,7 @@ func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
return ginresp.CompatAPIError(0, "Failed to query user")
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{
Success: true,
Message: "ok",
UserID: *data.UserID,
@@ -354,7 +354,7 @@ func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
// @Failure default {object} ginresp.compatAPIError
//
// @Router /api/ack.php [get]
-func (h CompatHandler) Ack(g *gin.Context) ginresp.HTTPResponse {
+func (h CompatHandler) Ack(pctx ginext.PreContext) ginext.HTTPResponse {
type query struct {
UserID *int64 `json:"user_id" form:"user_id"`
UserKey *string `json:"user_key" form:"user_key"`
@@ -434,7 +434,7 @@ func (h CompatHandler) Ack(g *gin.Context) ginresp.HTTPResponse {
}
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{
Success: true,
Message: "ok",
PrevAckValue: langext.Conditional(ackBefore, 1, 0),
@@ -460,7 +460,7 @@ func (h CompatHandler) Ack(g *gin.Context) ginresp.HTTPResponse {
// @Failure default {object} ginresp.compatAPIError
//
// @Router /api/requery.php [get]
-func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
+func (h CompatHandler) Requery(pctx ginext.PreContext) ginext.HTTPResponse {
type query struct {
UserID *int64 `json:"user_id" form:"user_id"`
UserKey *string `json:"user_key" form:"user_key"`
@@ -545,7 +545,7 @@ func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
})
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{
Success: true,
Message: "ok",
Count: len(compMsgs),
@@ -573,7 +573,7 @@ func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
// @Failure default {object} ginresp.compatAPIError
//
// @Router /api/update.php [get]
-func (h CompatHandler) Update(g *gin.Context) ginresp.HTTPResponse {
+func (h CompatHandler) Update(pctx ginext.PreContext) ginext.HTTPResponse {
type query struct {
UserID *int64 `json:"user_id" form:"user_id"`
UserKey *string `json:"user_key" form:"user_key"`
@@ -673,7 +673,7 @@ func (h CompatHandler) Update(g *gin.Context) ginresp.HTTPResponse {
return ginresp.CompatAPIError(0, "Failed to query user")
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{
Success: true,
Message: "user updated",
UserID: *data.UserID,
@@ -704,7 +704,7 @@ func (h CompatHandler) Update(g *gin.Context) ginresp.HTTPResponse {
// @Failure default {object} ginresp.compatAPIError
//
// @Router /api/expand.php [get]
-func (h CompatHandler) Expand(g *gin.Context) ginresp.HTTPResponse {
+func (h CompatHandler) Expand(pctx ginext.PreContext) ginext.HTTPResponse {
type query struct {
UserID *int64 `json:"user_id" form:"user_id"`
UserKey *string `json:"user_key" form:"user_key"`
@@ -779,7 +779,7 @@ func (h CompatHandler) Expand(g *gin.Context) ginresp.HTTPResponse {
return ginresp.CompatAPIError(0, "Failed to query message")
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{
Success: true,
Message: "ok",
Data: models.CompatMessage{
@@ -816,7 +816,7 @@ func (h CompatHandler) Expand(g *gin.Context) ginresp.HTTPResponse {
// @Failure default {object} ginresp.compatAPIError
//
// @Router /api/upgrade.php [get]
-func (h CompatHandler) Upgrade(g *gin.Context) ginresp.HTTPResponse {
+func (h CompatHandler) Upgrade(pctx ginext.PreContext) ginext.HTTPResponse {
type query struct {
UserID *int64 `json:"user_id" form:"user_id"`
UserKey *string `json:"user_key" form:"user_key"`
@@ -921,7 +921,7 @@ func (h CompatHandler) Upgrade(g *gin.Context) ginresp.HTTPResponse {
return ginresp.CompatAPIError(0, "Failed to query user")
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{
Success: true,
Message: "user updated",
UserID: *data.UserID,
diff --git a/scnserver/api/handler/external.go b/scnserver/api/handler/external.go
index d09877d..ee578de 100644
--- a/scnserver/api/handler/external.go
+++ b/scnserver/api/handler/external.go
@@ -7,7 +7,7 @@ import (
"blackforestbytes.com/simplecloudnotifier/logic"
"blackforestbytes.com/simplecloudnotifier/models"
"fmt"
- "github.com/gin-gonic/gin"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"net/http"
"time"
@@ -41,7 +41,7 @@ func NewExternalHandler(app *logic.Application) ExternalHandler {
// @Failure 500 {object} ginresp.apiError "An internal server error occurred - try again later"
//
// @Router /external/v1/uptime-kuma [POST]
-func (h ExternalHandler) UptimeKuma(g *gin.Context) ginresp.HTTPResponse {
+func (h ExternalHandler) UptimeKuma(pctx ginext.PreContext) ginext.HTTPResponse {
type query struct {
UserID *models.UserID `form:"user_id" example:"7725"`
KeyToken *string `form:"key" example:"P3TNH8mvv14fm"`
@@ -128,7 +128,7 @@ func (h ExternalHandler) UptimeKuma(g *gin.Context) ginresp.HTTPResponse {
return *errResp
}
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{
MessageID: okResp.Message.MessageID,
}))
}
diff --git a/scnserver/api/handler/message.go b/scnserver/api/handler/message.go
index b1f6395..d39fff3 100644
--- a/scnserver/api/handler/message.go
+++ b/scnserver/api/handler/message.go
@@ -2,12 +2,11 @@ package handler
import (
"blackforestbytes.com/simplecloudnotifier/api/apierr"
- "blackforestbytes.com/simplecloudnotifier/api/ginresp"
primarydb "blackforestbytes.com/simplecloudnotifier/db/impl/primary"
"blackforestbytes.com/simplecloudnotifier/logic"
"blackforestbytes.com/simplecloudnotifier/models"
- "github.com/gin-gonic/gin"
"gogs.mikescher.com/BlackForestBytes/goext/dataext"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"net/http"
)
@@ -49,7 +48,7 @@ func NewMessageHandler(app *logic.Application) MessageHandler {
//
// @Router / [POST]
// @Router /send [POST]
-func (h MessageHandler) SendMessage(g *gin.Context) ginresp.HTTPResponse {
+func (h MessageHandler) SendMessage(pctx ginext.PreContext) ginext.HTTPResponse {
type combined struct {
UserID *models.UserID `json:"user_id" form:"user_id" example:"7725" `
KeyToken *string `json:"key" form:"key" example:"P3TNH8mvv14fm" `
@@ -78,7 +77,7 @@ func (h MessageHandler) SendMessage(g *gin.Context) ginresp.HTTPResponse {
var b combined
var q combined
var f combined
- ctx, errResp := h.app.StartRequest(g, nil, &q, &b, &f, logic.RequestOptions{IgnoreWrongContentType: true})
+ ctx, g, errResp := h.app.StartRequest(pctx.Form(&f).Query(&q).Body(&b).Start())
if errResp != nil {
return *errResp
}
@@ -91,7 +90,7 @@ func (h MessageHandler) SendMessage(g *gin.Context) ginresp.HTTPResponse {
if errResp != nil {
return *errResp
} else {
- return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
+ return ctx.FinishSuccess(ginext.JSON(http.StatusOK, response{
Success: true,
ErrorID: apierr.NO_ERROR,
ErrorHighlight: -1,
diff --git a/scnserver/api/handler/website.go b/scnserver/api/handler/website.go
index 492bea0..ae04686 100644
--- a/scnserver/api/handler/website.go
+++ b/scnserver/api/handler/website.go
@@ -7,6 +7,7 @@ import (
"errors"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/rext"
"net/http"
"regexp"
@@ -27,60 +28,104 @@ func NewWebsiteHandler(app *logic.Application) WebsiteHandler {
}
}
-func (h WebsiteHandler) Index(g *gin.Context) ginresp.HTTPResponse {
+func (h WebsiteHandler) Index(pctx ginext.PreContext) ginext.HTTPResponse {
+ ctx, g, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
+
return h.serveAsset(g, "index.html", true)
}
-func (h WebsiteHandler) APIDocs(g *gin.Context) ginresp.HTTPResponse {
+func (h WebsiteHandler) APIDocs(pctx ginext.PreContext) ginext.HTTPResponse {
+ ctx, g, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
+
return h.serveAsset(g, "api.html", true)
}
-func (h WebsiteHandler) APIDocsMore(g *gin.Context) ginresp.HTTPResponse {
+func (h WebsiteHandler) APIDocsMore(pctx ginext.PreContext) ginext.HTTPResponse {
+ ctx, g, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
+
return h.serveAsset(g, "api_more.html", true)
}
-func (h WebsiteHandler) MessageSent(g *gin.Context) ginresp.HTTPResponse {
+func (h WebsiteHandler) MessageSent(pctx ginext.PreContext) ginext.HTTPResponse {
+ ctx, g, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
+
return h.serveAsset(g, "message_sent.html", true)
}
-func (h WebsiteHandler) FaviconIco(g *gin.Context) ginresp.HTTPResponse {
+func (h WebsiteHandler) FaviconIco(pctx ginext.PreContext) ginext.HTTPResponse {
+ ctx, g, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
+
return h.serveAsset(g, "favicon.ico", false)
}
-func (h WebsiteHandler) FaviconPNG(g *gin.Context) ginresp.HTTPResponse {
+func (h WebsiteHandler) FaviconPNG(pctx ginext.PreContext) ginext.HTTPResponse {
+ ctx, g, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
+
return h.serveAsset(g, "favicon.png", false)
}
-func (h WebsiteHandler) Javascript(g *gin.Context) ginresp.HTTPResponse {
+func (h WebsiteHandler) Javascript(pctx ginext.PreContext) ginext.HTTPResponse {
+ ctx, g, errResp := pctx.Start()
+ if errResp != nil {
+ return *errResp
+ }
+ defer ctx.Cancel()
+
type uri struct {
Filename string `uri:"fn"`
}
var u uri
if err := g.ShouldBindUri(&u); err != nil {
- return ginresp.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return ginext.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
return h.serveAsset(g, "js/"+u.Filename, false)
}
-func (h WebsiteHandler) CSS(g *gin.Context) ginresp.HTTPResponse {
+func (h WebsiteHandler) CSS(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
Filename string `uri:"fn"`
}
var u uri
- if err := g.ShouldBindUri(&u); err != nil {
- return ginresp.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ ctx, g, errResp := pctx.URI(&u).Start()
+ if errResp != nil {
+ return *errResp
}
+ defer ctx.Cancel()
return h.serveAsset(g, "css/"+u.Filename, false)
}
-func (h WebsiteHandler) serveAsset(g *gin.Context, fn string, repl bool) ginresp.HTTPResponse {
+func (h WebsiteHandler) serveAsset(g *gin.Context, fn string, repl bool) ginext.HTTPResponse {
_data, err := website.Assets.ReadFile(fn)
if err != nil {
- return ginresp.Status(http.StatusNotFound)
+ return ginext.Status(http.StatusNotFound)
}
data := string(_data)
@@ -141,7 +186,7 @@ func (h WebsiteHandler) serveAsset(g *gin.Context, fn string, repl bool) ginresp
mime = "image/svg+xml"
}
- return ginresp.Data(http.StatusOK, mime, []byte(data))
+ return ginext.Data(http.StatusOK, mime, []byte(data))
}
func (h WebsiteHandler) getReplConfig(key string) (string, bool) {
diff --git a/scnserver/api/router.go b/scnserver/api/router.go
index 0162d88..adbeaf9 100644
--- a/scnserver/api/router.go
+++ b/scnserver/api/router.go
@@ -1,7 +1,6 @@
package api
import (
- "blackforestbytes.com/simplecloudnotifier/api/ginext"
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
"blackforestbytes.com/simplecloudnotifier/api/handler"
"blackforestbytes.com/simplecloudnotifier/logic"
@@ -11,6 +10,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
)
type Router struct {
@@ -50,7 +50,7 @@ func NewRouter(app *logic.Application) *Router {
// @tag.name Common
//
// @BasePath /
-func (r *Router) Init(e *gin.Engine) error {
+func (r *Router) Init(e *ginext.GinWrapper) error {
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
err := v.RegisterValidation("entityid", models.ValidateEntityID, true)
@@ -61,131 +61,129 @@ func (r *Router) Init(e *gin.Engine) error {
return errors.New("failed to add validators - wrong engine")
}
+ wrap := func(fn ginext.WHandlerFunc) ginext.WHandlerFunc{return Wrap(r.app, fn)}
+
// ================ General (unversioned) ================
- commonAPI := e.Group("/api")
+ commonAPI := e.Routes().Group("/api")
{
- commonAPI.Any("/ping", r.Wrap(r.commonHandler.Ping))
- commonAPI.POST("/db-test", r.Wrap(r.commonHandler.DatabaseTest))
- commonAPI.GET("/health", r.Wrap(r.commonHandler.Health))
- commonAPI.POST("/sleep/:secs", r.Wrap(r.commonHandler.Sleep))
+ commonAPI.Any("/ping").Handle(wrap(r.commonHandler.Ping))
+ commonAPI.POST("/db-test").Handle(wrap(r.commonHandler.DatabaseTest))
+ commonAPI.GET("/health").Handle(wrap(r.commonHandler.Health))
+ commonAPI.POST("/sleep/:secs").Handle(wrap(r.commonHandler.Sleep))
}
// ================ Swagger ================
- docs := e.Group("/documentation")
+ docs := e.Routes().Group("/documentation")
{
- docs.GET("/swagger", ginext.RedirectTemporary("/documentation/swagger/"))
- docs.GET("/swagger/*sub", r.Wrap(swagger.Handle))
+ docs.GET("/swagger").Handle(wrap(ginext.RedirectTemporary("/documentation/swagger/")))
+ docs.GET("/swagger/*sub").Handle(wrap(swagger.Handle))
}
// ================ Website ================
- frontend := e.Group("")
+ frontend := e.Routes().Group("")
{
- frontend.GET("/", r.Wrap(r.websiteHandler.Index))
- frontend.GET("/index.php", r.Wrap(r.websiteHandler.Index))
- frontend.GET("/index.html", r.Wrap(r.websiteHandler.Index))
- frontend.GET("/index", r.Wrap(r.websiteHandler.Index))
+ frontend.GET("/").Handle(wrap(r.websiteHandler.Index))
+ frontend.GET("/index.php").Handle(wrap(r.websiteHandler.Index))
+ frontend.GET("/index.html").Handle(wrap(r.websiteHandler.Index))
+ frontend.GET("/index").Handle(wrap(r.websiteHandler.Index))
- frontend.GET("/api", r.Wrap(r.websiteHandler.APIDocs))
- frontend.GET("/api.php", r.Wrap(r.websiteHandler.APIDocs))
- frontend.GET("/api.html", r.Wrap(r.websiteHandler.APIDocs))
+ frontend.GET("/api").Handle(wrap(r.websiteHandler.APIDocs))
+ frontend.GET("/api.php").Handle(wrap(r.websiteHandler.APIDocs))
+ frontend.GET("/api.html").Handle(wrap(r.websiteHandler.APIDocs))
- frontend.GET("/api_more", r.Wrap(r.websiteHandler.APIDocsMore))
- frontend.GET("/api_more.php", r.Wrap(r.websiteHandler.APIDocsMore))
- frontend.GET("/api_more.html", r.Wrap(r.websiteHandler.APIDocsMore))
+ frontend.GET("/api_more").Handle(wrap(r.websiteHandler.APIDocsMore))
+ frontend.GET("/api_more.php").Handle(wrap(r.websiteHandler.APIDocsMore))
+ frontend.GET("/api_more.html").Handle(wrap(r.websiteHandler.APIDocsMore))
- frontend.GET("/message_sent", r.Wrap(r.websiteHandler.MessageSent))
- frontend.GET("/message_sent.php", r.Wrap(r.websiteHandler.MessageSent))
- frontend.GET("/message_sent.html", r.Wrap(r.websiteHandler.MessageSent))
+ frontend.GET("/message_sent").Handle(wrap(r.websiteHandler.MessageSent))
+ frontend.GET("/message_sent.php").Handle(wrap(r.websiteHandler.MessageSent))
+ frontend.GET("/message_sent.html").Handle(wrap(r.websiteHandler.MessageSent))
- frontend.GET("/favicon.ico", r.Wrap(r.websiteHandler.FaviconIco))
- frontend.GET("/favicon.png", r.Wrap(r.websiteHandler.FaviconPNG))
+ frontend.GET("/favicon.ico").Handle(wrap(r.websiteHandler.FaviconIco))
+ frontend.GET("/favicon.png").Handle(wrap(r.websiteHandler.FaviconPNG))
- frontend.GET("/js/:fn", r.Wrap(r.websiteHandler.Javascript))
- frontend.GET("/css/:fn", r.Wrap(r.websiteHandler.CSS))
+ frontend.GET("/js/:fn").Handle(wrap(r.websiteHandler.Javascript))
+ frontend.GET("/css/:fn").Handle(wrap(r.websiteHandler.CSS))
}
// ================ Compat (v1) ================
- compat := e.Group("/api")
+ compat := e.Routes().Group("/api")
{
- compat.GET("/register.php", r.Wrap(r.compatHandler.Register))
- compat.GET("/info.php", r.Wrap(r.compatHandler.Info))
- compat.GET("/ack.php", r.Wrap(r.compatHandler.Ack))
- compat.GET("/requery.php", r.Wrap(r.compatHandler.Requery))
- compat.GET("/update.php", r.Wrap(r.compatHandler.Update))
- compat.GET("/expand.php", r.Wrap(r.compatHandler.Expand))
- compat.GET("/upgrade.php", r.Wrap(r.compatHandler.Upgrade))
+ compat.GET("/register.php").Handle(wrap(r.compatHandler.Register))
+ compat.GET("/info.php").Handle(wrap(r.compatHandler.Info))
+ compat.GET("/ack.php").Handle(wrap(r.compatHandler.Ack))
+ compat.GET("/requery.php").Handle(wrap(r.compatHandler.Requery))
+ compat.GET("/update.php").Handle(wrap(r.compatHandler.Update))
+ compat.GET("/expand.php").Handle(wrap(r.compatHandler.Expand))
+ compat.GET("/upgrade.php").Handle(wrap(r.compatHandler.Upgrade))
}
// ================ Manage API (v2) ================
- apiv2 := e.Group("/api/v2/")
+ apiv2 := e.Routes().Group("/api/v2/")
{
- apiv2.POST("/users", r.Wrap(r.apiHandler.CreateUser))
- apiv2.GET("/users/:uid", r.Wrap(r.apiHandler.GetUser))
- apiv2.PATCH("/users/:uid", r.Wrap(r.apiHandler.UpdateUser))
+ apiv2.POST("/users").Handle(wrap(r.apiHandler.CreateUser))
+ apiv2.GET("/users/:uid").Handle(wrap(r.apiHandler.GetUser))
+ apiv2.PATCH("/users/:uid").Handle(wrap(r.apiHandler.UpdateUser))
- apiv2.GET("/users/:uid/keys", r.Wrap(r.apiHandler.ListUserKeys))
- apiv2.POST("/users/:uid/keys", r.Wrap(r.apiHandler.CreateUserKey))
- apiv2.GET("/users/:uid/keys/current", r.Wrap(r.apiHandler.GetCurrentUserKey))
- apiv2.GET("/users/:uid/keys/:kid", r.Wrap(r.apiHandler.GetUserKey))
- apiv2.PATCH("/users/:uid/keys/:kid", r.Wrap(r.apiHandler.UpdateUserKey))
- apiv2.DELETE("/users/:uid/keys/:kid", r.Wrap(r.apiHandler.DeleteUserKey))
+ apiv2.GET("/users/:uid/keys").Handle(wrap(r.apiHandler.ListUserKeys))
+ apiv2.POST("/users/:uid/keys").Handle(wrap(r.apiHandler.CreateUserKey))
+ apiv2.GET("/users/:uid/keys/current").Handle(wrap(r.apiHandler.GetCurrentUserKey))
+ apiv2.GET("/users/:uid/keys/:kid").Handle(wrap(r.apiHandler.GetUserKey))
+ apiv2.PATCH("/users/:uid/keys/:kid").Handle(wrap(r.apiHandler.UpdateUserKey))
+ apiv2.DELETE("/users/:uid/keys/:kid").Handle(wrap(r.apiHandler.DeleteUserKey))
- apiv2.GET("/users/:uid/clients", r.Wrap(r.apiHandler.ListClients))
- apiv2.GET("/users/:uid/clients/:cid", r.Wrap(r.apiHandler.GetClient))
- apiv2.PATCH("/users/:uid/clients/:cid", r.Wrap(r.apiHandler.UpdateClient))
- apiv2.POST("/users/:uid/clients", r.Wrap(r.apiHandler.AddClient))
- apiv2.DELETE("/users/:uid/clients/:cid", r.Wrap(r.apiHandler.DeleteClient))
+ apiv2.GET("/users/:uid/clients").Handle(wrap(r.apiHandler.ListClients))
+ apiv2.GET("/users/:uid/clients/:cid").Handle(wrap(r.apiHandler.GetClient))
+ apiv2.PATCH("/users/:uid/clients/:cid").Handle(wrap(r.apiHandler.UpdateClient))
+ apiv2.POST("/users/:uid/clients").Handle(wrap(r.apiHandler.AddClient))
+ apiv2.DELETE("/users/:uid/clients/:cid").Handle(wrap(r.apiHandler.DeleteClient))
- apiv2.GET("/users/:uid/channels", r.Wrap(r.apiHandler.ListChannels))
- apiv2.POST("/users/:uid/channels", r.Wrap(r.apiHandler.CreateChannel))
- apiv2.GET("/users/:uid/channels/:cid", r.Wrap(r.apiHandler.GetChannel))
- apiv2.PATCH("/users/:uid/channels/:cid", r.Wrap(r.apiHandler.UpdateChannel))
- apiv2.GET("/users/:uid/channels/:cid/messages", r.Wrap(r.apiHandler.ListChannelMessages))
- apiv2.GET("/users/:uid/channels/:cid/subscriptions", r.Wrap(r.apiHandler.ListChannelSubscriptions))
+ apiv2.GET("/users/:uid/channels").Handle(wrap(r.apiHandler.ListChannels))
+ apiv2.POST("/users/:uid/channels").Handle(wrap(r.apiHandler.CreateChannel))
+ apiv2.GET("/users/:uid/channels/:cid").Handle(wrap(r.apiHandler.GetChannel))
+ apiv2.PATCH("/users/:uid/channels/:cid").Handle(wrap(r.apiHandler.UpdateChannel))
+ apiv2.GET("/users/:uid/channels/:cid/messages").Handle(wrap(r.apiHandler.ListChannelMessages))
+ apiv2.GET("/users/:uid/channels/:cid/subscriptions").Handle(wrap(r.apiHandler.ListChannelSubscriptions))
- apiv2.GET("/users/:uid/subscriptions", r.Wrap(r.apiHandler.ListUserSubscriptions))
- apiv2.POST("/users/:uid/subscriptions", r.Wrap(r.apiHandler.CreateSubscription))
- apiv2.GET("/users/:uid/subscriptions/:sid", r.Wrap(r.apiHandler.GetSubscription))
- apiv2.DELETE("/users/:uid/subscriptions/:sid", r.Wrap(r.apiHandler.CancelSubscription))
- apiv2.PATCH("/users/:uid/subscriptions/:sid", r.Wrap(r.apiHandler.UpdateSubscription))
+ apiv2.GET("/users/:uid/subscriptions").Handle(wrap(r.apiHandler.ListUserSubscriptions))
+ apiv2.POST("/users/:uid/subscriptions").Handle(wrap(r.apiHandler.CreateSubscription))
+ apiv2.GET("/users/:uid/subscriptions/:sid").Handle(wrap(r.apiHandler.GetSubscription))
+ apiv2.DELETE("/users/:uid/subscriptions/:sid").Handle(wrap(r.apiHandler.CancelSubscription))
+ apiv2.PATCH("/users/:uid/subscriptions/:sid").Handle(wrap(r.apiHandler.UpdateSubscription))
- apiv2.GET("/messages", r.Wrap(r.apiHandler.ListMessages))
- apiv2.GET("/messages/:mid", r.Wrap(r.apiHandler.GetMessage))
- apiv2.DELETE("/messages/:mid", r.Wrap(r.apiHandler.DeleteMessage))
+ apiv2.GET("/messages").Handle(wrap(r.apiHandler.ListMessages))
+ apiv2.GET("/messages/:mid").Handle(wrap(r.apiHandler.GetMessage))
+ apiv2.DELETE("/messages/:mid").Handle(wrap(r.apiHandler.DeleteMessage))
- apiv2.GET("/preview/users/:uid", r.Wrap(r.apiHandler.GetUserPreview))
- apiv2.GET("/preview/keys/:kid", r.Wrap(r.apiHandler.GetUserKeyPreview))
- apiv2.GET("/preview/channels/:cid", r.Wrap(r.apiHandler.GetChannelPreview))
+ apiv2.GET("/preview/users/:uid").Handle(wrap(r.apiHandler.GetUserPreview))
+ apiv2.GET("/preview/keys/:kid").Handle(wrap(r.apiHandler.GetUserKeyPreview))
+ apiv2.GET("/preview/channels/:cid").Handle(wrap(r.apiHandler.GetChannelPreview))
}
// ================ Send API (unversioned) ================
- sendAPI := e.Group("")
+ sendAPI := e.Routes().Group("")
{
- sendAPI.POST("/", r.Wrap(r.messageHandler.SendMessage))
- sendAPI.POST("/send", r.Wrap(r.messageHandler.SendMessage))
- sendAPI.POST("/send.php", r.Wrap(r.compatHandler.SendMessage))
+ sendAPI.POST("/").Handle(wrap(r.messageHandler.SendMessage)
+ sendAPI.POST("/send").Handle(wrap(r.messageHandler.SendMessage)
+ sendAPI.POST("/send.php").Handle(wrap(r.compatHandler.SendMessage)
- sendAPI.POST("/external/v1/uptime-kuma", r.Wrap(r.externalHandler.UptimeKuma))
+ sendAPI.POST("/external/v1/uptime-kuma").Handle(wrap(r.externalHandler.UptimeKuma)
}
// ================
if r.app.Config.ReturnRawErrors {
- e.NoRoute(r.Wrap(r.commonHandler.NoRoute))
+ e.NoRoute(r.commonHandler.NoRoute)
}
// ================
return nil
}
-
-func (r *Router) Wrap(fn ginresp.WHandlerFunc) gin.HandlerFunc {
- return ginresp.Wrap(r.app, fn)
-}
diff --git a/scnserver/api/ginresp/wrapper.go b/scnserver/api/wrapper.go
similarity index 75%
rename from scnserver/api/ginresp/wrapper.go
rename to scnserver/api/wrapper.go
index 3994a98..73111fb 100644
--- a/scnserver/api/ginresp/wrapper.go
+++ b/scnserver/api/wrapper.go
@@ -1,33 +1,33 @@
-package ginresp
+package api
import (
scn "blackforestbytes.com/simplecloudnotifier"
"blackforestbytes.com/simplecloudnotifier/api/apierr"
+ "blackforestbytes.com/simplecloudnotifier/api/ginresp"
"blackforestbytes.com/simplecloudnotifier/models"
"errors"
"fmt"
"github.com/gin-gonic/gin"
- "github.com/mattn/go-sqlite3"
+ "github.com/glebarez/go-sqlite"
"github.com/rs/zerolog/log"
"gogs.mikescher.com/BlackForestBytes/goext/dataext"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"math/rand"
"runtime/debug"
"time"
)
-type WHandlerFunc func(*gin.Context) HTTPResponse
-
type RequestLogAcceptor interface {
InsertRequestLog(data models.RequestLog)
}
-func Wrap(rlacc RequestLogAcceptor, fn WHandlerFunc) gin.HandlerFunc {
+func Wrap(rlacc RequestLogAcceptor, fn ginext.WHandlerFunc) ginext.WHandlerFunc {
maxRetry := scn.Conf.RequestMaxRetry
retrySleep := scn.Conf.RequestRetrySleep
- return func(g *gin.Context) {
+ return func(pctx *ginext.PreContext) {
reqctx := g.Request.Context()
@@ -43,7 +43,7 @@ func Wrap(rlacc RequestLogAcceptor, fn WHandlerFunc) gin.HandlerFunc {
if panicObj != nil {
log.Error().Interface("panicObj", panicObj).Msg("Panic occured (in gin handler)")
log.Error().Msg(stackTrace)
- wrap = APIError(g, 500, apierr.PANIC, "A panic occured in the HTTP handler", errors.New(fmt.Sprintf("%+v\n\n@:\n%s", panicObj, stackTrace)))
+ wrap = ginresp.APIError(g, 500, apierr.PANIC, "A panic occured in the HTTP handler", errors.New(fmt.Sprintf("%+v\n\n@:\n%s", panicObj, stackTrace)))
}
if g.Writer.Written() {
@@ -70,9 +70,14 @@ func Wrap(rlacc RequestLogAcceptor, fn WHandlerFunc) gin.HandlerFunc {
rlacc.InsertRequestLog(createRequestLog(g, t0, ctr, wrap, nil))
}
- statuscode := wrap.Statuscode()
- if statuscode/100 != 2 {
- log.Warn().Str("url", g.Request.Method+"::"+g.Request.URL.String()).Msg(fmt.Sprintf("Request failed with statuscode %d", statuscode))
+ if scw, ok := wrap.(ginext.InspectableHTTPResponse); ok {
+
+ statuscode := scw.Statuscode()
+ if statuscode/100 != 2 {
+ log.Warn().Str("url", g.Request.Method+"::"+g.Request.URL.String()).Msg(fmt.Sprintf("Request failed with statuscode %d", statuscode))
+ }
+ } else {
+ log.Warn().Str("url", g.Request.Method+"::"+g.Request.URL.String()).Msg(fmt.Sprintf("Request failed with statuscode [unknown]"))
}
wrap.Write(g)
@@ -85,7 +90,7 @@ func Wrap(rlacc RequestLogAcceptor, fn WHandlerFunc) gin.HandlerFunc {
}
-func createRequestLog(g *gin.Context, t0 time.Time, ctr int, resp HTTPResponse, panicstr *string) models.RequestLog {
+func createRequestLog(g *gin.Context, t0 time.Time, ctr int, resp ginext.HTTPResponse, panicstr *string) models.RequestLog {
t1 := time.Now()
@@ -109,9 +114,11 @@ func createRequestLog(g *gin.Context, t0 time.Time, ctr int, resp HTTPResponse,
var strrespbody *string = nil
if resp != nil {
- respbody = resp.BodyString()
- if respbody != nil && len(*respbody) < scn.Conf.ReqLogMaxBodySize {
- strrespbody = respbody
+ if resp2, ok := resp.(ginext.InspectableHTTPResponse); ok {
+ respbody = resp2.BodyString(g)
+ if respbody != nil && len(*respbody) < scn.Conf.ReqLogMaxBodySize {
+ strrespbody = respbody
+ }
}
}
@@ -147,7 +154,7 @@ func createRequestLog(g *gin.Context, t0 time.Time, ctr int, resp HTTPResponse,
}
}
-func callPanicSafe(fn WHandlerFunc, g *gin.Context) (res HTTPResponse, stackTrace string, panicObj any) {
+func callPanicSafe(fn ginext.WHandlerFunc, g ginext.PreContext) (res ginext.HTTPResponse, stackTrace string, panicObj any) {
defer func() {
if rec := recover(); rec != nil {
res = nil
@@ -173,17 +180,14 @@ func resetBody(g *gin.Context) error {
return nil
}
-func isSqlite3Busy(r HTTPResponse) bool {
- if errwrap, ok := r.(*errorHTTPResponse); ok && errwrap != nil {
-
- if errors.Is(errwrap.error, sqlite3.ErrBusy) {
- return true
- }
-
- var s3err sqlite3.Error
- if errors.As(errwrap.error, &s3err) {
- if errors.Is(s3err.Code, sqlite3.ErrBusy) {
- return true
+func isSqlite3Busy(r ginext.HTTPResponse) bool {
+ if errwrap, ok := r.(interface{ Unwrap() error }); ok && errwrap != nil {
+ {
+ var s3err *sqlite.Error
+ if errors.As(errwrap.Unwrap(), &s3err) {
+ if s3err.Code() == 5 { // [5] == SQLITE_BUSY
+ return true
+ }
}
}
}
diff --git a/scnserver/cmd/dbhash/main.go b/scnserver/cmd/dbhash/main.go
index ca64535..f6e9015 100644
--- a/scnserver/cmd/dbhash/main.go
+++ b/scnserver/cmd/dbhash/main.go
@@ -4,7 +4,6 @@ import (
"blackforestbytes.com/simplecloudnotifier/db/schema"
"context"
"fmt"
- "github.com/mattn/go-sqlite3"
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
"gogs.mikescher.com/BlackForestBytes/goext/sq"
"time"
@@ -21,7 +20,7 @@ func main() {
fmt.Println()
for i := 2; i <= schema.PrimarySchemaVersion; i++ {
- h0, err := sq.HashMattnSqliteSchema(ctx, schema.PrimarySchema[i].SQL)
+ h0, err := sq.HashGoSqliteSchema(ctx, schema.PrimarySchema[i].SQL)
if err != nil {
h0 = "ERR"
}
@@ -29,7 +28,7 @@ func main() {
}
for i := 1; i <= schema.RequestsSchemaVersion; i++ {
- h0, err := sq.HashMattnSqliteSchema(ctx, schema.RequestsSchema[i].SQL)
+ h0, err := sq.HashGoSqliteSchema(ctx, schema.RequestsSchema[i].SQL)
if err != nil {
h0 = "ERR"
}
@@ -37,7 +36,7 @@ func main() {
}
for i := 1; i <= schema.LogsSchemaVersion; i++ {
- h0, err := sq.HashMattnSqliteSchema(ctx, schema.LogsSchema[i].SQL)
+ h0, err := sq.HashGoSqliteSchema(ctx, schema.LogsSchema[i].SQL)
if err != nil {
h0 = "ERR"
}
diff --git a/scnserver/cmd/scnserver/main.go b/scnserver/cmd/scnserver/main.go
index 204f658..5dc44e9 100644
--- a/scnserver/cmd/scnserver/main.go
+++ b/scnserver/cmd/scnserver/main.go
@@ -3,13 +3,14 @@ package main
import (
scn "blackforestbytes.com/simplecloudnotifier"
"blackforestbytes.com/simplecloudnotifier/api"
- "blackforestbytes.com/simplecloudnotifier/api/ginext"
"blackforestbytes.com/simplecloudnotifier/google"
"blackforestbytes.com/simplecloudnotifier/jobs"
"blackforestbytes.com/simplecloudnotifier/logic"
"blackforestbytes.com/simplecloudnotifier/push"
"fmt"
"github.com/rs/zerolog/log"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
+ "gogs.mikescher.com/BlackForestBytes/goext/langext"
)
func main() {
@@ -31,7 +32,12 @@ func main() {
return
}
- ginengine := ginext.NewEngine(conf)
+ ginengine := ginext.NewEngine(ginext.Options{
+ AllowCors: &conf.Cors,
+ GinDebug: &conf.GinDebug,
+ BufferBody: langext.PTrue,
+ Timeout: &conf.RequestTimeout,
+ })
router := api.NewRouter(app)
diff --git a/scnserver/db/impl/logs/database.go b/scnserver/db/impl/logs/database.go
index 0863ec9..f12aefa 100644
--- a/scnserver/db/impl/logs/database.go
+++ b/scnserver/db/impl/logs/database.go
@@ -9,8 +9,8 @@ import (
"database/sql"
"errors"
"fmt"
+ "github.com/glebarez/go-sqlite"
"github.com/jmoiron/sqlx"
- _ "github.com/mattn/go-sqlite3"
"github.com/rs/zerolog/log"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/sq"
@@ -28,6 +28,10 @@ func NewLogsDatabase(cfg server.Config) (*Database, error) {
url := fmt.Sprintf("file:%s?_journal=%s&_timeout=%d&_fk=%s&_busy_timeout=%d", conf.File, conf.Journal, conf.Timeout.Milliseconds(), langext.FormatBool(conf.CheckForeignKeys, "true", "false"), conf.BusyTimeout.Milliseconds())
+ if !langext.InArray("sqlite3", sql.Drivers()) {
+ sqlite.RegisterAsSQLITE3()
+ }
+
xdb, err := sqlx.Open("sqlite3", url)
if err != nil {
return nil, err
diff --git a/scnserver/db/impl/primary/database.go b/scnserver/db/impl/primary/database.go
index 52ad6e9..0b835d9 100644
--- a/scnserver/db/impl/primary/database.go
+++ b/scnserver/db/impl/primary/database.go
@@ -9,8 +9,8 @@ import (
"database/sql"
"errors"
"fmt"
+ "github.com/glebarez/go-sqlite"
"github.com/jmoiron/sqlx"
- _ "github.com/mattn/go-sqlite3"
"github.com/rs/zerolog/log"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/sq"
@@ -28,6 +28,10 @@ func NewPrimaryDatabase(cfg server.Config) (*Database, error) {
url := fmt.Sprintf("file:%s?_journal=%s&_timeout=%d&_fk=%s&_busy_timeout=%d", conf.File, conf.Journal, conf.Timeout.Milliseconds(), langext.FormatBool(conf.CheckForeignKeys, "true", "false"), conf.BusyTimeout.Milliseconds())
+ if !langext.InArray("sqlite3", sql.Drivers()) {
+ sqlite.RegisterAsSQLITE3()
+ }
+
xdb, err := sqlx.Open("sqlite3", url)
if err != nil {
return nil, err
diff --git a/scnserver/db/impl/requests/database.go b/scnserver/db/impl/requests/database.go
index 283bf5f..9dea758 100644
--- a/scnserver/db/impl/requests/database.go
+++ b/scnserver/db/impl/requests/database.go
@@ -9,8 +9,8 @@ import (
"database/sql"
"errors"
"fmt"
+ "github.com/glebarez/go-sqlite"
"github.com/jmoiron/sqlx"
- _ "github.com/mattn/go-sqlite3"
"github.com/rs/zerolog/log"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/sq"
@@ -28,6 +28,10 @@ func NewRequestsDatabase(cfg server.Config) (*Database, error) {
url := fmt.Sprintf("file:%s?_journal=%s&_timeout=%d&_fk=%s&_busy_timeout=%d", conf.File, conf.Journal, conf.Timeout.Milliseconds(), langext.FormatBool(conf.CheckForeignKeys, "true", "false"), conf.BusyTimeout.Milliseconds())
+ if !langext.InArray("sqlite3", sql.Drivers()) {
+ sqlite.RegisterAsSQLITE3()
+ }
+
xdb, err := sqlx.Open("sqlite3", url)
if err != nil {
return nil, err
@@ -92,7 +96,7 @@ func (db *Database) Migrate(outerctx context.Context) error {
schemastr := schema.RequestsSchema[schema.RequestsSchemaVersion].SQL
schemahash := schema.RequestsSchema[schema.RequestsSchemaVersion].Hash
- schemahash, err := sq.HashMattnSqliteSchema(tctx, schemastr)
+ schemahash, err := sq.HashGoSqliteSchema(tctx, schemastr)
if err != nil {
return err
}
diff --git a/scnserver/go.mod b/scnserver/go.mod
index c5d28ea..dd9b986 100644
--- a/scnserver/go.mod
+++ b/scnserver/go.mod
@@ -6,31 +6,33 @@ toolchain go1.22.3
require (
github.com/gin-gonic/gin v1.10.0
- github.com/go-playground/validator/v10 v10.20.0
+ github.com/glebarez/go-sqlite v1.22.0
+ github.com/go-playground/validator/v10 v10.22.0
github.com/go-sql-driver/mysql v1.8.1
github.com/jmoiron/sqlx v1.4.0
github.com/mattn/go-sqlite3 v1.14.22
github.com/rs/zerolog v1.33.0
- gogs.mikescher.com/BlackForestBytes/goext v0.0.463
+ gogs.mikescher.com/BlackForestBytes/goext v0.0.482
gopkg.in/loremipsum.v1 v1.1.2
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
- github.com/bytedance/sonic v1.11.8 // indirect
+ github.com/bytedance/sonic v1.11.9 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
+ github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.4 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
- github.com/google/go-cmp v0.5.9 // indirect
+ github.com/google/uuid v1.5.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
- github.com/klauspost/compress v1.17.8 // indirect
- github.com/klauspost/cpuid/v2 v2.2.7 // indirect
+ github.com/klauspost/compress v1.17.9 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
@@ -38,6 +40,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
+ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
@@ -45,14 +48,18 @@ require (
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 // indirect
- go.mongodb.org/mongo-driver v1.15.0 // indirect
+ go.mongodb.org/mongo-driver v1.16.0 // indirect
golang.org/x/arch v0.8.0 // indirect
- golang.org/x/crypto v0.23.0 // indirect
- golang.org/x/net v0.25.0 // indirect
+ golang.org/x/crypto v0.25.0 // indirect
+ golang.org/x/net v0.27.0 // indirect
golang.org/x/sync v0.7.0 // indirect
- golang.org/x/sys v0.20.0 // indirect
- golang.org/x/term v0.20.0 // indirect
- golang.org/x/text v0.15.0 // indirect
- google.golang.org/protobuf v1.34.1 // indirect
+ golang.org/x/sys v0.22.0 // indirect
+ golang.org/x/term v0.22.0 // indirect
+ golang.org/x/text v0.16.0 // indirect
+ google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+ modernc.org/libc v1.37.6 // indirect
+ modernc.org/mathutil v1.6.0 // indirect
+ modernc.org/memory v1.7.2 // indirect
+ modernc.org/sqlite v1.28.0 // indirect
)
diff --git a/scnserver/go.sum b/scnserver/go.sum
index d35a87d..5a9c70a 100644
--- a/scnserver/go.sum
+++ b/scnserver/go.sum
@@ -1,7 +1,7 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
-github.com/bytedance/sonic v1.11.8 h1:Zw/j1KfiS+OYTi9lyB3bb0CFxPJVkM17k1wyDG32LRA=
-github.com/bytedance/sonic v1.11.8/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
+github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg=
+github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
@@ -28,8 +28,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
-github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
+github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
@@ -37,20 +37,22 @@ github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
+github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
-github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
-github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
+github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
@@ -107,23 +109,23 @@ github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gi
github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 h1:tBiBTKHnIjovYoLX/TPkcf+OjqqKGQrPtGT3Foz+Pgo=
github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76/go.mod h1:SQliXeA7Dhkt//vS29v3zpbEwoa+zb2Cn5xj5uO4K5U=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc=
-go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
-gogs.mikescher.com/BlackForestBytes/goext v0.0.463 h1:1sdU/jI7gzzucKv3CBefT1Hk5frGAYvgl/ItC9PdoqA=
-gogs.mikescher.com/BlackForestBytes/goext v0.0.463/go.mod h1:ZEaw70t0Wx044Ifkt8fcDHO/KtD3dwgxclX3OF6ElvA=
+go.mongodb.org/mongo-driver v1.16.0 h1:tpRsfBJMROVHKpdGyc1BBEzzjDUWjItxbVSZ8Ls4BQ4=
+go.mongodb.org/mongo-driver v1.16.0/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw=
+gogs.mikescher.com/BlackForestBytes/goext v0.0.482 h1:veU8oJdGZ9rjLB8sluagBduiBs3BbEDf60sGmEEv8lk=
+gogs.mikescher.com/BlackForestBytes/goext v0.0.482/go.mod h1:GxqLkJwPWQB5lVgWhmBPnx9RC+F0Dvi2xHKwfCmCQgM=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
-golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
+golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
-golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
+golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
@@ -137,24 +139,24 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
-golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
-golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
+golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
-google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/loremipsum.v1 v1.1.2 h1:12APklfJKuGszqZsrArW5QoQh03/W+qyCCjvnDuS6Tw=
diff --git a/scnserver/logic/appcontext.go b/scnserver/logic/appcontext.go
index 75a86c8..92c50c4 100644
--- a/scnserver/logic/appcontext.go
+++ b/scnserver/logic/appcontext.go
@@ -9,6 +9,7 @@ import (
"errors"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/sq"
"time"
)
@@ -81,7 +82,7 @@ func (ac *AppContext) RequestURI() string {
}
}
-func (ac *AppContext) FinishSuccess(res ginresp.HTTPResponse) ginresp.HTTPResponse {
+func (ac *AppContext) FinishSuccess(res ginext.HTTPResponse) ginext.HTTPResponse {
if ac.cancelled {
panic("Cannot finish a cancelled request")
}
diff --git a/scnserver/logic/application.go b/scnserver/logic/application.go
index 6d058e4..620b6aa 100644
--- a/scnserver/logic/application.go
+++ b/scnserver/logic/application.go
@@ -4,6 +4,7 @@ import (
scn "blackforestbytes.com/simplecloudnotifier"
"blackforestbytes.com/simplecloudnotifier/api/apierr"
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
+ "blackforestbytes.com/simplecloudnotifier/db"
"blackforestbytes.com/simplecloudnotifier/db/simplectx"
"blackforestbytes.com/simplecloudnotifier/google"
"blackforestbytes.com/simplecloudnotifier/models"
@@ -11,13 +12,12 @@ import (
"context"
"errors"
"github.com/gin-gonic/gin"
- "github.com/gin-gonic/gin/binding"
"github.com/rs/zerolog/log"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/rext"
"gogs.mikescher.com/BlackForestBytes/goext/syncext"
"net"
- "net/http"
"os"
"os/signal"
"regexp"
@@ -33,7 +33,7 @@ var rexCompatTitleChannel = rext.W(regexp.MustCompile("^\\[(?P[A-Za-z\\
type Application struct {
Config scn.Config
- Gin *gin.Engine
+ Gin *ginext.GinWrapper
Database *DBPool
Pusher push.NotificationClient
AndroidPublisher google.AndroidPublisherClient
@@ -53,7 +53,7 @@ func NewApp(db *DBPool) *Application {
}
}
-func (app *Application) Init(cfg scn.Config, g *gin.Engine, fb push.NotificationClient, apc google.AndroidPublisherClient, jobs []Job) {
+func (app *Application) Init(cfg scn.Config, g *ginext.GinWrapper, fb push.NotificationClient, apc google.AndroidPublisherClient, jobs []Job) {
app.Config = cfg
app.Gin = g
app.Pusher = fb
@@ -69,38 +69,17 @@ func (app *Application) Stop() {
}
func (app *Application) Run() {
- httpserver := &http.Server{
- Addr: net.JoinHostPort(app.Config.ServerIP, app.Config.ServerPort),
- Handler: app.Gin,
- }
- errChan := make(chan error)
+ // ================== START HTTP ==================
- go func() {
-
- ln, err := net.Listen("tcp", httpserver.Addr)
- if err != nil {
- errChan <- err
- return
- }
-
- _, port, err := net.SplitHostPort(ln.Addr().String())
- if err != nil {
- errChan <- err
- return
- }
-
- log.Info().Str("address", httpserver.Addr).Msg("HTTP-Server started on http://localhost:" + port)
+ addr := net.JoinHostPort(app.Config.ServerIP, app.Config.ServerPort)
+ errChan, httpserver := app.Gin.ListenAndServeHTTP(addr, func(port string) {
app.Port = port
+ app.IsRunning.Set(true)
+ })
- app.IsRunning.Set(true) // the net.Listener a few lines above is at this point actually already buffering requests
-
- errChan <- httpserver.Serve(ln)
- }()
-
- sigstop := make(chan os.Signal, 1)
- signal.Notify(sigstop, os.Interrupt, syscall.SIGTERM)
+ // ================== START JOBS ==================
for _, job := range app.Jobs {
err := job.Start()
@@ -109,6 +88,11 @@ func (app *Application) Run() {
}
}
+ // ================== LISTEN FOR SIGNALS ==================
+
+ sigstop := make(chan os.Signal, 1)
+ signal.Notify(sigstop, os.Interrupt, syscall.SIGTERM)
+
select {
case <-sigstop:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
@@ -127,7 +111,7 @@ func (app *Application) Run() {
case err := <-errChan:
log.Error().Err(err).Msg("HTTP-Server failed")
- case _ = <-app.stopChan:
+ case <-app.stopChan:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
@@ -142,20 +126,25 @@ func (app *Application) Run() {
}
}
+ // ================== STOP JOBS ==================
+
for _, job := range app.Jobs {
job.Stop()
}
- log.Info().Msg("Manually stopped Jobs")
+ // ================== STOP DB ==================
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
- defer cancel()
- err := app.Database.Stop(ctx)
- if err != nil {
- log.Info().Err(err).Msg("Error while stopping the database")
+ {
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+ err := app.Database.Stop(ctx)
+ if err != nil {
+ log.Err(err).Msg("Failed to stop database")
+ }
}
+ log.Info().Msg("Stopped Databases")
- log.Info().Msg("Manually closed database connection")
+ // ================== FINISH ==================
app.IsRunning.Set(false)
}
@@ -223,65 +212,26 @@ type RequestOptions struct {
IgnoreWrongContentType bool
}
-func (app *Application) StartRequest(g *gin.Context, uri any, query any, body any, form any, opts ...RequestOptions) (*AppContext, *ginresp.HTTPResponse) {
+func (app *Application) StartRequest(gectx *ginext.AppContext, g *gin.Context, r *ginext.HTTPResponse) (*AppContext, *gin.Context, *ginext.HTTPResponse) {
- ignoreWrongContentType := langext.ArrAny(opts, func(o RequestOptions) bool { return o.IgnoreWrongContentType })
-
- if uri != nil {
- if err := g.ShouldBindUri(uri); err != nil {
- return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_URI_PARAM, "Failed to read uri", err))
- }
+ if r != nil {
+ return nil, g, r
}
- if query != nil {
- if err := g.ShouldBindQuery(query); err != nil {
- return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_QUERY_PARAM, "Failed to read query", err))
- }
- }
-
- if body != nil {
- if g.ContentType() == "application/json" {
- if err := g.ShouldBindJSON(body); err != nil {
- return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "Failed to read body", err))
- }
- } else {
- if !ignoreWrongContentType {
- return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "missing JSON body", nil))
- }
- }
- }
-
- if form != nil {
- if g.ContentType() == "multipart/form-data" {
- if err := g.ShouldBindWith(form, binding.Form); err != nil {
- return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "Failed to read multipart-form", err))
- }
- } else if g.ContentType() == "application/x-www-form-urlencoded" {
- if err := g.ShouldBindWith(form, binding.Form); err != nil {
- return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "Failed to read urlencoded-form", err))
- }
- } else {
- if !ignoreWrongContentType {
- return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "missing form body", nil))
- }
- }
- }
-
- ictx, cancel := context.WithTimeout(context.Background(), app.Config.RequestTimeout)
- actx := CreateAppContext(app, g, ictx, cancel)
+ actx := CreateAppContext(app, g, gectx, gectx.Cancel)
authheader := g.GetHeader("Authorization")
perm, err := app.getPermissions(actx, authheader)
if err != nil {
- cancel()
- return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.PERM_QUERY_FAIL, "Failed to determine permissions", err))
+ gectx.Cancel()
+ return nil, g, langext.Ptr(ginresp.APIError(g, 400, apierr.PERM_QUERY_FAIL, "Failed to determine permissions", err))
}
actx.permissions = perm
g.Set("perm", perm)
- return actx, nil
+ return actx, g, nil
}
func (app *Application) NewSimpleTransactionContext(timeout time.Duration) *simplectx.SimpleContext {
@@ -289,7 +239,7 @@ func (app *Application) NewSimpleTransactionContext(timeout time.Duration) *simp
return simplectx.CreateSimpleContext(ictx, cancel)
}
-func (app *Application) getPermissions(ctx *AppContext, hdr string) (models.PermissionSet, error) {
+func (app *Application) getPermissions(ctx db.TxContext, hdr string) (models.PermissionSet, error) {
if hdr == "" {
return models.NewEmptyPermissions(), nil
}
diff --git a/scnserver/logic/message.go b/scnserver/logic/message.go
index bb792c3..de4617e 100644
--- a/scnserver/logic/message.go
+++ b/scnserver/logic/message.go
@@ -24,7 +24,7 @@ type SendMessageResponse struct {
CompatMessageID int64
}
-func (app *Application) SendMessage(g *gin.Context, ctx *AppContext, UserID *models.UserID, Key *string, Channel *string, Title *string, Content *string, Priority *int, UserMessageID *string, SendTimestamp *float64, SenderName *string) (*SendMessageResponse, *ginresp.HTTPResponse) {
+func (app *Application) SendMessage(g *gin.Context, ctx *AppContext, UserID *models.UserID, Key *string, Channel *string, Title *string, Content *string, Priority *int, UserMessageID *string, SendTimestamp *float64, SenderName *string) (*SendMessageResponse, *ginext.HTTPResponse) {
if Title != nil {
Title = langext.Ptr(strings.TrimSpace(*Title))
}
diff --git a/scnserver/logic/permissions.go b/scnserver/logic/permissions.go
index bcc873c..e9d48cf 100644
--- a/scnserver/logic/permissions.go
+++ b/scnserver/logic/permissions.go
@@ -9,7 +9,7 @@ import (
"gogs.mikescher.com/BlackForestBytes/goext/langext"
)
-func (ac *AppContext) CheckPermissionUserRead(userid models.UserID) *ginresp.HTTPResponse {
+func (ac *AppContext) CheckPermissionUserRead(userid models.UserID) *ginext.HTTPResponse {
p := ac.permissions
if p.Token != nil && p.Token.IsUserRead(userid) {
return nil
@@ -18,7 +18,7 @@ func (ac *AppContext) CheckPermissionUserRead(userid models.UserID) *ginresp.HTT
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
-func (ac *AppContext) CheckPermissionSelfAllMessagesRead() *ginresp.HTTPResponse {
+func (ac *AppContext) CheckPermissionSelfAllMessagesRead() *ginext.HTTPResponse {
p := ac.permissions
if p.Token != nil && p.Token.IsAllMessagesRead(p.Token.OwnerUserID) {
return nil
@@ -27,7 +27,7 @@ func (ac *AppContext) CheckPermissionSelfAllMessagesRead() *ginresp.HTTPResponse
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
-func (ac *AppContext) CheckPermissionAllMessagesRead(userid models.UserID) *ginresp.HTTPResponse {
+func (ac *AppContext) CheckPermissionAllMessagesRead(userid models.UserID) *ginext.HTTPResponse {
p := ac.permissions
if p.Token != nil && p.Token.IsAllMessagesRead(userid) {
return nil
@@ -36,7 +36,7 @@ func (ac *AppContext) CheckPermissionAllMessagesRead(userid models.UserID) *ginr
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
-func (ac *AppContext) CheckPermissionChanMessagesRead(channel models.Channel) *ginresp.HTTPResponse {
+func (ac *AppContext) CheckPermissionChanMessagesRead(channel models.Channel) *ginext.HTTPResponse {
p := ac.permissions
if p.Token != nil && p.Token.IsChannelMessagesRead(channel.ChannelID) {
@@ -63,7 +63,7 @@ func (ac *AppContext) CheckPermissionChanMessagesRead(channel models.Channel) *g
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
-func (ac *AppContext) CheckPermissionUserAdmin(userid models.UserID) *ginresp.HTTPResponse {
+func (ac *AppContext) CheckPermissionUserAdmin(userid models.UserID) *ginext.HTTPResponse {
p := ac.permissions
if p.Token != nil && p.Token.IsAdmin(userid) {
return nil
@@ -72,7 +72,7 @@ func (ac *AppContext) CheckPermissionUserAdmin(userid models.UserID) *ginresp.HT
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
}
-func (ac *AppContext) CheckPermissionSend(channel models.Channel, key string) (*models.KeyToken, *ginresp.HTTPResponse) {
+func (ac *AppContext) CheckPermissionSend(channel models.Channel, key string) (*models.KeyToken, *ginext.HTTPResponse) {
keytok, err := ac.app.Database.Primary.GetKeyTokenByToken(ac, key)
if err != nil {
@@ -107,7 +107,7 @@ func (ac *AppContext) CheckPermissionMessageDelete(msg models.Message) bool {
return false
}
-func (ac *AppContext) CheckPermissionAny() *ginresp.HTTPResponse {
+func (ac *AppContext) CheckPermissionAny() *ginext.HTTPResponse {
p := ac.permissions
if p.Token == nil {
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
diff --git a/scnserver/models/enums_gen.go b/scnserver/models/enums_gen.go
index 6d1ef2f..7cec25e 100644
--- a/scnserver/models/enums_gen.go
+++ b/scnserver/models/enums_gen.go
@@ -5,7 +5,7 @@ package models
import "gogs.mikescher.com/BlackForestBytes/goext/langext"
import "gogs.mikescher.com/BlackForestBytes/goext/enums"
-const ChecksumEnumGenerator = "e500346e3f60b3abf78558ec3df128c3be2a1cefa71c4f1feba9293d14eb85d1" // GoExtVersion: 0.0.463
+const ChecksumEnumGenerator = "fd2e0463f7720d853f7a3394352c084ac7d086e9e012caa3d3d70a6e83749970" // GoExtVersion: 0.0.482
// ================================ ClientType ================================
//
diff --git a/scnserver/models/ids_gen.go b/scnserver/models/ids_gen.go
index a6dac6e..90df989 100644
--- a/scnserver/models/ids_gen.go
+++ b/scnserver/models/ids_gen.go
@@ -15,7 +15,7 @@ import "reflect"
import "regexp"
import "strings"
-const ChecksumCharsetIDGenerator = "e500346e3f60b3abf78558ec3df128c3be2a1cefa71c4f1feba9293d14eb85d1" // GoExtVersion: 0.0.463
+const ChecksumCharsetIDGenerator = "fd2e0463f7720d853f7a3394352c084ac7d086e9e012caa3d3d70a6e83749970" // GoExtVersion: 0.0.482
const idlen = 24
diff --git a/scnserver/swagger/swagger.go b/scnserver/swagger/swagger.go
index deb123f..8b63917 100644
--- a/scnserver/swagger/swagger.go
+++ b/scnserver/swagger/swagger.go
@@ -1,10 +1,10 @@
package swagger
import (
- "blackforestbytes.com/simplecloudnotifier/api/ginresp"
"embed"
_ "embed"
"github.com/gin-gonic/gin"
+ "gogs.mikescher.com/BlackForestBytes/goext/ginext"
"net/http"
"strings"
)
@@ -46,26 +46,28 @@ func getAsset(fn string) ([]byte, string, bool) {
return data, mime, true
}
-func Handle(g *gin.Context) ginresp.HTTPResponse {
+func Handle(pctx ginext.PreContext) ginext.HTTPResponse {
type uri struct {
Filename string `uri:"sub"`
}
var u uri
- if err := g.ShouldBindUri(&u); err != nil {
- return ginresp.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ ctx, _, errResp := pctx.URI(&u).Start()
+ if errResp != nil {
+ return *errResp
}
+ defer ctx.Cancel()
u.Filename = strings.TrimLeft(u.Filename, "/")
if u.Filename == "" {
index, _, _ := getAsset("index.html")
- return ginresp.Data(http.StatusOK, "text/html", index)
+ return ginext.Data(http.StatusOK, "text/html", index)
}
if data, mime, ok := getAsset(u.Filename); ok {
- return ginresp.Data(http.StatusOK, mime, data)
+ return ginext.Data(http.StatusOK, mime, data)
}
- return ginresp.JSON(http.StatusNotFound, gin.H{"error": "AssetNotFound", "filename": u.Filename})
+ return ginext.JSON(http.StatusNotFound, gin.H{"error": "AssetNotFound", "filename": u.Filename})
}
diff --git a/scnserver/swagger/swagger.json b/scnserver/swagger/swagger.json
index 03c7606..cd5657e 100644
--- a/scnserver/swagger/swagger.json
+++ b/scnserver/swagger/swagger.json
@@ -19,63 +19,39 @@
"parameters": [
{
"type": "string",
- "example": "test",
- "name": "channel",
- "in": "query"
- },
- {
- "type": "string",
- "example": "This is a message",
"name": "content",
"in": "query"
},
{
"type": "string",
- "example": "P3TNH8mvv14fm",
- "name": "key",
- "in": "query"
- },
- {
- "type": "string",
- "example": "db8b0e6a-a08c-4646",
"name": "msg_id",
"in": "query"
},
{
- "enum": [
- 0,
- 1,
- 2
- ],
"type": "integer",
- "example": 1,
"name": "priority",
"in": "query"
},
- {
- "type": "string",
- "example": "example-server",
- "name": "sender_name",
- "in": "query"
- },
{
"type": "number",
- "example": 1669824037,
"name": "timestamp",
"in": "query"
},
{
"type": "string",
- "example": "Hello World",
"name": "title",
"in": "query"
},
{
- "type": "string",
- "example": "7725",
+ "type": "integer",
"name": "user_id",
"in": "query"
},
+ {
+ "type": "string",
+ "name": "user_key",
+ "in": "query"
+ },
{
"description": " ",
"name": "post_body",
@@ -86,62 +62,38 @@
},
{
"type": "string",
- "example": "test",
- "name": "channel",
- "in": "formData"
- },
- {
- "type": "string",
- "example": "This is a message",
"name": "content",
"in": "formData"
},
{
"type": "string",
- "example": "P3TNH8mvv14fm",
- "name": "key",
- "in": "formData"
- },
- {
- "type": "string",
- "example": "db8b0e6a-a08c-4646",
"name": "msg_id",
"in": "formData"
},
{
- "enum": [
- 0,
- 1,
- 2
- ],
"type": "integer",
- "example": 1,
"name": "priority",
"in": "formData"
},
- {
- "type": "string",
- "example": "example-server",
- "name": "sender_name",
- "in": "formData"
- },
{
"type": "number",
- "example": 1669824037,
"name": "timestamp",
"in": "formData"
},
{
"type": "string",
- "example": "Hello World",
"name": "title",
"in": "formData"
},
{
- "type": "string",
- "example": "7725",
+ "type": "integer",
"name": "user_id",
"in": "formData"
+ },
+ {
+ "type": "string",
+ "name": "user_key",
+ "in": "formData"
}
],
"responses": {
@@ -2765,63 +2717,39 @@
"parameters": [
{
"type": "string",
- "example": "test",
- "name": "channel",
- "in": "query"
- },
- {
- "type": "string",
- "example": "This is a message",
"name": "content",
"in": "query"
},
{
"type": "string",
- "example": "P3TNH8mvv14fm",
- "name": "key",
- "in": "query"
- },
- {
- "type": "string",
- "example": "db8b0e6a-a08c-4646",
"name": "msg_id",
"in": "query"
},
{
- "enum": [
- 0,
- 1,
- 2
- ],
"type": "integer",
- "example": 1,
"name": "priority",
"in": "query"
},
- {
- "type": "string",
- "example": "example-server",
- "name": "sender_name",
- "in": "query"
- },
{
"type": "number",
- "example": 1669824037,
"name": "timestamp",
"in": "query"
},
{
"type": "string",
- "example": "Hello World",
"name": "title",
"in": "query"
},
{
- "type": "string",
- "example": "7725",
+ "type": "integer",
"name": "user_id",
"in": "query"
},
+ {
+ "type": "string",
+ "name": "user_key",
+ "in": "query"
+ },
{
"description": " ",
"name": "post_body",
@@ -2832,62 +2760,38 @@
},
{
"type": "string",
- "example": "test",
- "name": "channel",
- "in": "formData"
- },
- {
- "type": "string",
- "example": "This is a message",
"name": "content",
"in": "formData"
},
{
"type": "string",
- "example": "P3TNH8mvv14fm",
- "name": "key",
- "in": "formData"
- },
- {
- "type": "string",
- "example": "db8b0e6a-a08c-4646",
"name": "msg_id",
"in": "formData"
},
{
- "enum": [
- 0,
- 1,
- 2
- ],
"type": "integer",
- "example": 1,
"name": "priority",
"in": "formData"
},
- {
- "type": "string",
- "example": "example-server",
- "name": "sender_name",
- "in": "formData"
- },
{
"type": "number",
- "example": 1669824037,
"name": "timestamp",
"in": "formData"
},
{
"type": "string",
- "example": "Hello World",
"name": "title",
"in": "formData"
},
{
- "type": "string",
- "example": "7725",
+ "type": "integer",
"name": "user_id",
"in": "formData"
+ },
+ {
+ "type": "string",
+ "name": "user_key",
+ "in": "formData"
}
],
"responses": {
@@ -2935,121 +2839,73 @@
"parameters": [
{
"type": "string",
- "example": "test",
- "name": "channel",
- "in": "query"
- },
- {
- "type": "string",
- "example": "This is a message",
"name": "content",
"in": "query"
},
{
"type": "string",
- "example": "P3TNH8mvv14fm",
- "name": "key",
- "in": "query"
- },
- {
- "type": "string",
- "example": "db8b0e6a-a08c-4646",
"name": "msg_id",
"in": "query"
},
{
- "enum": [
- 0,
- 1,
- 2
- ],
"type": "integer",
- "example": 1,
"name": "priority",
"in": "query"
},
- {
- "type": "string",
- "example": "example-server",
- "name": "sender_name",
- "in": "query"
- },
{
"type": "number",
- "example": 1669824037,
"name": "timestamp",
"in": "query"
},
{
"type": "string",
- "example": "Hello World",
"name": "title",
"in": "query"
},
{
- "type": "string",
- "example": "7725",
+ "type": "integer",
"name": "user_id",
"in": "query"
},
{
"type": "string",
- "example": "test",
- "name": "channel",
- "in": "formData"
+ "name": "user_key",
+ "in": "query"
},
{
"type": "string",
- "example": "This is a message",
"name": "content",
"in": "formData"
},
{
"type": "string",
- "example": "P3TNH8mvv14fm",
- "name": "key",
- "in": "formData"
- },
- {
- "type": "string",
- "example": "db8b0e6a-a08c-4646",
"name": "msg_id",
"in": "formData"
},
{
- "enum": [
- 0,
- 1,
- 2
- ],
"type": "integer",
- "example": 1,
"name": "priority",
"in": "formData"
},
- {
- "type": "string",
- "example": "example-server",
- "name": "sender_name",
- "in": "formData"
- },
{
"type": "number",
- "example": 1669824037,
"name": "timestamp",
"in": "formData"
},
{
"type": "string",
- "example": "Hello World",
"name": "title",
"in": "formData"
},
{
- "type": "string",
- "example": "7725",
+ "type": "integer",
"name": "user_id",
"in": "formData"
+ },
+ {
+ "type": "string",
+ "name": "user_key",
+ "in": "formData"
}
],
"responses": {
@@ -3545,46 +3401,26 @@
"handler.SendMessage.combined": {
"type": "object",
"properties": {
- "channel": {
- "type": "string",
- "example": "test"
- },
"content": {
- "type": "string",
- "example": "This is a message"
- },
- "key": {
- "type": "string",
- "example": "P3TNH8mvv14fm"
+ "type": "string"
},
"msg_id": {
- "type": "string",
- "example": "db8b0e6a-a08c-4646"
+ "type": "string"
},
"priority": {
- "type": "integer",
- "enum": [
- 0,
- 1,
- 2
- ],
- "example": 1
- },
- "sender_name": {
- "type": "string",
- "example": "example-server"
+ "type": "integer"
},
"timestamp": {
- "type": "number",
- "example": 1669824037
+ "type": "number"
},
"title": {
- "type": "string",
- "example": "Hello World"
+ "type": "string"
},
"user_id": {
- "type": "string",
- "example": "7725"
+ "type": "integer"
+ },
+ "user_key": {
+ "type": "string"
}
}
},
@@ -3613,7 +3449,7 @@
"type": "integer"
},
"scn_msg_id": {
- "type": "string"
+ "type": "integer"
},
"success": {
"type": "boolean"
diff --git a/scnserver/swagger/swagger.yaml b/scnserver/swagger/swagger.yaml
index 81046da..9a33c92 100644
--- a/scnserver/swagger/swagger.yaml
+++ b/scnserver/swagger/swagger.yaml
@@ -327,36 +327,19 @@ definitions:
type: object
handler.SendMessage.combined:
properties:
- channel:
- example: test
- type: string
content:
- example: This is a message
- type: string
- key:
- example: P3TNH8mvv14fm
type: string
msg_id:
- example: db8b0e6a-a08c-4646
type: string
priority:
- enum:
- - 0
- - 1
- - 2
- example: 1
type: integer
- sender_name:
- example: example-server
- type: string
timestamp:
- example: 1669824037
type: number
title:
- example: Hello World
type: string
user_id:
- example: "7725"
+ type: integer
+ user_key:
type: string
type: object
handler.SendMessage.response:
@@ -376,7 +359,7 @@ definitions:
quota_max:
type: integer
scn_msg_id:
- type: string
+ type: integer
success:
type: boolean
suppress_send:
@@ -802,90 +785,52 @@ paths:
description: All parameter can be set via query-parameter or the json body.
Only UserID, UserKey and Title are required
parameters:
- - example: test
- in: query
- name: channel
- type: string
- - example: This is a message
- in: query
+ - in: query
name: content
type: string
- - example: P3TNH8mvv14fm
- in: query
- name: key
- type: string
- - example: db8b0e6a-a08c-4646
- in: query
+ - in: query
name: msg_id
type: string
- - enum:
- - 0
- - 1
- - 2
- example: 1
- in: query
+ - in: query
name: priority
type: integer
- - example: example-server
- in: query
- name: sender_name
- type: string
- - example: 1669824037
- in: query
+ - in: query
name: timestamp
type: number
- - example: Hello World
- in: query
+ - in: query
name: title
type: string
- - example: "7725"
- in: query
+ - in: query
name: user_id
+ type: integer
+ - in: query
+ name: user_key
type: string
- description: ' '
in: body
name: post_body
schema:
$ref: '#/definitions/handler.SendMessage.combined'
- - example: test
- in: formData
- name: channel
- type: string
- - example: This is a message
- in: formData
+ - in: formData
name: content
type: string
- - example: P3TNH8mvv14fm
- in: formData
- name: key
- type: string
- - example: db8b0e6a-a08c-4646
- in: formData
+ - in: formData
name: msg_id
type: string
- - enum:
- - 0
- - 1
- - 2
- example: 1
- in: formData
+ - in: formData
name: priority
type: integer
- - example: example-server
- in: formData
- name: sender_name
- type: string
- - example: 1669824037
- in: formData
+ - in: formData
name: timestamp
type: number
- - example: Hello World
- in: formData
+ - in: formData
name: title
type: string
- - example: "7725"
- in: formData
+ - in: formData
name: user_id
+ type: integer
+ - in: formData
+ name: user_key
type: string
responses:
"200":
@@ -2685,90 +2630,52 @@ paths:
description: All parameter can be set via query-parameter or the json body.
Only UserID, UserKey and Title are required
parameters:
- - example: test
- in: query
- name: channel
- type: string
- - example: This is a message
- in: query
+ - in: query
name: content
type: string
- - example: P3TNH8mvv14fm
- in: query
- name: key
- type: string
- - example: db8b0e6a-a08c-4646
- in: query
+ - in: query
name: msg_id
type: string
- - enum:
- - 0
- - 1
- - 2
- example: 1
- in: query
+ - in: query
name: priority
type: integer
- - example: example-server
- in: query
- name: sender_name
- type: string
- - example: 1669824037
- in: query
+ - in: query
name: timestamp
type: number
- - example: Hello World
- in: query
+ - in: query
name: title
type: string
- - example: "7725"
- in: query
+ - in: query
name: user_id
+ type: integer
+ - in: query
+ name: user_key
type: string
- description: ' '
in: body
name: post_body
schema:
$ref: '#/definitions/handler.SendMessage.combined'
- - example: test
- in: formData
- name: channel
- type: string
- - example: This is a message
- in: formData
+ - in: formData
name: content
type: string
- - example: P3TNH8mvv14fm
- in: formData
- name: key
- type: string
- - example: db8b0e6a-a08c-4646
- in: formData
+ - in: formData
name: msg_id
type: string
- - enum:
- - 0
- - 1
- - 2
- example: 1
- in: formData
+ - in: formData
name: priority
type: integer
- - example: example-server
- in: formData
- name: sender_name
- type: string
- - example: 1669824037
- in: formData
+ - in: formData
name: timestamp
type: number
- - example: Hello World
- in: formData
+ - in: formData
name: title
type: string
- - example: "7725"
- in: formData
+ - in: formData
name: user_id
+ type: integer
+ - in: formData
+ name: user_key
type: string
responses:
"200":
@@ -2801,85 +2708,47 @@ paths:
description: All parameter can be set via query-parameter or form-data body.
Only UserID, UserKey and Title are required
parameters:
- - example: test
- in: query
- name: channel
- type: string
- - example: This is a message
- in: query
+ - in: query
name: content
type: string
- - example: P3TNH8mvv14fm
- in: query
- name: key
- type: string
- - example: db8b0e6a-a08c-4646
- in: query
+ - in: query
name: msg_id
type: string
- - enum:
- - 0
- - 1
- - 2
- example: 1
- in: query
+ - in: query
name: priority
type: integer
- - example: example-server
- in: query
- name: sender_name
- type: string
- - example: 1669824037
- in: query
+ - in: query
name: timestamp
type: number
- - example: Hello World
- in: query
+ - in: query
name: title
type: string
- - example: "7725"
- in: query
+ - in: query
name: user_id
+ type: integer
+ - in: query
+ name: user_key
type: string
- - example: test
- in: formData
- name: channel
- type: string
- - example: This is a message
- in: formData
+ - in: formData
name: content
type: string
- - example: P3TNH8mvv14fm
- in: formData
- name: key
- type: string
- - example: db8b0e6a-a08c-4646
- in: formData
+ - in: formData
name: msg_id
type: string
- - enum:
- - 0
- - 1
- - 2
- example: 1
- in: formData
+ - in: formData
name: priority
type: integer
- - example: example-server
- in: formData
- name: sender_name
- type: string
- - example: 1669824037
- in: formData
+ - in: formData
name: timestamp
type: number
- - example: Hello World
- in: formData
+ - in: formData
name: title
type: string
- - example: "7725"
- in: formData
+ - in: formData
name: user_id
+ type: integer
+ - in: formData
+ name: user_key
type: string
responses:
"200":
diff --git a/scnserver/test/util/log.go b/scnserver/test/util/log.go
index a84cd11..545b7c0 100644
--- a/scnserver/test/util/log.go
+++ b/scnserver/test/util/log.go
@@ -1,7 +1,6 @@
package util
import (
- "blackforestbytes.com/simplecloudnotifier/api/ginext"
"fmt"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
diff --git a/scnserver/test/util/webserver.go b/scnserver/test/util/webserver.go
index e15b5bd..2477eea 100644
--- a/scnserver/test/util/webserver.go
+++ b/scnserver/test/util/webserver.go
@@ -3,7 +3,6 @@ package util
import (
scn "blackforestbytes.com/simplecloudnotifier"
"blackforestbytes.com/simplecloudnotifier/api"
- "blackforestbytes.com/simplecloudnotifier/api/ginext"
"blackforestbytes.com/simplecloudnotifier/google"
"blackforestbytes.com/simplecloudnotifier/jobs"
"blackforestbytes.com/simplecloudnotifier/logic"