SimpleCloudNotifier/scnserver/api/handler/common.go

259 lines
6.5 KiB
Go
Raw Permalink Normal View History

2022-11-13 19:17:07 +01:00
package handler
import (
2022-11-23 20:21:49 +01:00
"blackforestbytes.com/simplecloudnotifier/api/apierr"
2022-12-20 13:55:09 +01:00
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
"blackforestbytes.com/simplecloudnotifier/db/simplectx"
2022-11-13 19:17:07 +01:00
"blackforestbytes.com/simplecloudnotifier/logic"
"blackforestbytes.com/simplecloudnotifier/models"
2022-11-13 19:17:07 +01:00
"bytes"
2022-11-23 19:32:23 +01:00
"errors"
2022-11-13 19:17:07 +01:00
"github.com/gin-gonic/gin"
"gogs.mikescher.com/BlackForestBytes/goext/ginext"
2022-11-24 12:53:27 +01:00
"gogs.mikescher.com/BlackForestBytes/goext/langext"
2022-11-23 20:21:49 +01:00
"gogs.mikescher.com/BlackForestBytes/goext/timeext"
2022-11-13 19:17:07 +01:00
"net/http"
2022-11-23 20:21:49 +01:00
"time"
2022-11-13 19:17:07 +01:00
)
type CommonHandler struct {
app *logic.Application
}
func NewCommonHandler(app *logic.Application) CommonHandler {
return CommonHandler{
app: app,
}
}
type pingResponse struct {
Message string `json:"message"`
Info pingResponseInfo `json:"info"`
}
type pingResponseInfo struct {
Method string `json:"method"`
Request string `json:"request"`
Headers map[string][]string `json:"headers"`
URI string `json:"uri"`
Address string `json:"addr"`
}
// Ping swaggerdoc
//
2023-04-21 21:45:16 +02:00
// @Summary Simple endpoint to test connection (any http method)
// @Tags Common
2022-11-23 19:32:23 +01:00
//
2023-04-21 21:45:16 +02:00
// @Success 200 {object} pingResponse
// @Failure 500 {object} ginresp.apiError
2022-11-23 19:32:23 +01:00
//
2023-04-21 21:45:16 +02:00
// @Router /api/ping [get]
// @Router /api/ping [post]
// @Router /api/ping [put]
// @Router /api/ping [delete]
// @Router /api/ping [patch]
func (h CommonHandler) Ping(pctx ginext.PreContext) ginext.HTTPResponse {
ctx, g, errResp := pctx.Start()
if errResp != nil {
return *errResp
}
defer ctx.Cancel()
return h.app.DoRequest(ctx, g, models.TLockRead, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
buf := new(bytes.Buffer)
_, _ = buf.ReadFrom(g.Request.Body)
resuestBody := buf.String()
return ginext.JSON(http.StatusOK, pingResponse{
Message: "Pong",
Info: pingResponseInfo{
Method: g.Request.Method,
Request: resuestBody,
Headers: g.Request.Header,
URI: g.Request.RequestURI,
Address: g.Request.RemoteAddr,
},
})
2022-11-13 19:17:07 +01:00
})
}
// DatabaseTest swaggerdoc
//
2023-04-21 21:45:16 +02:00
// @Summary Check for a working database connection
// @ID api-common-dbtest
// @Tags Common
2022-11-23 19:32:23 +01:00
//
2023-04-21 21:45:16 +02:00
// @Success 200 {object} handler.DatabaseTest.response
// @Failure 500 {object} ginresp.apiError
2022-11-23 19:32:23 +01:00
//
2023-04-21 21:45:16 +02:00
// @Router /api/db-test [post]
func (h CommonHandler) DatabaseTest(pctx ginext.PreContext) ginext.HTTPResponse {
2022-11-13 19:17:07 +01:00
type response struct {
Success bool `json:"success"`
LibVersion string `json:"libVersion"`
SourceID string `json:"sourceID"`
2022-11-13 19:17:07 +01:00
}
ctx, g, errResp := pctx.Start()
if errResp != nil {
return *errResp
}
defer ctx.Cancel()
return h.app.DoRequest(ctx, g, models.TLockRead, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
2022-11-13 19:17:07 +01:00
versionStr, sourceID, err := h.app.Database.Primary.Version(ctx)
if err != nil {
return ginresp.InternalError(err)
}
err = h.app.Database.Ping(ctx)
if err != nil {
return ginresp.InternalError(err)
}
return ginext.JSON(http.StatusOK, response{
Success: true,
LibVersion: versionStr,
SourceID: sourceID,
})
2022-11-13 19:17:07 +01:00
})
}
// Health swaggerdoc
//
2023-04-21 21:45:16 +02:00
// @Summary Server Health-checks
// @ID api-common-health
// @Tags Common
2022-11-23 19:32:23 +01:00
//
2023-04-21 21:45:16 +02:00
// @Success 200 {object} handler.Health.response
// @Failure 500 {object} ginresp.apiError
2022-11-23 19:32:23 +01:00
//
2023-04-21 21:45:16 +02:00
// @Router /api/health [get]
func (h CommonHandler) Health(pctx ginext.PreContext) ginext.HTTPResponse {
2022-11-13 19:17:07 +01:00
type response struct {
Status string `json:"status"`
}
2022-11-23 19:32:23 +01:00
ctx, g, errResp := pctx.Start()
if errResp != nil {
return *errResp
}
defer ctx.Cancel()
2022-11-24 12:53:27 +01:00
return h.app.DoRequest(ctx, g, models.TLockReadWrite, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
tctx := simplectx.CreateSimpleContext(ctx, nil)
2022-11-24 12:53:27 +01:00
err := h.app.Database.Ping(tctx)
if err != nil {
return ginresp.InternalError(err)
}
2022-11-24 12:53:27 +01:00
for _, subdb := range h.app.Database.List() {
uuidKey, _ := langext.NewHexUUID()
uuidWrite, _ := langext.NewHexUUID()
err = subdb.WriteMetaString(tctx, uuidKey, uuidWrite)
if err != nil {
return ginresp.InternalError(err)
}
uuidRead, err := subdb.ReadMetaString(tctx, uuidKey)
if err != nil {
return ginresp.InternalError(err)
}
if uuidRead == nil || uuidWrite != *uuidRead {
return ginresp.InternalError(errors.New("writing into DB was not consistent"))
}
err = subdb.DeleteMeta(tctx, uuidKey)
if err != nil {
return ginresp.InternalError(err)
}
}
2022-11-24 12:53:27 +01:00
return ginext.JSON(http.StatusOK, response{Status: "ok"})
2022-11-24 12:53:27 +01:00
})
2022-11-13 19:17:07 +01:00
}
2022-11-18 21:25:40 +01:00
2022-11-23 20:21:49 +01:00
// Sleep swaggerdoc
//
2023-04-21 21:45:16 +02:00
// @Summary Return 200 after x seconds
// @ID api-common-sleep
// @Tags Common
2022-11-23 20:21:49 +01:00
//
2023-04-21 21:45:16 +02:00
// @Param secs path number true "sleep delay (in seconds)"
2022-11-23 22:12:47 +01:00
//
2023-04-21 21:45:16 +02:00
// @Success 200 {object} handler.Sleep.response
// @Failure 400 {object} ginresp.apiError
// @Failure 500 {object} ginresp.apiError
2022-11-23 20:21:49 +01:00
//
2023-04-21 21:45:16 +02:00
// @Router /api/sleep/{secs} [post]
func (h CommonHandler) Sleep(pctx ginext.PreContext) ginext.HTTPResponse {
2022-11-23 20:21:49 +01:00
type uri struct {
Seconds float64 `uri:"secs"`
}
type response struct {
Start string `json:"start"`
End string `json:"end"`
Duration float64 `json:"duration"`
}
ctx, g, errResp := pctx.Start()
if errResp != nil {
return *errResp
}
defer ctx.Cancel()
return h.app.DoRequest(ctx, g, models.TLockRead, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
2022-11-23 20:21:49 +01:00
t0 := time.Now().Format(time.RFC3339Nano)
var u uri
if err := g.ShouldBindUri(&u); err != nil {
return ginresp.APIError(g, 400, apierr.BINDFAIL_URI_PARAM, "Failed to read uri", err)
}
time.Sleep(timeext.FromSeconds(u.Seconds))
2022-11-23 20:21:49 +01:00
t1 := time.Now().Format(time.RFC3339Nano)
2022-11-23 20:21:49 +01:00
return ginext.JSON(http.StatusOK, response{
Start: t0,
End: t1,
Duration: u.Seconds,
})
2022-11-23 20:21:49 +01:00
})
}
func (h CommonHandler) NoRoute(pctx ginext.PreContext) ginext.HTTPResponse {
ctx, g, errResp := pctx.Start()
if errResp != nil {
return *errResp
}
defer ctx.Cancel()
return h.app.DoRequest(ctx, g, models.TLockRead, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
return ginext.JSON(http.StatusNotFound, gin.H{
"": "================ ROUTE NOT FOUND ================",
"FullPath": g.FullPath(),
"Method": g.Request.Method,
"URL": g.Request.URL.String(),
"RequestURI": g.Request.RequestURI,
"Proto": g.Request.Proto,
"Header": g.Request.Header,
"~": "================ ROUTE NOT FOUND ================",
})
2022-11-18 21:25:40 +01:00
})
}