added template for new golang backend
This commit is contained in:
parent
bd11d7973c
commit
0e58a5c5f0
|
@ -0,0 +1,176 @@
|
|||
|
||||
|
||||
_build
|
||||
.run-data
|
||||
|
||||
DOCKER_GIT_INFO
|
||||
|
||||
|
||||
##############
|
||||
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/goland,macos,linux
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=goland,macos,linux
|
||||
|
||||
### GoLand ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### GoLand Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
# .idea/misc.xml
|
||||
# *.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
||||
.idea/**/sonarlint/
|
||||
|
||||
# SonarQube Plugin
|
||||
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
||||
.idea/**/sonarIssues.xml
|
||||
|
||||
# Markdown Navigator plugin
|
||||
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
||||
.idea/**/markdown-navigator.xml
|
||||
.idea/**/markdown-navigator-enh.xml
|
||||
.idea/**/markdown-navigator/
|
||||
|
||||
# Cache file creation bug
|
||||
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
||||
.idea/$CACHE_FILE$
|
||||
|
||||
# CodeStream plugin
|
||||
# https://plugins.jetbrains.com/plugin/12206-codestream
|
||||
.idea/codestream.xml
|
||||
|
||||
# Azure Toolkit for IntelliJ plugin
|
||||
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
|
||||
.idea/**/azureSettings.xml
|
||||
|
||||
### Linux ###
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### macOS Patch ###
|
||||
# iCloud generated files
|
||||
*.icloud
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/goland,macos,linux
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
|
@ -0,0 +1,11 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/server.iml" filepath="$PROJECT_DIR$/.idea/server.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,65 @@
|
|||
DOCKER_REPO=registry.blackforestbytes.com
|
||||
DOCKER_NAME=scn_server
|
||||
PORT=9090
|
||||
|
||||
NAMESPACE=$(shell git rev-parse --abbrev-ref HEAD)
|
||||
HASH=$(shell git rev-parse HEAD)
|
||||
|
||||
build:
|
||||
rm -f ./_build/scn_backend
|
||||
go build -v -o _build/scn_backend ./cmd/scnserver
|
||||
|
||||
run: build
|
||||
mkdir -p .run-data
|
||||
_build/scn_backend
|
||||
|
||||
build-docker:
|
||||
[ ! -f "DOCKER_GIT_INFO" ] || rm DOCKER_GIT_INFO
|
||||
git rev-parse --abbrev-ref HEAD >> DOCKER_GIT_INFO
|
||||
git rev-parse HEAD >> DOCKER_GIT_INFO
|
||||
git log -1 --format=%cd --date=iso >> DOCKER_GIT_INFO
|
||||
git config --get remote.origin.url >> DOCKER_GIT_INFO
|
||||
docker build \
|
||||
-t "$(DOCKER_NAME):$(HASH)" \
|
||||
-t "$(DOCKER_NAME):$(NAMESPACE)-latest" \
|
||||
-t "$(DOCKER_NAME):latest" \
|
||||
-t "$(DOCKER_REPO)/$(DOCKER_NAME):$(HASH)" \
|
||||
-t "$(DOCKER_REPO)/$(DOCKER_NAME):$(NAMESPACE)-latest" \
|
||||
-t "$(DOCKER_REPO)/$(DOCKER_NAME):latest" \
|
||||
.
|
||||
|
||||
build-swagger:
|
||||
which swag || go install github.com/swaggo/swag/cmd/swag@latest
|
||||
swag init -generalInfo api/router.go --output ./swagger/ --outputTypes "json,yaml"
|
||||
|
||||
run-docker-local:
|
||||
mkdir -p .run-data
|
||||
docker run --rm \
|
||||
--init \
|
||||
--env "CONF_NS=local" \
|
||||
--volume "$(shell pwd)/.run-data/docker-local:/data" \
|
||||
--network host \
|
||||
$(DOCKER_NAME):latest
|
||||
|
||||
inspect-docker:
|
||||
mkdir -p .run-data
|
||||
docker run -ti \
|
||||
--rm \
|
||||
--volume "$(shell pwd)/.run-data/docker-inspect:/data" \
|
||||
$(DOCKER_NAME):latest \
|
||||
bash
|
||||
|
||||
push-docker:
|
||||
docker image push "$(DOCKER_REPO)/$(DOCKER_NAME):$(HASH)"
|
||||
docker image push "$(DOCKER_REPO)/$(DOCKER_NAME):$(NAMESPACE)-latest"
|
||||
docker image push "$(DOCKER_REPO)/$(DOCKER_NAME):latest"
|
||||
|
||||
clean:
|
||||
rm -rf _build/*
|
||||
rm -rf .run-data/*
|
||||
git clean -fdx
|
||||
go clean
|
||||
|
||||
fmt:
|
||||
go fmt ./...
|
||||
swag fmt
|
|
@ -0,0 +1,30 @@
|
|||
package apierr
|
||||
|
||||
type APIError int
|
||||
|
||||
const (
|
||||
NO_ERROR APIError = 0000
|
||||
|
||||
MISSING_UID APIError = 1101
|
||||
MISSING_TOK APIError = 1102
|
||||
MISSING_TITLE APIError = 1103
|
||||
INVALID_PRIO APIError = 1104
|
||||
REQ_METHOD APIError = 1105
|
||||
|
||||
NO_TITLE APIError = 1201
|
||||
TITLE_TOO_LONG APIError = 1202
|
||||
CONTENT_TOO_LONG APIError = 1203
|
||||
USR_MSG_ID_TOO_LONG APIError = 1204
|
||||
TIMESTAMP_OUT_OF_RANGE APIError = 1205
|
||||
|
||||
USER_NOT_FOUND APIError = 1301
|
||||
USER_AUTH_FAILED APIError = 1302
|
||||
|
||||
NO_DEVICE_LINKED APIError = 1401
|
||||
|
||||
QUOTA_REACHED APIError = 2101
|
||||
|
||||
FIREBASE_COM_FAILED APIError = 9901
|
||||
FIREBASE_COM_ERRORED APIError = 9902
|
||||
INTERNAL_EXCEPTION APIError = 9903
|
||||
)
|
|
@ -0,0 +1,98 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"blackforestbytes.com/simplecloudnotifier/common/ginresp"
|
||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||
"bytes"
|
||||
"github.com/gin-gonic/gin"
|
||||
sqlite3 "github.com/mattn/go-sqlite3"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
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
|
||||
//
|
||||
// @Success 200 {object} pingResponse
|
||||
// @Failure 500 {object} ginresp.errBody
|
||||
// @Router /ping [get]
|
||||
// @Router /ping [post]
|
||||
// @Router /ping [put]
|
||||
// @Router /ping [delete]
|
||||
// @Router /ping [patch]
|
||||
func (h CommonHandler) Ping(g *gin.Context) ginresp.HTTPResponse {
|
||||
buf := new(bytes.Buffer)
|
||||
_, _ = buf.ReadFrom(g.Request.Body)
|
||||
resuestBody := buf.String()
|
||||
|
||||
return ginresp.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,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// DatabaseTest swaggerdoc
|
||||
//
|
||||
// @Success 200 {object} handler.DatabaseTest.response
|
||||
// @Failure 500 {object} ginresp.errBody
|
||||
// @Router /db-test [get]
|
||||
func (h CommonHandler) DatabaseTest(g *gin.Context) ginresp.HTTPResponse {
|
||||
type response struct {
|
||||
Success bool `json:"success"`
|
||||
LibVersion string `json:"libVersion"`
|
||||
LibVersionNumber int `json:"libVersionNumber"`
|
||||
SourceID string `json:"sourceID"`
|
||||
}
|
||||
|
||||
libVersion, libVersionNumber, sourceID := sqlite3.Version()
|
||||
|
||||
err := h.app.Database.Ping()
|
||||
if err != nil {
|
||||
return ginresp.InternalError(err)
|
||||
}
|
||||
|
||||
return ginresp.JSON(http.StatusOK, response{
|
||||
Success: true,
|
||||
LibVersion: libVersion,
|
||||
LibVersionNumber: libVersionNumber,
|
||||
SourceID: sourceID,
|
||||
})
|
||||
}
|
||||
|
||||
// Health swaggerdoc
|
||||
//
|
||||
// @Success 200 {object} handler.Health.response
|
||||
// @Failure 500 {object} ginresp.errBody
|
||||
// @Router /health [get]
|
||||
func (h CommonHandler) Health(*gin.Context) ginresp.HTTPResponse {
|
||||
type response struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
return ginresp.JSON(http.StatusOK, response{Status: "ok"})
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
||||
"blackforestbytes.com/simplecloudnotifier/api/models"
|
||||
"blackforestbytes.com/simplecloudnotifier/common/ginresp"
|
||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type CompatHandler struct {
|
||||
app *logic.Application
|
||||
}
|
||||
|
||||
func NewCompatHandler(app *logic.Application) CompatHandler {
|
||||
return CompatHandler{
|
||||
app: app,
|
||||
}
|
||||
}
|
||||
|
||||
// Register swaggerdoc
|
||||
//
|
||||
// @Summary Register a new account
|
||||
// @Param fcm_token query string true "the (android) fcm token"
|
||||
// @Param pro query string true "if the user is a paid account" Enums(true, false)
|
||||
// @Param pro_token query string true "the (android) IAP token"
|
||||
// @Success 200 {object} handler.Register.response
|
||||
// @Failure 500 {object} ginresp.internAPIError
|
||||
// @Router /register.php [get]
|
||||
func (h CompatHandler) Register(g *gin.Context) ginresp.HTTPResponse {
|
||||
type query struct {
|
||||
FCMToken string `form:"fcm_token"`
|
||||
Pro string `form:"pro"`
|
||||
ProToken string `form:"pro_token"`
|
||||
}
|
||||
type response struct {
|
||||
Success string `json:"success"`
|
||||
Message string `json:"message"`
|
||||
UserID string `json:"user_id"`
|
||||
UserKey string `json:"user_key"`
|
||||
QuotaUsed string `json:"quota"`
|
||||
QuotaMax string `json:"quota_max"`
|
||||
IsPro string `json:"is_pro"`
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
return ginresp.NotImplemented(0)
|
||||
}
|
||||
|
||||
// Info swaggerdoc
|
||||
//
|
||||
// @Summary Get information about the current user
|
||||
// @Param user_id query string true "the user_id"
|
||||
// @Param user_key query string true "the user_key"
|
||||
// @Success 200 {object} handler.Info.response
|
||||
// @Failure 500 {object} ginresp.internAPIError
|
||||
// @Router /info.php [get]
|
||||
func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
|
||||
type query struct {
|
||||
UserID string `form:"user_id"`
|
||||
UserKey string `form:"user_key"`
|
||||
}
|
||||
type response struct {
|
||||
Success string `json:"success"`
|
||||
Message string `json:"message"`
|
||||
UserID string `json:"user_id"`
|
||||
UserKey string `json:"user_key"`
|
||||
QuotaUsed string `json:"quota"`
|
||||
QuotaMax string `json:"quota_max"`
|
||||
IsPro string `json:"is_pro"`
|
||||
FCMSet bool `json:"fcm_token_set"`
|
||||
UnackCount int `json:"unack_count"`
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
return ginresp.NotImplemented(0)
|
||||
}
|
||||
|
||||
// Ack swaggerdoc
|
||||
//
|
||||
// @Summary Acknowledge that a message was received
|
||||
// @Param user_id query string true "the user_id"
|
||||
// @Param user_key query string true "the user_key"
|
||||
// @Param scn_msg_id query string true "the message id"
|
||||
// @Success 200 {object} handler.Ack.response
|
||||
// @Failure 500 {object} ginresp.internAPIError
|
||||
// @Router /ack.php [get]
|
||||
func (h CompatHandler) Ack(g *gin.Context) ginresp.HTTPResponse {
|
||||
type query struct {
|
||||
UserID string `form:"user_id"`
|
||||
UserKey string `form:"user_key"`
|
||||
MessageID string `form:"scn_msg_id"`
|
||||
}
|
||||
type response struct {
|
||||
Success string `json:"success"`
|
||||
Message string `json:"message"`
|
||||
PrevAckValue int `json:"prev_ack"`
|
||||
NewAckValue int `json:"new_ack"`
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
return ginresp.NotImplemented(0)
|
||||
}
|
||||
|
||||
// Requery swaggerdoc
|
||||
//
|
||||
// @Summary Return all not-acknowledged messages
|
||||
// @Param user_id query string true "the user_id"
|
||||
// @Param user_key query string true "the user_key"
|
||||
// @Success 200 {object} handler.Requery.response
|
||||
// @Failure 500 {object} ginresp.internAPIError
|
||||
// @Router /requery.php [get]
|
||||
func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
|
||||
type query struct {
|
||||
UserID string `form:"user_id"`
|
||||
UserKey string `form:"user_key"`
|
||||
}
|
||||
type response struct {
|
||||
Success string `json:"success"`
|
||||
Message string `json:"message"`
|
||||
Count int `json:"count"`
|
||||
Data []models.CompatMessage `json:"data"`
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
return ginresp.NotImplemented(0)
|
||||
}
|
||||
|
||||
// Update swaggerdoc
|
||||
//
|
||||
// @Summary Set the fcm-token (android)
|
||||
// @Param user_id query string true "the user_id"
|
||||
// @Param user_key query string true "the user_key"
|
||||
// @Param fcm_token query string true "the (android) fcm token"
|
||||
// @Success 200 {object} handler.Update.response
|
||||
// @Failure 500 {object} ginresp.internAPIError
|
||||
// @Router /update.php [get]
|
||||
func (h CompatHandler) Update(g *gin.Context) ginresp.HTTPResponse {
|
||||
type query struct {
|
||||
UserID string `form:"user_id"`
|
||||
UserKey string `form:"user_key"`
|
||||
FCMToken string `form:"fcm_token"`
|
||||
}
|
||||
type response struct {
|
||||
Success string `json:"success"`
|
||||
Message string `json:"message"`
|
||||
UserID string `json:"user_id"`
|
||||
UserKey string `json:"user_key"`
|
||||
QuotaUsed string `json:"quota"`
|
||||
QuotaMax string `json:"quota_max"`
|
||||
IsPro string `json:"is_pro"`
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
return ginresp.NotImplemented(0)
|
||||
}
|
||||
|
||||
// Expand swaggerdoc
|
||||
//
|
||||
// @Summary Get a whole (potentially truncated) message
|
||||
// @Success 200 {object} handler.Expand.response
|
||||
// @Failure 500 {object} ginresp.internAPIError
|
||||
// @Router /expand.php [get]
|
||||
func (h CompatHandler) Expand(g *gin.Context) ginresp.HTTPResponse {
|
||||
type query struct {
|
||||
UserID string `form:"user_id"`
|
||||
UserKey string `form:"user_key"`
|
||||
MessageID string `form:"scn_msg_id"`
|
||||
}
|
||||
type response struct {
|
||||
Success string `json:"success"`
|
||||
Message string `json:"message"`
|
||||
Data models.ShortCompatMessage `json:"data"`
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
return ginresp.NotImplemented(0)
|
||||
}
|
||||
|
||||
// Upgrade swaggerdoc
|
||||
//
|
||||
// @Summary Upgrade a free account to a paid account
|
||||
// @Param user_id query string true "the user_id"
|
||||
// @Param user_key query string true "the user_key"
|
||||
// @Param pro query string true "if the user is a paid account" Enums(true, false)
|
||||
// @Param pro_token query string true "the (android) IAP token"
|
||||
// @Success 200 {object} handler.Upgrade.response
|
||||
// @Failure 500 {object} ginresp.internAPIError
|
||||
// @Router /upgrade.php [get]
|
||||
func (h CompatHandler) Upgrade(g *gin.Context) ginresp.HTTPResponse {
|
||||
type query struct {
|
||||
UserID string `form:"user_id"`
|
||||
UserKey string `form:"user_key"`
|
||||
Pro string `form:"pro"`
|
||||
ProToken string `form:"pro_token"`
|
||||
}
|
||||
type response struct {
|
||||
Success string `json:"success"`
|
||||
Message string `json:"message"`
|
||||
Data models.ShortCompatMessage `json:"data"`
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
return ginresp.NotImplemented(0)
|
||||
}
|
||||
|
||||
// Send swaggerdoc
|
||||
//
|
||||
// @Summary Send a message
|
||||
// @Description all aeguments can either be supplied in the query or in the json body
|
||||
// @Param user_id query string true "the user_id"
|
||||
// @Param user_key query string true "the user_key"
|
||||
// @Param title query string true "The message title"
|
||||
// @Param content query string false "The message content"
|
||||
// @Param priority query string false "The message priority" Enum(0, 1, 2)
|
||||
// @Param msg_id query string false "The message idempotency id"
|
||||
// @Param timestamp query string false "The message timestamp"
|
||||
// @Param user_id body string true "the user_id"
|
||||
// @Param user_key body string true "the user_key"
|
||||
// @Param title body string true "The message title"
|
||||
// @Param content body string false "The message content"
|
||||
// @Param priority body string false "The message priority" Enum(0, 1, 2)
|
||||
// @Param msg_id body string false "The message idempotency id"
|
||||
// @Param timestamp body string false "The message timestamp"
|
||||
// @Success 200 {object} handler.Send.response
|
||||
// @Failure 500 {object} ginresp.sendAPIError
|
||||
// @Router /send.php [post]
|
||||
func (h CompatHandler) Send(g *gin.Context) ginresp.HTTPResponse {
|
||||
type query struct {
|
||||
//TODO
|
||||
}
|
||||
type response struct {
|
||||
Success string `json:"success"`
|
||||
Message string `json:"message"`
|
||||
//TODO
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
return ginresp.SendAPIError(apierr.INTERNAL_EXCEPTION, -1, "NotImplemented")
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package models
|
||||
|
||||
type CompatMessage struct {
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
Priority int `json:"priority"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
UserMessageID string `json:"usr_msg_id"`
|
||||
SCNMessageID string `json:"scn_msg_id"`
|
||||
}
|
||||
|
||||
type ShortCompatMessage struct {
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
Trimmed bool `json:"trimmed"`
|
||||
Priority int `json:"priority"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
UserMessageID string `json:"usr_msg_id"`
|
||||
SCNMessageID string `json:"scn_msg_id"`
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/handler"
|
||||
"blackforestbytes.com/simplecloudnotifier/common/ginext"
|
||||
"blackforestbytes.com/simplecloudnotifier/common/ginresp"
|
||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||
"blackforestbytes.com/simplecloudnotifier/swagger"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Router struct {
|
||||
app *logic.Application
|
||||
|
||||
commonHandler handler.CommonHandler
|
||||
compatHandler handler.CompatHandler
|
||||
}
|
||||
|
||||
func NewRouter(app *logic.Application) *Router {
|
||||
return &Router{
|
||||
app: app,
|
||||
|
||||
commonHandler: handler.NewCommonHandler(app),
|
||||
compatHandler: handler.NewCompatHandler(app),
|
||||
}
|
||||
}
|
||||
|
||||
// Init swaggerdocs
|
||||
// @title SimpleCloudNotifier API
|
||||
// @version 2.0
|
||||
// @description API for SCN
|
||||
// @host scn.blackforestbytes.com
|
||||
// @BasePath /api/
|
||||
func (r *Router) Init(e *gin.Engine) {
|
||||
|
||||
e.Any("/ping", ginresp.Wrap(r.commonHandler.Ping))
|
||||
e.POST("/db-test", ginresp.Wrap(r.commonHandler.DatabaseTest))
|
||||
e.GET("/health", ginresp.Wrap(r.commonHandler.Health))
|
||||
|
||||
e.GET("documentation/swagger", ginext.RedirectTemporary("/documentation/swagger/"))
|
||||
e.GET("documentation/swagger/", ginresp.Wrap(swagger.Handle))
|
||||
e.GET("documentation/swagger/:fn", ginresp.Wrap(swagger.Handle))
|
||||
|
||||
e.POST("/send.php", ginresp.Wrap(r.compatHandler.Send))
|
||||
e.GET("/register.php", ginresp.Wrap(r.compatHandler.Register))
|
||||
e.GET("/info.php", ginresp.Wrap(r.compatHandler.Info))
|
||||
e.GET("/ack.php", ginresp.Wrap(r.compatHandler.Ack))
|
||||
e.GET("/requery.php", ginresp.Wrap(r.compatHandler.Requery))
|
||||
e.GET("/update.php", ginresp.Wrap(r.compatHandler.Update))
|
||||
e.GET("/expand.php", ginresp.Wrap(r.compatHandler.Expand))
|
||||
e.GET("/upgrade.php", ginresp.Wrap(r.compatHandler.Upgrade))
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
scn "blackforestbytes.com/simplecloudnotifier"
|
||||
"blackforestbytes.com/simplecloudnotifier/api"
|
||||
"blackforestbytes.com/simplecloudnotifier/common"
|
||||
"blackforestbytes.com/simplecloudnotifier/common/ginext"
|
||||
"blackforestbytes.com/simplecloudnotifier/db"
|
||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||
"fmt"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var conf = scn.Conf
|
||||
|
||||
func main() {
|
||||
common.Init(conf)
|
||||
|
||||
log.Info().Msg(fmt.Sprintf("Starting with config-namespace <%s>", conf.Namespace))
|
||||
|
||||
sqlite, err := db.NewDatabase(conf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
app := logic.NewApp(sqlite)
|
||||
|
||||
ginengine := ginext.NewEngine(conf)
|
||||
|
||||
router := api.NewRouter(app)
|
||||
|
||||
app.Init(conf, ginengine)
|
||||
|
||||
router.Init(ginengine)
|
||||
|
||||
app.Run()
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
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", "POST, OPTIONS, GET, PUT")
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
c.AbortWithStatus(http.StatusOK)
|
||||
} else {
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package ginext
|
||||
|
||||
import (
|
||||
scn "blackforestbytes.com/simplecloudnotifier"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func NewEngine(cfg scn.Config) *gin.Engine {
|
||||
engine := gin.New()
|
||||
|
||||
engine.RedirectFixedPath = false
|
||||
engine.RedirectTrailingSlash = false
|
||||
|
||||
engine.Use(CorsMiddleware())
|
||||
|
||||
if cfg.GinDebug {
|
||||
engine.Use(gin.Logger())
|
||||
}
|
||||
|
||||
return engine
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package ginresp
|
||||
|
||||
type sendAPIError struct {
|
||||
Success bool `json:"success"`
|
||||
Error int `json:"error"`
|
||||
ErrorHighlight int `json:"errhighlight"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type internAPIError struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorID int `json:"errid,omitempty"`
|
||||
Message string `json:"message"`
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package ginresp
|
||||
|
||||
type errBody struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package ginresp
|
||||
|
||||
import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type HTTPResponse interface {
|
||||
Write(context *gin.Context)
|
||||
}
|
||||
|
||||
type jsonHTTPResponse struct {
|
||||
statusCode int
|
||||
data any
|
||||
}
|
||||
|
||||
func (j jsonHTTPResponse) Write(g *gin.Context) {
|
||||
g.JSON(j.statusCode, j.data)
|
||||
}
|
||||
|
||||
type emptyHTTPResponse struct {
|
||||
statusCode int
|
||||
data any
|
||||
}
|
||||
|
||||
func (j emptyHTTPResponse) Write(g *gin.Context) {
|
||||
g.Status(j.statusCode)
|
||||
}
|
||||
|
||||
type textHTTPResponse struct {
|
||||
statusCode int
|
||||
data string
|
||||
}
|
||||
|
||||
func (j textHTTPResponse) Write(g *gin.Context) {
|
||||
g.String(j.statusCode, "%s", j.data)
|
||||
}
|
||||
|
||||
type dataHTTPResponse struct {
|
||||
statusCode int
|
||||
data []byte
|
||||
contentType string
|
||||
}
|
||||
|
||||
func (j dataHTTPResponse) Write(g *gin.Context) {
|
||||
g.Data(j.statusCode, j.contentType, j.data)
|
||||
}
|
||||
|
||||
type errHTTPResponse struct {
|
||||
statusCode int
|
||||
data any
|
||||
}
|
||||
|
||||
func (j errHTTPResponse) Write(g *gin.Context) {
|
||||
g.JSON(j.statusCode, j.data)
|
||||
}
|
||||
|
||||
func Status(sc int) HTTPResponse {
|
||||
return &emptyHTTPResponse{statusCode: sc}
|
||||
}
|
||||
|
||||
func JSON(sc int, data any) HTTPResponse {
|
||||
return &jsonHTTPResponse{statusCode: sc, data: data}
|
||||
}
|
||||
|
||||
func Data(sc int, contentType string, data []byte) HTTPResponse {
|
||||
return &dataHTTPResponse{statusCode: sc, contentType: contentType, data: data}
|
||||
}
|
||||
|
||||
func Text(sc int, data string) HTTPResponse {
|
||||
return &textHTTPResponse{statusCode: sc, data: data}
|
||||
}
|
||||
|
||||
func InternalError(e error) HTTPResponse {
|
||||
return &errHTTPResponse{statusCode: http.StatusInternalServerError, data: errBody{Success: false, Message: e.Error()}}
|
||||
}
|
||||
|
||||
func NotImplemented(errid int) HTTPResponse {
|
||||
return &errHTTPResponse{statusCode: http.StatusInternalServerError, data: internAPIError{Success: false, ErrorID: errid, Message: "NotImplemented"}}
|
||||
}
|
||||
|
||||
func SendAPIError(errorid apierr.APIError, highlight int, msg string) HTTPResponse {
|
||||
return &errHTTPResponse{statusCode: http.StatusInternalServerError, data: sendAPIError{Success: false, Error: int(errorid), ErrorHighlight: highlight, Message: msg}}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package ginresp
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
type WHandlerFunc func(*gin.Context) HTTPResponse
|
||||
|
||||
func Wrap(fn WHandlerFunc) gin.HandlerFunc {
|
||||
|
||||
return func(context *gin.Context) {
|
||||
|
||||
wrap := fn(context)
|
||||
|
||||
if context.Writer.Written() {
|
||||
panic("Writing in WrapperFunc is not supported")
|
||||
}
|
||||
|
||||
wrap.Write(context)
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
scn "blackforestbytes.com/simplecloudnotifier"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Init(cfg scn.Config) {
|
||||
cw := zerolog.ConsoleWriter{
|
||||
Out: os.Stdout,
|
||||
TimeFormat: "2006-01-02 15:04:05 Z07:00",
|
||||
}
|
||||
|
||||
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
|
||||
multi := zerolog.MultiLevelWriter(cw)
|
||||
logger := zerolog.New(multi).With().
|
||||
Timestamp().
|
||||
Caller().
|
||||
Logger()
|
||||
|
||||
log.Logger = logger
|
||||
|
||||
if cfg.GinDebug {
|
||||
gin.SetMode(gin.DebugMode)
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
} else {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
}
|
||||
|
||||
log.Debug().Msg("Initialized")
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"github.com/rs/zerolog/log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Namespace string
|
||||
GinDebug bool
|
||||
ServerIP string
|
||||
ServerPort string
|
||||
DBFile string
|
||||
}
|
||||
|
||||
var Conf Config
|
||||
|
||||
var configLoc = Config{
|
||||
Namespace: "local",
|
||||
GinDebug: true,
|
||||
ServerIP: "0.0.0.0",
|
||||
ServerPort: "8080",
|
||||
DBFile: ".run-data/db.sqlite3",
|
||||
}
|
||||
|
||||
var configDev = Config{
|
||||
Namespace: "develop",
|
||||
GinDebug: true,
|
||||
ServerIP: "0.0.0.0",
|
||||
ServerPort: "80",
|
||||
DBFile: "/data/scn.sqlite3",
|
||||
}
|
||||
|
||||
var configStag = Config{
|
||||
Namespace: "staging",
|
||||
GinDebug: true,
|
||||
ServerIP: "0.0.0.0",
|
||||
ServerPort: "80",
|
||||
DBFile: "/data/scn.sqlite3",
|
||||
}
|
||||
|
||||
var configProd = Config{
|
||||
Namespace: "production",
|
||||
GinDebug: false,
|
||||
ServerIP: "0.0.0.0",
|
||||
ServerPort: "80",
|
||||
DBFile: "/data/scn.sqlite3",
|
||||
}
|
||||
|
||||
var allConfig = []Config{
|
||||
configLoc,
|
||||
configDev,
|
||||
configStag,
|
||||
configProd,
|
||||
}
|
||||
|
||||
func getConfig(ns string) (Config, bool) {
|
||||
if ns == "" {
|
||||
return configLoc, true
|
||||
}
|
||||
for _, c := range allConfig {
|
||||
if c.Namespace == ns {
|
||||
return c, true
|
||||
}
|
||||
}
|
||||
return Config{}, false
|
||||
}
|
||||
|
||||
func init() {
|
||||
ns := os.Getenv("CONF_NS")
|
||||
|
||||
cfg, ok := getConfig(ns)
|
||||
if !ok {
|
||||
log.Fatal().Str("ns", ns).Msg("Unknown config-namespace")
|
||||
}
|
||||
|
||||
Conf = cfg
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
scn "blackforestbytes.com/simplecloudnotifier"
|
||||
"database/sql"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func NewDatabase(conf scn.Config) (*sql.DB, error) {
|
||||
return sql.Open("sqlite3", conf.DBFile)
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// Package docs GENERATED BY SWAG; DO NOT EDIT
|
||||
// This file was generated by swaggo/swag
|
||||
package docs
|
||||
|
||||
import "github.com/swaggo/swag"
|
||||
|
||||
const docTemplate = `{
|
||||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "{{escape .Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"contact": {},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/ping": {
|
||||
"get": {
|
||||
"description": "asdf",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "Test request",
|
||||
"operationId": "ping",
|
||||
"responses": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = &swag.Spec{
|
||||
Version: "",
|
||||
Host: "",
|
||||
BasePath: "",
|
||||
Schemes: []string{},
|
||||
Title: "",
|
||||
Description: "",
|
||||
InfoInstanceName: "swagger",
|
||||
SwaggerTemplate: docTemplate,
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"contact": {}
|
||||
},
|
||||
"paths": {
|
||||
"/ping": {
|
||||
"get": {
|
||||
"description": "asdf",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "Test request",
|
||||
"operationId": "ping",
|
||||
"responses": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
info:
|
||||
contact: {}
|
||||
paths:
|
||||
/ping:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: asdf
|
||||
operationId: ping
|
||||
produces:
|
||||
- application/json
|
||||
responses: {}
|
||||
summary: Test request
|
||||
swagger: "2.0"
|
|
@ -0,0 +1,42 @@
|
|||
module blackforestbytes.com/simplecloudnotifier
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.8.1
|
||||
github.com/rs/zerolog v1.28.0
|
||||
github.com/swaggo/swag v1.8.7
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.10.0 // indirect
|
||||
github.com/goccy/go-json v0.9.7 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.16 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.7 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
|
@ -0,0 +1,133 @@
|
|||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
|
||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
|
||||
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
|
||||
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
|
||||
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
|
||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
|
||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
|
||||
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/swaggo/swag v1.8.7 h1:2K9ivTD3teEO+2fXV6zrZKDqk5IuU2aJtBDo8U7omWU=
|
||||
github.com/swaggo/swag v1.8.7/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -0,0 +1,63 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
scn "blackforestbytes.com/simplecloudnotifier"
|
||||
"context"
|
||||
"database/sql"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog/log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Application struct {
|
||||
Config scn.Config
|
||||
Gin *gin.Engine
|
||||
Database *sql.DB
|
||||
}
|
||||
|
||||
func NewApp(db *sql.DB) *Application {
|
||||
return &Application{Database: db}
|
||||
}
|
||||
|
||||
func (app *Application) Init(cfg scn.Config, g *gin.Engine) {
|
||||
app.Config = cfg
|
||||
app.Gin = g
|
||||
}
|
||||
|
||||
func (app *Application) Run() {
|
||||
httpserver := &http.Server{
|
||||
Addr: net.JoinHostPort(app.Config.ServerIP, app.Config.ServerPort),
|
||||
Handler: app.Gin,
|
||||
}
|
||||
|
||||
errChan := make(chan error)
|
||||
|
||||
go func() {
|
||||
log.Info().Str("address", httpserver.Addr).Msg("HTTP-Server started")
|
||||
errChan <- httpserver.ListenAndServe()
|
||||
}()
|
||||
|
||||
stop := make(chan os.Signal, 1)
|
||||
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
|
||||
select {
|
||||
case <-stop:
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
log.Info().Msg("Stopping HTTP-Server")
|
||||
err := httpserver.Shutdown(ctx)
|
||||
if err != nil {
|
||||
log.Info().Err(err).Msg("Error while stopping the http-server")
|
||||
return
|
||||
}
|
||||
log.Info().Msg("Stopped HTTP-Server")
|
||||
|
||||
case err := <-errChan:
|
||||
log.Error().Err(err).Msg("HTTP-Server failed")
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>API Documentation</title>
|
||||
<link rel="stylesheet" href="swagger-ui.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="swagger-ui-bundle.js" crossorigin></script>
|
||||
<script src="swagger-ui-standalone-preset.js" crossorigin></script>
|
||||
<script>
|
||||
window.onload = () => {
|
||||
window.ui = SwaggerUIBundle({
|
||||
url: './swagger.json',
|
||||
dom_id: '#swagger-ui',
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
layout: "StandaloneLayout"
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,68 @@
|
|||
package swagger
|
||||
|
||||
import (
|
||||
"blackforestbytes.com/simplecloudnotifier/common/ginresp"
|
||||
"embed"
|
||||
_ "embed"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:embed index.html
|
||||
//go:embed swagger.json
|
||||
//go:embed swagger.yaml
|
||||
//go:embed swagger-ui-bundle.js
|
||||
//go:embed swagger-ui.css
|
||||
//go:embed swagger-ui-standalone-preset.js
|
||||
var assets embed.FS
|
||||
|
||||
func getAsset(fn string) ([]byte, string, bool) {
|
||||
data, err := assets.ReadFile(fn)
|
||||
if err != nil {
|
||||
return nil, "", false
|
||||
}
|
||||
|
||||
mime := "text/plain"
|
||||
|
||||
lowerFN := strings.ToLower(fn)
|
||||
if strings.HasSuffix(lowerFN, ".html") || strings.HasSuffix(lowerFN, ".htm") {
|
||||
mime = "text/html"
|
||||
} else if strings.HasSuffix(lowerFN, ".css") {
|
||||
mime = "text/css"
|
||||
} else if strings.HasSuffix(lowerFN, ".js") {
|
||||
mime = "text/javascript"
|
||||
} else if strings.HasSuffix(lowerFN, ".json") {
|
||||
mime = "application/json"
|
||||
} else if strings.HasSuffix(lowerFN, ".jpeg") || strings.HasSuffix(lowerFN, ".jpg") {
|
||||
mime = "image/jpeg"
|
||||
} else if strings.HasSuffix(lowerFN, ".png") {
|
||||
mime = "image/png"
|
||||
} else if strings.HasSuffix(lowerFN, ".svg") {
|
||||
mime = "image/svg+xml"
|
||||
}
|
||||
|
||||
return data, mime, true
|
||||
}
|
||||
|
||||
func Handle(g *gin.Context) ginresp.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()})
|
||||
}
|
||||
|
||||
if u.Filename == "" {
|
||||
index, _, _ := getAsset("index.html")
|
||||
return ginresp.Data(http.StatusOK, "text/html", index)
|
||||
}
|
||||
|
||||
if data, mime, ok := getAsset(u.Filename); ok {
|
||||
return ginresp.Data(http.StatusOK, mime, data)
|
||||
}
|
||||
|
||||
return ginresp.JSON(http.StatusNotFound, gin.H{"error": "AssetNotFound", "filename": u.Filename})
|
||||
}
|
|
@ -0,0 +1,844 @@
|
|||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "API for SCN",
|
||||
"title": "SimpleCloudNotifier API",
|
||||
"contact": {},
|
||||
"version": "2.0"
|
||||
},
|
||||
"host": "scn.blackforestbytes.com",
|
||||
"basePath": "/api/",
|
||||
"paths": {
|
||||
"/ack.php": {
|
||||
"get": {
|
||||
"summary": "Acknowledge that a message was received",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_id",
|
||||
"name": "user_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_key",
|
||||
"name": "user_key",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the message id",
|
||||
"name": "scn_msg_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Ack.response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.internAPIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/db-test": {
|
||||
"get": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.DatabaseTest.response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.errBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/expand.php": {
|
||||
"get": {
|
||||
"summary": "Get a whole (potentially truncated) message",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Expand.response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.internAPIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/health": {
|
||||
"get": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Health.response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.errBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/info.php": {
|
||||
"get": {
|
||||
"summary": "Get information about the current user",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_id",
|
||||
"name": "user_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_key",
|
||||
"name": "user_key",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Info.response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.internAPIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ping": {
|
||||
"get": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.pingResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.errBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.pingResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.errBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.pingResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.errBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.pingResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.errBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.pingResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.errBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/register.php": {
|
||||
"get": {
|
||||
"summary": "Register a new account",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the (android) fcm token",
|
||||
"name": "fcm_token",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"true",
|
||||
"false"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "if the user is a paid account",
|
||||
"name": "pro",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the (android) IAP token",
|
||||
"name": "pro_token",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Register.response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.internAPIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/requery.php": {
|
||||
"get": {
|
||||
"summary": "Return all not-acknowledged messages",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_id",
|
||||
"name": "user_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_key",
|
||||
"name": "user_key",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Requery.response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.internAPIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/send.php": {
|
||||
"post": {
|
||||
"description": "all aeguments can either be supplied in the query or in the json body",
|
||||
"summary": "Send a message",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_id",
|
||||
"name": "user_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_key",
|
||||
"name": "user_key",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The message title",
|
||||
"name": "title",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The message content",
|
||||
"name": "content",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The message priority",
|
||||
"name": "priority",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The message idempotency id",
|
||||
"name": "msg_id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The message timestamp",
|
||||
"name": "timestamp",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"description": "the user_id",
|
||||
"name": "user_id",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "the user_key",
|
||||
"name": "user_key",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "The message title",
|
||||
"name": "title",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "The message content",
|
||||
"name": "content",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "The message priority",
|
||||
"name": "priority",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "The message idempotency id",
|
||||
"name": "msg_id",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "The message timestamp",
|
||||
"name": "timestamp",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Send.response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.sendAPIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/update.php": {
|
||||
"get": {
|
||||
"summary": "Set the fcm-token (android)",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_id",
|
||||
"name": "user_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_key",
|
||||
"name": "user_key",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the (android) fcm token",
|
||||
"name": "fcm_token",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Update.response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.internAPIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/upgrade.php": {
|
||||
"get": {
|
||||
"summary": "Upgrade a free account to a paid account",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_id",
|
||||
"name": "user_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the user_key",
|
||||
"name": "user_key",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"true",
|
||||
"false"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "if the user is a paid account",
|
||||
"name": "pro",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the (android) IAP token",
|
||||
"name": "pro_token",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Upgrade.response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.internAPIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"ginresp.errBody": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ginresp.internAPIError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"errid": {
|
||||
"type": "integer"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ginresp.sendAPIError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"errhighlight": {
|
||||
"type": "integer"
|
||||
},
|
||||
"error": {
|
||||
"type": "integer"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Ack.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"new_ack": {
|
||||
"type": "integer"
|
||||
},
|
||||
"prev_ack": {
|
||||
"type": "integer"
|
||||
},
|
||||
"success": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.DatabaseTest.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"libVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"libVersionNumber": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sourceID": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Expand.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/models.ShortCompatMessage"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Health.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Info.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fcm_token_set": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"is_pro": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"quota": {
|
||||
"type": "string"
|
||||
},
|
||||
"quota_max": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "string"
|
||||
},
|
||||
"unack_count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_key": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Register.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"is_pro": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"quota": {
|
||||
"type": "string"
|
||||
},
|
||||
"quota_max": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_key": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Requery.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/models.CompatMessage"
|
||||
}
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Send.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Update.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"is_pro": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"quota": {
|
||||
"type": "string"
|
||||
},
|
||||
"quota_max": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_key": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Upgrade.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/models.ShortCompatMessage"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.pingResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"info": {
|
||||
"$ref": "#/definitions/handler.pingResponseInfo"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.pingResponseInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"addr": {
|
||||
"type": "string"
|
||||
},
|
||||
"headers": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"method": {
|
||||
"type": "string"
|
||||
},
|
||||
"request": {
|
||||
"type": "string"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.CompatMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"body": {
|
||||
"type": "string"
|
||||
},
|
||||
"priority": {
|
||||
"type": "integer"
|
||||
},
|
||||
"scn_msg_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"usr_msg_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.ShortCompatMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"body": {
|
||||
"type": "string"
|
||||
},
|
||||
"priority": {
|
||||
"type": "integer"
|
||||
},
|
||||
"scn_msg_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"trimmed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"usr_msg_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,551 @@
|
|||
basePath: /api/
|
||||
definitions:
|
||||
ginresp.errBody:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
success:
|
||||
type: boolean
|
||||
type: object
|
||||
ginresp.internAPIError:
|
||||
properties:
|
||||
errid:
|
||||
type: integer
|
||||
message:
|
||||
type: string
|
||||
success:
|
||||
type: boolean
|
||||
type: object
|
||||
ginresp.sendAPIError:
|
||||
properties:
|
||||
errhighlight:
|
||||
type: integer
|
||||
error:
|
||||
type: integer
|
||||
message:
|
||||
type: string
|
||||
success:
|
||||
type: boolean
|
||||
type: object
|
||||
handler.Ack.response:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
new_ack:
|
||||
type: integer
|
||||
prev_ack:
|
||||
type: integer
|
||||
success:
|
||||
type: string
|
||||
type: object
|
||||
handler.DatabaseTest.response:
|
||||
properties:
|
||||
libVersion:
|
||||
type: string
|
||||
libVersionNumber:
|
||||
type: integer
|
||||
sourceID:
|
||||
type: string
|
||||
success:
|
||||
type: boolean
|
||||
type: object
|
||||
handler.Expand.response:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/definitions/models.ShortCompatMessage'
|
||||
message:
|
||||
type: string
|
||||
success:
|
||||
type: string
|
||||
type: object
|
||||
handler.Health.response:
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
handler.Info.response:
|
||||
properties:
|
||||
fcm_token_set:
|
||||
type: boolean
|
||||
is_pro:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
quota:
|
||||
type: string
|
||||
quota_max:
|
||||
type: string
|
||||
success:
|
||||
type: string
|
||||
unack_count:
|
||||
type: integer
|
||||
user_id:
|
||||
type: string
|
||||
user_key:
|
||||
type: string
|
||||
type: object
|
||||
handler.Register.response:
|
||||
properties:
|
||||
is_pro:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
quota:
|
||||
type: string
|
||||
quota_max:
|
||||
type: string
|
||||
success:
|
||||
type: string
|
||||
user_id:
|
||||
type: string
|
||||
user_key:
|
||||
type: string
|
||||
type: object
|
||||
handler.Requery.response:
|
||||
properties:
|
||||
count:
|
||||
type: integer
|
||||
data:
|
||||
items:
|
||||
$ref: '#/definitions/models.CompatMessage'
|
||||
type: array
|
||||
message:
|
||||
type: string
|
||||
success:
|
||||
type: string
|
||||
type: object
|
||||
handler.Send.response:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
success:
|
||||
type: string
|
||||
type: object
|
||||
handler.Update.response:
|
||||
properties:
|
||||
is_pro:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
quota:
|
||||
type: string
|
||||
quota_max:
|
||||
type: string
|
||||
success:
|
||||
type: string
|
||||
user_id:
|
||||
type: string
|
||||
user_key:
|
||||
type: string
|
||||
type: object
|
||||
handler.Upgrade.response:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/definitions/models.ShortCompatMessage'
|
||||
message:
|
||||
type: string
|
||||
success:
|
||||
type: string
|
||||
type: object
|
||||
handler.pingResponse:
|
||||
properties:
|
||||
info:
|
||||
$ref: '#/definitions/handler.pingResponseInfo'
|
||||
message:
|
||||
type: string
|
||||
type: object
|
||||
handler.pingResponseInfo:
|
||||
properties:
|
||||
addr:
|
||||
type: string
|
||||
headers:
|
||||
additionalProperties:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
method:
|
||||
type: string
|
||||
request:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
type: object
|
||||
models.CompatMessage:
|
||||
properties:
|
||||
body:
|
||||
type: string
|
||||
priority:
|
||||
type: integer
|
||||
scn_msg_id:
|
||||
type: string
|
||||
timestamp:
|
||||
type: integer
|
||||
title:
|
||||
type: string
|
||||
usr_msg_id:
|
||||
type: string
|
||||
type: object
|
||||
models.ShortCompatMessage:
|
||||
properties:
|
||||
body:
|
||||
type: string
|
||||
priority:
|
||||
type: integer
|
||||
scn_msg_id:
|
||||
type: string
|
||||
timestamp:
|
||||
type: integer
|
||||
title:
|
||||
type: string
|
||||
trimmed:
|
||||
type: boolean
|
||||
usr_msg_id:
|
||||
type: string
|
||||
type: object
|
||||
host: scn.blackforestbytes.com
|
||||
info:
|
||||
contact: {}
|
||||
description: API for SCN
|
||||
title: SimpleCloudNotifier API
|
||||
version: "2.0"
|
||||
paths:
|
||||
/ack.php:
|
||||
get:
|
||||
parameters:
|
||||
- description: the user_id
|
||||
in: query
|
||||
name: user_id
|
||||
required: true
|
||||
type: string
|
||||
- description: the user_key
|
||||
in: query
|
||||
name: user_key
|
||||
required: true
|
||||
type: string
|
||||
- description: the message id
|
||||
in: query
|
||||
name: scn_msg_id
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Ack.response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.internAPIError'
|
||||
summary: Acknowledge that a message was received
|
||||
/db-test:
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.DatabaseTest.response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.errBody'
|
||||
/expand.php:
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Expand.response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.internAPIError'
|
||||
summary: Get a whole (potentially truncated) message
|
||||
/health:
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Health.response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.errBody'
|
||||
/info.php:
|
||||
get:
|
||||
parameters:
|
||||
- description: the user_id
|
||||
in: query
|
||||
name: user_id
|
||||
required: true
|
||||
type: string
|
||||
- description: the user_key
|
||||
in: query
|
||||
name: user_key
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Info.response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.internAPIError'
|
||||
summary: Get information about the current user
|
||||
/ping:
|
||||
delete:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.pingResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.errBody'
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.pingResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.errBody'
|
||||
patch:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.pingResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.errBody'
|
||||
post:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.pingResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.errBody'
|
||||
put:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.pingResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.errBody'
|
||||
/register.php:
|
||||
get:
|
||||
parameters:
|
||||
- description: the (android) fcm token
|
||||
in: query
|
||||
name: fcm_token
|
||||
required: true
|
||||
type: string
|
||||
- description: if the user is a paid account
|
||||
enum:
|
||||
- "true"
|
||||
- "false"
|
||||
in: query
|
||||
name: pro
|
||||
required: true
|
||||
type: string
|
||||
- description: the (android) IAP token
|
||||
in: query
|
||||
name: pro_token
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Register.response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.internAPIError'
|
||||
summary: Register a new account
|
||||
/requery.php:
|
||||
get:
|
||||
parameters:
|
||||
- description: the user_id
|
||||
in: query
|
||||
name: user_id
|
||||
required: true
|
||||
type: string
|
||||
- description: the user_key
|
||||
in: query
|
||||
name: user_key
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Requery.response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.internAPIError'
|
||||
summary: Return all not-acknowledged messages
|
||||
/send.php:
|
||||
post:
|
||||
description: all aeguments can either be supplied in the query or in the json
|
||||
body
|
||||
parameters:
|
||||
- description: the user_id
|
||||
in: query
|
||||
name: user_id
|
||||
required: true
|
||||
type: string
|
||||
- description: the user_key
|
||||
in: query
|
||||
name: user_key
|
||||
required: true
|
||||
type: string
|
||||
- description: The message title
|
||||
in: query
|
||||
name: title
|
||||
required: true
|
||||
type: string
|
||||
- description: The message content
|
||||
in: query
|
||||
name: content
|
||||
type: string
|
||||
- description: The message priority
|
||||
in: query
|
||||
name: priority
|
||||
type: string
|
||||
- description: The message idempotency id
|
||||
in: query
|
||||
name: msg_id
|
||||
type: string
|
||||
- description: The message timestamp
|
||||
in: query
|
||||
name: timestamp
|
||||
type: string
|
||||
- description: the user_id
|
||||
in: body
|
||||
name: user_id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- description: the user_key
|
||||
in: body
|
||||
name: user_key
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- description: The message title
|
||||
in: body
|
||||
name: title
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- description: The message content
|
||||
in: body
|
||||
name: content
|
||||
schema:
|
||||
type: string
|
||||
- description: The message priority
|
||||
in: body
|
||||
name: priority
|
||||
schema:
|
||||
type: string
|
||||
- description: The message idempotency id
|
||||
in: body
|
||||
name: msg_id
|
||||
schema:
|
||||
type: string
|
||||
- description: The message timestamp
|
||||
in: body
|
||||
name: timestamp
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Send.response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.sendAPIError'
|
||||
summary: Send a message
|
||||
/update.php:
|
||||
get:
|
||||
parameters:
|
||||
- description: the user_id
|
||||
in: query
|
||||
name: user_id
|
||||
required: true
|
||||
type: string
|
||||
- description: the user_key
|
||||
in: query
|
||||
name: user_key
|
||||
required: true
|
||||
type: string
|
||||
- description: the (android) fcm token
|
||||
in: query
|
||||
name: fcm_token
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Update.response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.internAPIError'
|
||||
summary: Set the fcm-token (android)
|
||||
/upgrade.php:
|
||||
get:
|
||||
parameters:
|
||||
- description: the user_id
|
||||
in: query
|
||||
name: user_id
|
||||
required: true
|
||||
type: string
|
||||
- description: the user_key
|
||||
in: query
|
||||
name: user_key
|
||||
required: true
|
||||
type: string
|
||||
- description: if the user is a paid account
|
||||
enum:
|
||||
- "true"
|
||||
- "false"
|
||||
in: query
|
||||
name: pro
|
||||
required: true
|
||||
type: string
|
||||
- description: the (android) IAP token
|
||||
in: query
|
||||
name: pro_token
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Upgrade.response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.internAPIError'
|
||||
summary: Upgrade a free account to a paid account
|
||||
swagger: "2.0"
|
Loading…
Reference in New Issue