mirror of
https://github.com/makayabou/asg-server.git
synced 2026-05-02 17:43:36 +02:00
Merge pull request #3 from capcom6/testing
TTL, compatibility and logging
This commit is contained in:
commit
414b7fd26f
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -9,7 +9,7 @@
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${workspaceRoot}/cmd/smsgateway/main.go",
|
||||
"program": "${workspaceRoot}/cmd/sms-gateway/main.go",
|
||||
"cwd": "${workspaceRoot}",
|
||||
}
|
||||
]
|
||||
|
||||
16
Makefile
16
Makefile
@ -22,9 +22,21 @@ db-upgrade:
|
||||
|
||||
db-upgrade-raw:
|
||||
go run ./cmd/$(project_name)/main.go db-upgrade
|
||||
|
||||
run:
|
||||
go run cmd/$(project_name)/main.go
|
||||
|
||||
test:
|
||||
go test ./...
|
||||
go test -cover ./...
|
||||
|
||||
build:
|
||||
go build ./cmd/$(project_name)
|
||||
|
||||
install:
|
||||
go install ./cmd/$(project_name)
|
||||
|
||||
docker-dev:
|
||||
docker-compose -f deployments/docker-compose/docker-compose.dev.yml up --build
|
||||
|
||||
api-docs:
|
||||
swag fmt -g ./cmd/$(project_name)/main.go \
|
||||
@ -33,4 +45,4 @@ api-docs:
|
||||
view-docs:
|
||||
php -S 127.0.0.1:8080 -t ./api
|
||||
|
||||
.PHONY: init init-dev air db-upgrade db-upgrade-raw test api-docs view-docs
|
||||
.PHONY: init init-dev air run test install api-docs docker-dev view-docs
|
||||
@ -16,16 +16,34 @@ Authorization: Basic IUGFXE:v4ejpbeydvjo1h
|
||||
|
||||
{
|
||||
"message": "Test",
|
||||
"ttl": {{$randomInt 0 86400}},
|
||||
"ttl": 60,
|
||||
"phoneNumbers": [
|
||||
"79990001234"
|
||||
]
|
||||
}
|
||||
|
||||
###
|
||||
GET {{baseUrl}}/api/3rdparty/v1/message/pRl1wf_yez5TikJb_xemU HTTP/1.1
|
||||
GET {{baseUrl}}/api/3rdparty/v1/message/iZo6T9hw7wTuKLQUIP29I HTTP/1.1
|
||||
Authorization: Basic IUGFXE:v4ejpbeydvjo1h
|
||||
|
||||
###
|
||||
GET {{baseUrl}}/api/mobile/v1/message HTTP/1.1
|
||||
Authorization: Bearer KuvE4LBXzvy8QO2ZXDDMP
|
||||
Authorization: Bearer KuvE4LBXzvy8QO2ZXDDMP
|
||||
|
||||
###
|
||||
PATCH {{baseUrl}}/api/mobile/v1/message HTTP/1.1
|
||||
Authorization: Bearer KuvE4LBXzvy8QO2ZXDDMP
|
||||
Content-Type: application/json
|
||||
|
||||
[
|
||||
{
|
||||
"id": "8GHr-tUz6JBRFpTUXDV4w",
|
||||
"state": "Pending",
|
||||
"recipients": [
|
||||
{
|
||||
"phoneNumber": "79990001234",
|
||||
"state": "Pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
15
build/package/Dockerfile.dev
Normal file
15
build/package/Dockerfile.dev
Normal file
@ -0,0 +1,15 @@
|
||||
FROM golang:1.20-alpine
|
||||
|
||||
ENV GO111MODULE="on"
|
||||
ENV GOOS="linux"
|
||||
ENV CGO_ENABLED=0
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN go install github.com/cosmtrek/air@latest && \
|
||||
go install github.com/go-delve/delve/cmd/dlv@latest
|
||||
|
||||
EXPOSE 2345
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["air", "-c", ".air.toml"]
|
||||
@ -11,3 +11,8 @@ database:
|
||||
password: root
|
||||
database: notifications
|
||||
debug: true
|
||||
fcm:
|
||||
credentials_json: >
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
ALTER TABLE `messages`
|
||||
ADD `valid_until` datetime;
|
||||
ADD `valid_until` datetime(3) DEFAULT NULL;
|
||||
-- +goose StatementEnd
|
||||
---
|
||||
-- +goose Down
|
||||
|
||||
23
deployments/docker-compose/docker-compose.dev.yml
Normal file
23
deployments/docker-compose/docker-compose.dev.yml
Normal file
@ -0,0 +1,23 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
sms-gateway:
|
||||
image: sms-gateway
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ../../build/package/Dockerfile.dev
|
||||
container_name: sms-gateway
|
||||
environment:
|
||||
- DEBUG=1
|
||||
- HTTP__LISTEN=:3000
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "3456:2345"
|
||||
volumes:
|
||||
- "../..:/app"
|
||||
- "/tmp/sms-gateway/go-cache:/go/pkg"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
restart: 'no'
|
||||
5
go.mod
5
go.mod
@ -5,10 +5,12 @@ go 1.20
|
||||
require (
|
||||
firebase.google.com/go/v4 v4.12.1
|
||||
github.com/go-playground/validator/v10 v10.15.5
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/gofiber/contrib/fiberzap/v2 v2.1.1
|
||||
github.com/gofiber/fiber/v2 v2.50.0
|
||||
github.com/jaevor/go-nanoid v1.3.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/nyaruka/phonenumbers v1.1.8
|
||||
github.com/valyala/fasthttp v1.50.0
|
||||
go.uber.org/fx v1.20.1
|
||||
@ -34,7 +36,6 @@ require (
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
@ -49,7 +50,9 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/philhofer/fwd v1.1.2 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/tinylib/msgp v1.1.8 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
|
||||
13
go.sum
13
go.sum
@ -96,6 +96,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
|
||||
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@ -115,6 +117,8 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/nyaruka/phonenumbers v1.1.8 h1:mjFu85FeoH2Wy18aOMUvxqi1GgAqiQSJsa/cCC5yu2s=
|
||||
github.com/nyaruka/phonenumbers v1.1.8/go.mod h1:DC7jZd321FqUe+qWSNcHi10tyIyGNXGcNbfkPvdp1Vs=
|
||||
github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
|
||||
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
|
||||
github.com/pkg/errors v0.8.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=
|
||||
@ -132,6 +136,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
|
||||
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e9M=
|
||||
@ -171,6 +177,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -181,6 +188,7 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@ -191,6 +199,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -204,15 +213,18 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
@ -225,6 +237,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@ -16,15 +16,16 @@ type Config struct {
|
||||
}
|
||||
|
||||
type HTTP struct {
|
||||
Listen string `yaml:"listen"`
|
||||
Listen string `yaml:"listen" envconfig:"HTTP__LISTEN"`
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
User string `yaml:"user"`
|
||||
Password string `yaml:"password"`
|
||||
Database string `yaml:"database"`
|
||||
Host string `yaml:"host" envconfig:"DATABASE__HOST"`
|
||||
Port int `yaml:"port" envconfig:"DATABASE__PORT"`
|
||||
User string `yaml:"user" envconfig:"DATABASE__USER"`
|
||||
Password string `yaml:"password" envconfig:"DATABASE__PASSWORD"`
|
||||
Database string `yaml:"database" envconfig:"DATABASE__DATABASE"`
|
||||
Timezone string `yaml:"timezone" envconfig:"DATABASE__TIMEZONE"`
|
||||
}
|
||||
|
||||
type FCMConfig struct {
|
||||
@ -41,6 +42,7 @@ var defaultConfig = Config{
|
||||
User: "sms",
|
||||
Password: "sms",
|
||||
Database: "sms",
|
||||
Timezone: "UTC",
|
||||
},
|
||||
FCM: FCMConfig{
|
||||
CredentialsJSON: "",
|
||||
|
||||
@ -1,31 +1,25 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/capcom6/sms-gateway/internal/infra/config"
|
||||
"github.com/capcom6/sms-gateway/internal/infra/db"
|
||||
"github.com/capcom6/sms-gateway/internal/infra/http"
|
||||
"github.com/capcom6/sms-gateway/internal/sms-gateway/services"
|
||||
"go.uber.org/fx"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var Module = fx.Module(
|
||||
"appconfig",
|
||||
fx.Provide(
|
||||
fx.Annotate(
|
||||
func() any {
|
||||
return &defaultConfig
|
||||
},
|
||||
fx.ResultTags(`name:"config:source"`),
|
||||
),
|
||||
func(log *zap.Logger) Config {
|
||||
if err := config.LoadConfig(&defaultConfig); err != nil {
|
||||
log.Error("Error loading config", zap.Error(err))
|
||||
}
|
||||
|
||||
return defaultConfig
|
||||
},
|
||||
),
|
||||
fx.Provide(
|
||||
fx.Annotate(
|
||||
func(cfg any) Config {
|
||||
return *cfg.(*Config)
|
||||
},
|
||||
fx.ParamTags(`name:"config:result"`),
|
||||
),
|
||||
),
|
||||
// fx.Provide(GetConfig),
|
||||
fx.Provide(func(cfg Config) http.Config {
|
||||
return http.Config{
|
||||
Listen: cfg.HTTP.Listen,
|
||||
@ -38,6 +32,7 @@ var Module = fx.Module(
|
||||
User: cfg.Database.User,
|
||||
Password: cfg.Database.Password,
|
||||
Database: cfg.Database.Database,
|
||||
Timezone: cfg.Database.Timezone,
|
||||
}
|
||||
}),
|
||||
fx.Provide(func(cfg Config) services.PushServiceConfig {
|
||||
|
||||
@ -5,19 +5,28 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"go.uber.org/zap"
|
||||
"github.com/kelseyhightower/envconfig"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
}
|
||||
|
||||
func New(params Param) any {
|
||||
func LoadConfig(config any) error {
|
||||
err := godotenv.Load()
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
params.Logger.Error("Error loading .env file", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
if err := loadFromYaml(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := loadFromEnv(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadFromYaml(config any) error {
|
||||
configPath := "config.yml"
|
||||
if envPath := os.Getenv("CONFIG_PATH"); envPath != "" {
|
||||
configPath = envPath
|
||||
@ -25,13 +34,16 @@ func New(params Param) any {
|
||||
|
||||
yamlFile, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
params.Logger.Error("Error reading config file", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(yamlFile, params.Config)
|
||||
if err != nil {
|
||||
params.Logger.Error("Error unmarshalling config file", zap.Error(err))
|
||||
if err := yaml.Unmarshal(yamlFile, config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return params.Config
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadFromEnv(config any) error {
|
||||
return envconfig.Process("", config)
|
||||
}
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"go.uber.org/fx"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var Module = fx.Module(
|
||||
"config",
|
||||
fx.Decorate(func(log *zap.Logger) *zap.Logger {
|
||||
return log.Named("config")
|
||||
}),
|
||||
fx.Provide(
|
||||
fx.Annotate(
|
||||
New,
|
||||
fx.ResultTags(`name:"config:result"`),
|
||||
),
|
||||
),
|
||||
)
|
||||
@ -1,13 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"go.uber.org/fx"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Param struct {
|
||||
fx.In
|
||||
|
||||
Logger *zap.Logger
|
||||
Config any `name:"config:source"`
|
||||
}
|
||||
@ -14,6 +14,7 @@ type Config struct {
|
||||
User string
|
||||
Password string
|
||||
Database string
|
||||
Timezone string
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
|
||||
@ -2,7 +2,10 @@ package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
|
||||
sql "github.com/go-sql-driver/mysql"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
@ -13,6 +16,8 @@ func New(params Params) (*gorm.DB, error) {
|
||||
dsn := makeDSN(params.Config)
|
||||
cfgGorm := makeConfig(params)
|
||||
|
||||
sql.SetLogger(log.Default())
|
||||
|
||||
return gorm.Open(mysql.Open(dsn), cfgGorm)
|
||||
}
|
||||
|
||||
@ -27,8 +32,9 @@ func makeConfig(params Params) *gorm.Config {
|
||||
}
|
||||
|
||||
func makeDSN(cfg Config) string {
|
||||
cfg = configDefault(cfg)
|
||||
return fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=utf8mb4,utf8&parseTime=true&tls=preferred",
|
||||
cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Database,
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=utf8mb4,utf8&parseTime=true&loc=%s&tls=preferred",
|
||||
cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Database, url.QueryEscape(cfg.Timezone),
|
||||
)
|
||||
}
|
||||
|
||||
@ -16,3 +16,17 @@ func AsApiHandler(f any) any {
|
||||
fx.ResultTags(`group:"api-routes"`),
|
||||
)
|
||||
}
|
||||
|
||||
func errorHandler(c *fiber.Ctx, err error) error {
|
||||
code := fiber.StatusInternalServerError
|
||||
|
||||
// Retrieve the custom status code if it's an fiber.*Error
|
||||
if e, ok := err.(*fiber.Error); ok {
|
||||
code = e.Code
|
||||
}
|
||||
|
||||
// Send json error
|
||||
return c.Status(code).JSON(&fiber.Map{
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ func New(params Params) (*fiber.App, error) {
|
||||
WriteTimeout: WriteTimeout,
|
||||
IdleTimeout: IdleTimeout,
|
||||
DisableStartupMessage: true,
|
||||
ErrorHandler: errorHandler,
|
||||
})
|
||||
|
||||
app.Use(recover.New())
|
||||
|
||||
@ -3,7 +3,6 @@ package smsgateway
|
||||
import (
|
||||
appconfig "github.com/capcom6/sms-gateway/internal/config"
|
||||
"github.com/capcom6/sms-gateway/internal/infra/cli"
|
||||
"github.com/capcom6/sms-gateway/internal/infra/config"
|
||||
"github.com/capcom6/sms-gateway/internal/infra/db"
|
||||
"github.com/capcom6/sms-gateway/internal/infra/http"
|
||||
"github.com/capcom6/sms-gateway/internal/infra/logger"
|
||||
@ -22,7 +21,6 @@ var Module = fx.Module(
|
||||
"server",
|
||||
cli.Module,
|
||||
appconfig.Module,
|
||||
config.Module,
|
||||
logger.Module,
|
||||
http.Module,
|
||||
validator.Module,
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
package handlers
|
||||
|
||||
// func New(params Params) Result {
|
||||
// return Result{
|
||||
// Handlers: []http.ApiHanlder{},
|
||||
// }
|
||||
// }
|
||||
|
||||
// func Register(router fiber.Router, db *gorm.DB) error {
|
||||
// cfg := config.GetConfig()
|
||||
|
||||
// users := repositories.NewUsersRepository(db)
|
||||
// devices := repositories.NewDevicesRepository(db)
|
||||
// messages := repositories.NewMessagesRepository(db)
|
||||
|
||||
// validator := validator.New()
|
||||
// authSvc := services.NewAuthService(users, devices)
|
||||
// pushSvc := services.NewPushService(cfg.FCM.CredentialsJSON)
|
||||
// messagesSvc := services.NewMessagesService(pushSvc, messages)
|
||||
|
||||
// newMobileHandler(validator, authSvc, messagesSvc).register(router.Group("/mobile/v1"))
|
||||
// newThirdPartyHandler(validator, authSvc, messagesSvc).register(router.Group("/3rdparty/v1"))
|
||||
|
||||
// return nil
|
||||
// }
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"github.com/capcom6/sms-gateway/pkg/smsgateway"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/limiter"
|
||||
"github.com/jaevor/go-nanoid"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@ -167,7 +168,7 @@ func (h *mobileHandler) authorize(handler func(models.Device, *fiber.Ctx) error)
|
||||
func (h *mobileHandler) Register(router fiber.Router) {
|
||||
router = router.Group("/mobile/v1")
|
||||
|
||||
router.Post("/device", h.postDevice)
|
||||
router.Post("/device", limiter.New(), h.postDevice)
|
||||
|
||||
router.Use(apikey.New(apikey.Config{
|
||||
Authorizer: func(token string) bool {
|
||||
|
||||
@ -10,7 +10,7 @@ type MessageState string
|
||||
|
||||
const (
|
||||
MessageStatePending MessageState = "Pending"
|
||||
MessageStateProcessed MessageState = "Processes"
|
||||
MessageStateProcessed MessageState = "Processed"
|
||||
MessageStateSent MessageState = "Sent"
|
||||
MessageStateDelivered MessageState = "Delivered"
|
||||
MessageStateFailed MessageState = "Failed"
|
||||
@ -47,7 +47,7 @@ type Message struct {
|
||||
ExtID string `gorm:"not null;type:varchar(36);uniqueIndex:unq_messages_id_device,priority:1"`
|
||||
Message string `gorm:"not null;type:tinytext"`
|
||||
State MessageState `gorm:"not null;type:enum('Pending','Sent','Processed','Delivered','Failed');default:Pending;index:idx_messages_device_state"`
|
||||
ValidUntil time.Time `gorm:"type:datetime"`
|
||||
ValidUntil *time.Time `gorm:"type:datetime"`
|
||||
|
||||
Device Device `gorm:"foreignKey:DeviceID;constraint:OnDelete:CASCADE"`
|
||||
Recipients []MessageRecipient `gorm:"foreignKey:MessageID;constraint:OnDelete:CASCADE"`
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"github.com/capcom6/sms-gateway/internal/sms-gateway/repositories"
|
||||
"github.com/capcom6/sms-gateway/pkg/slices"
|
||||
"github.com/capcom6/sms-gateway/pkg/smsgateway"
|
||||
"github.com/capcom6/sms-gateway/pkg/types"
|
||||
"github.com/jaevor/go-nanoid"
|
||||
"github.com/nyaruka/phonenumbers"
|
||||
)
|
||||
@ -45,8 +46,8 @@ func (s *MessagesService) SelectPending(deviceID string) ([]smsgateway.Message,
|
||||
result := make([]smsgateway.Message, len(messages))
|
||||
for i, v := range messages {
|
||||
var ttl *uint64 = nil
|
||||
if !v.ValidUntil.IsZero() {
|
||||
delta := time.Until(v.ValidUntil).Seconds()
|
||||
if v.ValidUntil != nil {
|
||||
delta := time.Until(*v.ValidUntil).Seconds()
|
||||
if delta > 0 {
|
||||
deltaInt := uint64(delta)
|
||||
ttl = &deltaInt
|
||||
@ -73,6 +74,10 @@ func (s *MessagesService) UpdateState(deviceID string, message smsgateway.Messag
|
||||
return err
|
||||
}
|
||||
|
||||
if message.State == smsgateway.MessageStatePending {
|
||||
message.State = smsgateway.MessageStateProcessed
|
||||
}
|
||||
|
||||
existing.State = models.MessageState(message.State)
|
||||
existing.Recipients = s.recipientsStateToModel(message.Recipients)
|
||||
|
||||
@ -113,9 +118,9 @@ func (s *MessagesService) Enqeue(device models.Device, message smsgateway.Messag
|
||||
}
|
||||
}
|
||||
|
||||
validUntil := time.Time{}
|
||||
var validUntil *time.Time = nil
|
||||
if message.TTL != nil && *message.TTL > 0 {
|
||||
validUntil = time.Now().Add(time.Duration(*message.TTL) * time.Second)
|
||||
validUntil = types.AsPointer(time.Now().Add(time.Duration(*message.TTL) * time.Second))
|
||||
}
|
||||
|
||||
msg := models.Message{
|
||||
@ -153,11 +158,11 @@ func (s *MessagesService) Enqeue(device models.Device, message smsgateway.Messag
|
||||
func (s *MessagesService) filterTimeouted(messages []models.Message) []models.Message {
|
||||
result := make([]models.Message, 0, len(messages))
|
||||
for _, v := range messages {
|
||||
if v.ValidUntil.IsZero() || time.Now().Before(v.ValidUntil) {
|
||||
if v.ValidUntil == nil || time.Now().Before(*v.ValidUntil) {
|
||||
result = append(result, v)
|
||||
} else if v.State == models.MessageStatePending {
|
||||
v.State = models.MessageStateFailed
|
||||
for i, _ := range v.Recipients {
|
||||
for i := range v.Recipients {
|
||||
v.Recipients[i].State = models.MessageStateFailed
|
||||
}
|
||||
s.Messages.UpdateState(&v)
|
||||
@ -192,8 +197,17 @@ func (s *MessagesService) recipientsStateToModel(input []smsgateway.RecipientSta
|
||||
output := make([]models.MessageRecipient, len(input))
|
||||
|
||||
for i, v := range input {
|
||||
phoneNumber := v.PhoneNumber
|
||||
if len(phoneNumber) > 0 && phoneNumber[0] != '+' {
|
||||
phoneNumber = "+" + phoneNumber
|
||||
}
|
||||
|
||||
if v.State == smsgateway.MessageStatePending {
|
||||
v.State = smsgateway.MessageStateProcessed
|
||||
}
|
||||
|
||||
output[i] = models.MessageRecipient{
|
||||
PhoneNumber: v.PhoneNumber,
|
||||
PhoneNumber: phoneNumber,
|
||||
State: models.MessageState(v.State),
|
||||
}
|
||||
}
|
||||
|
||||
86
internal/sms-gateway/services/messages_test.go
Normal file
86
internal/sms-gateway/services/messages_test.go
Normal file
@ -0,0 +1,86 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/capcom6/sms-gateway/internal/sms-gateway/models"
|
||||
"github.com/capcom6/sms-gateway/pkg/smsgateway"
|
||||
)
|
||||
|
||||
func TestMessagesService_recipientsStateToModel(t *testing.T) {
|
||||
type args struct {
|
||||
input []smsgateway.RecipientState
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
s *MessagesService
|
||||
args args
|
||||
want []models.MessageRecipient
|
||||
}{
|
||||
{
|
||||
name: "Without +",
|
||||
s: &MessagesService{},
|
||||
args: args{
|
||||
input: []smsgateway.RecipientState{
|
||||
{
|
||||
PhoneNumber: "79990001234",
|
||||
State: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []models.MessageRecipient{
|
||||
{
|
||||
MessageID: 0,
|
||||
PhoneNumber: "+79990001234",
|
||||
State: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "With +",
|
||||
s: &MessagesService{},
|
||||
args: args{
|
||||
input: []smsgateway.RecipientState{
|
||||
{
|
||||
PhoneNumber: "+79990001234",
|
||||
State: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []models.MessageRecipient{
|
||||
{
|
||||
MessageID: 0,
|
||||
PhoneNumber: "+79990001234",
|
||||
State: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Empty phone",
|
||||
s: &MessagesService{},
|
||||
args: args{
|
||||
input: []smsgateway.RecipientState{
|
||||
{
|
||||
PhoneNumber: "",
|
||||
State: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []models.MessageRecipient{
|
||||
{
|
||||
MessageID: 0,
|
||||
PhoneNumber: "",
|
||||
State: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.s.recipientsStateToModel(tt.args.input); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("MessagesService.recipientsStateToModel() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
5
pkg/types/types.go
Normal file
5
pkg/types/types.go
Normal file
@ -0,0 +1,5 @@
|
||||
package types
|
||||
|
||||
func AsPointer[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user