diff --git a/.appveyor.yml b/.appveyor.yml
deleted file mode 100644
index deb97ab1b..000000000
--- a/.appveyor.yml
+++ /dev/null
@@ -1,64 +0,0 @@
-version: '{build}'
-image: 'Visual Studio 2019'
-platform: x64
-
-max_jobs: 1
-
-environment:
- CGO_ENABLED: 0
- GOPATH: c:\go
- docker_username:
- secure: em/TNLUXxG19O/HvbvfJuQ==
- docker_password:
- secure: Yo9FJJqihaNz5q8T4Jz8tQ==
-
-branches:
- only:
- - master
-
-install:
- - ps: |
- choco install -y mingw
- docker version
- go version
-
-build_script:
- - ps: |
- if ( $env:APPVEYOR_REPO_TAG -eq 'false' ) {
- $version = $env:APPVEYOR_REPO_COMMIT
- $buildDate = $env:APPVEYOR_REPO_COMMIT_TIMESTAMP
- } else {
- $version = $env:APPVEYOR_REPO_TAG_NAME
- $buildDate = $env:APPVEYOR_REPO_COMMIT_TIMESTAMP
- }
- go build -a -o release/gorush.exe .
-
- docker pull microsoft/nanoserver:10.0.14393.1884
- docker build -f docker/Dockerfile.windows.amd64 -t appleboy/gorush:windows-amd64 .
-
-test_script:
- - ps: |
- docker run --rm appleboy/gorush:windows-amd64 --version
-
-deploy_script:
- - ps: |
- $ErrorActionPreference = 'Stop';
- if ( $env:APPVEYOR_PULL_REQUEST_NUMBER ) {
- Write-Host Nothing to deploy.
- } else {
- echo $env:DOCKER_PASSWORD | docker login --username $env:DOCKER_USERNAME --password-stdin
- if ( $env:APPVEYOR_REPO_TAG -eq 'true' ) {
- $major,$minor,$patch = $env:APPVEYOR_REPO_TAG_NAME.split('.')
- docker push appleboy/gorush:windows-amd64
- docker tag appleboy/gorush:windows-amd64 appleboy/gorush:$major.$minor.$patch-windows-amd64
- docker push appleboy/gorush:$major.$minor.$patch-windows-amd64
- docker tag appleboy/gorush:windows-amd64 appleboy/gorush:$major.$minor-windows-amd64
- docker push appleboy/gorush:$major.$minor-windows-amd64
- docker tag appleboy/gorush:windows-amd64 appleboy/gorush:$major-windows-amd64
- docker push appleboy/gorush:$major-windows-amd64
- } else {
- if ( $env:APPVEYOR_REPO_BRANCH -eq 'master' ) {
- docker push appleboy/gorush:windows-amd64
- }
- }
- }
diff --git a/.drone.yml b/.drone.yml
index 57b9f89bc..b0d245258 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -7,29 +7,11 @@ platform:
arch: amd64
steps:
-- name: vet
- pull: always
- image: golang:1.16
- commands:
- - make vet
- volumes:
- - name: gopath
- path: /go
-
- name: lint
pull: always
- image: golang:1.16
- commands:
- - make lint
- volumes:
- - name: gopath
- path: /go
-
-- name: misspell
- pull: always
- image: golang:1.16
+ image: golangci/golangci-lint:v1.41.1
commands:
- - make misspell-check
+ - golangci-lint run -v
volumes:
- name: gopath
path: /go
@@ -80,6 +62,11 @@ services:
- name: redis
image: redis
+- name: nsq
+ image: nsqio/nsq
+ commands:
+ - /nsqd
+
volumes:
- name: gopath
temp: {}
@@ -122,19 +109,6 @@ steps:
commands:
- ./release/linux/amd64/gorush --help
-- name: dryrun
- pull: always
- image: plugins/docker:linux-amd64
- settings:
- cache_from: appleboy/gorush
- dockerfile: docker/Dockerfile.linux.amd64
- dry_run: true
- repo: appleboy/gorush
- tags: linux-amd64
- when:
- event:
- - pull_request
-
- name: publish
pull: always
image: plugins/docker:linux-amd64
@@ -201,19 +175,6 @@ steps:
commands:
- ./release/linux/arm64/gorush --help
-- name: dryrun
- pull: always
- image: plugins/docker:linux-arm64
- settings:
- cache_from: appleboy/gorush
- dockerfile: docker/Dockerfile.linux.arm64
- dry_run: true
- repo: appleboy/gorush
- tags: linux-arm64
- when:
- event:
- - pull_request
-
- name: publish
pull: always
image: plugins/docker:linux-arm64
@@ -280,19 +241,6 @@ steps:
commands:
- ./release/linux/arm/gorush --help
-- name: dryrun
- pull: always
- image: plugins/docker:linux-arm
- settings:
- cache_from: appleboy/gorush
- dockerfile: docker/Dockerfile.linux.arm
- dry_run: true
- repo: appleboy/gorush
- tags: linux-arm
- when:
- event:
- - pull_request
-
- name: publish
pull: always
image: plugins/docker:linux-arm
diff --git a/.gitignore b/.gitignore
index 683a0e610..1fd9c9a88 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,3 +36,4 @@ custom
release
coverage.txt
node_modules
+config.yml
diff --git a/Makefile b/Makefile
index f10c03881..abed8186e 100644
--- a/Makefile
+++ b/Makefile
@@ -6,12 +6,11 @@ DEPLOY_ACCOUNT := appleboy
DEPLOY_IMAGE := $(EXECUTABLE)
GOFMT ?= gofumpt -l -s -extra
-TARGETS ?= linux darwin windows openbsd
-ARCHS ?= amd64 386
+TARGETS ?= linux darwin windows
+ARCHS ?= amd64
GOFILES := $(shell find . -name "*.go" -type f)
TAGS ?= sqlite
LDFLAGS ?= -X 'main.Version=$(VERSION)'
-NODE_PROTOC_PLUGIN := $(shell which grpc_tools_node_protoc_plugin)
ifneq ($(shell uname), Darwin)
EXTLDFLAGS = -extldflags "-static" $(null)
@@ -149,16 +148,14 @@ clean:
find . -name *.db -delete
-rm -rf release dist .cover
-rpc/example/node/gorush_*_pb.js: rpc/proto/gorush.proto
- @hash grpc_tools_node_protoc_plugin > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
- npm install -g grpc-tools; \
- fi
- protoc -I rpc/proto rpc/proto/gorush.proto --js_out=import_style=commonjs,binary:rpc/example/node/ --grpc_out=rpc/example/node/ --plugin=protoc-gen-grpc=$(NODE_PROTOC_PLUGIN)
+generate_proto_js:
+ npm install grpc-tools
+ protoc -I rpc/proto rpc/proto/gorush.proto --js_out=import_style=commonjs,binary:rpc/example/node/ --grpc_out=rpc/example/node/ --plugin=protoc-gen-grpc="node_modules/.bin/grpc_tools_node_protoc_plugin"
-rpc/proto/gorush.pb.go: rpc/proto/gorush.proto
- protoc -I rpc/proto rpc/proto/gorush.proto --go_out=plugins=grpc:rpc/proto
+generate_proto_go:
+ protoc -I rpc/proto rpc/proto/gorush.proto --go_out=rpc/proto --go-grpc_out=require_unimplemented_servers=false:rpc/proto
-generate_proto: rpc/proto/gorush.pb.go rpc/example/node/gorush_*_pb.js
+generate_proto: generate_proto_go generate_proto_js
version:
@echo $(VERSION)
diff --git a/README.md b/README.md
index a7661a6e6..6b3b9f2ca 100644
--- a/README.md
+++ b/README.md
@@ -4,14 +4,10 @@ A push notification micro server using [Gin](https://github.com/gin-gonic/gin) f
[](https://godoc.org/github.com/appleboy/gorush)
[](https://cloud.drone.io/appleboy/gorush)
-[](https://ci.appveyor.com/project/appleboy/gorush-fp5dh)
[](https://codecov.io/gh/appleboy/gorush)
[](https://goreportcard.com/report/github.com/appleboy/gorush)
[](https://codebeat.co/projects/github-com-appleboy-gorush)
-[](https://www.codacy.com/app/appleboy/gorush?utm_source=github.com&utm_medium=referral&utm_content=appleboy/gorush&utm_campaign=Badge_Grade)
[](https://hub.docker.com/r/appleboy/gorush/)
-[](https://microbadger.com/images/appleboy/gorush "Get your own image badge on microbadger.com")
-[](https://github.com/appleboy/gorush/releases/latest)
[](https://app.netlify.com/sites/gorush/deploys)
[](https://opencollective.com/gorush)
@@ -94,6 +90,7 @@ A push notification micro server using [Gin](https://github.com/gin-gonic/gin) f
- Support send notification through [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call) protocol, we use [gRPC](https://grpc.io/) as default framework.
- Support running in Docker, [Kubernetes](https://kubernetes.io/) or [AWS Lambda](https://aws.amazon.com/lambda) ([Native Support in Golang](https://aws.amazon.com/blogs/compute/announcing-go-support-for-aws-lambda/))
- Support graceful shutdown that workers and queue have been sent to APNs/FCM before shutdown service.
+- Support different Queue as backend like [NSQ](https://nsq.io/) or [NATS](https://nats.io/), defaut engine is local [Channel](https://tour.golang.org/concurrency/2).
See the default [YAML config example](config/testdata/config.yml):
@@ -145,11 +142,22 @@ android:
max_retry: 0 # resend fail notification, default value zero is disabled
huawei:
- enabled: true
+ enabled: false
appsecret: "YOUR_APP_SECRET"
appid: "YOUR_APP_ID"
max_retry: 0 # resend fail notification, default value zero is disabled
+queue:
+ engine: "local" # support "local", "nsq" and "nats " default value is "local"
+ nsq:
+ addr: 127.0.0.1:4150
+ topic: gorush
+ channel: gorush
+ nats:
+ addr: 127.0.0.1:4222
+ subj: gorush
+ queue: gorush
+
ios:
enabled: false
key_path: "key.pem"
@@ -173,7 +181,8 @@ log:
stat:
engine: "memory" # support memory, redis, boltdb, buntdb or leveldb
redis:
- addr: "localhost:6379"
+ cluster: false
+ addr: "localhost:6379" # if cluster is true, you may set this to "localhost:6379,localhost:6380,localhost:6381"
password: ""
db: 0
boltdb:
@@ -216,19 +225,19 @@ go get -u -v github.com/appleboy/gorush
On linux
```sh
-wget https://github.com/appleboy/gorush/releases/download/v1.13.0/gorush-v1.13.0-linux-amd64 -O gorush
+wget https://github.com/appleboy/gorush/releases/download/v1.14.0/gorush-v1.14.0-linux-amd64 -O gorush
```
On OS X
```sh
-wget https://github.com/appleboy/gorush/releases/download/v1.13.0/gorush-v1.13.0-darwin-amd64 -O gorush
+wget https://github.com/appleboy/gorush/releases/download/v1.14.0/gorush-v1.14.0-darwin-amd64 -O gorush
```
On Windows
```sh
-wget https://github.com/appleboy/gorush/releases/download/v1.13.0/gorush-v1.13.0-windows-amd64.exe -O gorush.exe
+wget https://github.com/appleboy/gorush/releases/download/v1.14.0/gorush-v1.14.0-windows-amd64.exe -O gorush.exe
```
On macOS, use Homebrew.
@@ -294,7 +303,7 @@ Huawei Options:
Common Options:
--topic iOS or Android topic message
-h, --help Show this message
- -v, --version Show version
+ -V, --version Show version
```
### Send Android notification
@@ -1042,7 +1051,7 @@ func main() {
Badge: 1,
Category: "test",
Sound: "test",
- Priority: proto.Priority_High,
+ Priority: proto.NotificationRequest_HIGH,
Alert: &proto.Alert{
Title: "Test Title",
Body: "Test Alert Body",
@@ -1062,10 +1071,13 @@ func main() {
},
})
if err != nil {
- log.Fatalf("could not greet: %v", err)
+ log.Println("could not greet: ", err)
+ }
+
+ if r != nil {
+ log.Printf("Success: %t\n", r.Success)
+ log.Printf("Count: %d\n", r.Counts)
}
- log.Printf("Success: %t\n", r.Success)
- log.Printf("Count: %d\n", r.Counts)
}
```
@@ -1144,7 +1156,7 @@ func main() {
Badge: 1,
Category: "test",
Sound: "test",
- Priority: proto.Priority_High,
+ Priority: proto.NotificationRequest_HIGH,
Alert: &proto.Alert{
Title: "Test Title",
Body: "Test Alert Body",
@@ -1164,10 +1176,13 @@ func main() {
},
})
if err != nil {
- log.Fatalf("could not greet: %v", err)
+ log.Println("could not greet: ", err)
+ }
+
+ if r != nil {
+ log.Printf("Success: %t\n", r.Success)
+ log.Printf("Count: %d\n", r.Counts)
}
- log.Printf("Success: %t\n", r.Success)
- log.Printf("Count: %d\n", r.Counts)
}
```
diff --git a/config/config.go b/config/config.go
index ce37a7c22..8cdb11ddf 100644
--- a/config/config.go
+++ b/config/config.go
@@ -57,11 +57,22 @@ android:
max_retry: 0 # resend fail notification, default value zero is disabled
huawei:
- enabled: true
+ enabled: false
appsecret: "YOUR_APP_SECRET"
appid: "YOUR_APP_ID"
max_retry: 0 # resend fail notification, default value zero is disabled
+queue:
+ engine: "local" # support "local", "nsq", default value is "local"
+ nsq:
+ addr: 127.0.0.1:4150
+ topic: gorush
+ channel: gorush
+ nats:
+ addr: 127.0.0.1:4222
+ subj: gorush
+ queue: gorush
+
ios:
enabled: false
key_path: ""
@@ -85,7 +96,8 @@ log:
stat:
engine: "memory" # support memory, redis, boltdb, buntdb or leveldb
redis:
- addr: "localhost:6379"
+ cluster: false
+ addr: "localhost:6379" # if cluster is true, you may set this to "localhost:6379,localhost:6380,localhost:6381"
password: ""
db: 0
boltdb:
@@ -106,6 +118,7 @@ type ConfYaml struct {
Android SectionAndroid `yaml:"android"`
Huawei SectionHuawei `yaml:"huawei"`
Ios SectionIos `yaml:"ios"`
+ Queue SectionQueue `yaml:"queue"`
Log SectionLog `yaml:"log"`
Stat SectionStat `yaml:"stat"`
GRPC SectionGRPC `yaml:"grpc"`
@@ -201,8 +214,30 @@ type SectionStat struct {
BadgerDB SectionBadgerDB `yaml:"badgerdb"`
}
+// SectionQueue is sub section of config.
+type SectionQueue struct {
+ Engine string `yaml:"engine"`
+ NSQ SectionNSQ `yaml:"nsq"`
+ NATS SectionNATS `yaml:"nats"`
+}
+
+// SectionNSQ is sub section of config.
+type SectionNSQ struct {
+ Addr string `yaml:"addr"`
+ Topic string `yaml:"topic"`
+ Channel string `yaml:"channel"`
+}
+
+// SectionNATS is sub section of config.
+type SectionNATS struct {
+ Addr string `yaml:"addr"`
+ Subj string `yaml:"subj"`
+ Queue string `yaml:"queue"`
+}
+
// SectionRedis is sub section of config.
type SectionRedis struct {
+ Cluster bool `yaml:"cluster"`
Addr string `yaml:"addr"`
Password string `yaml:"password"`
DB int `yaml:"db"`
@@ -243,16 +278,16 @@ type SectionGRPC struct {
}
// LoadConf load config from file and read in environment variables that match
-func LoadConf(confPath string) (ConfYaml, error) {
- var conf ConfYaml
+func LoadConf(confPath ...string) (*ConfYaml, error) {
+ conf := &ConfYaml{}
viper.SetConfigType("yaml")
viper.AutomaticEnv() // read in environment variables that match
viper.SetEnvPrefix("gorush") // will be uppercased automatically
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
- if confPath != "" {
- content, err := ioutil.ReadFile(confPath)
+ if len(confPath) > 0 && confPath[0] != "" {
+ content, err := ioutil.ReadFile(confPath[0])
if err != nil {
return conf, err
}
@@ -341,8 +376,18 @@ func LoadConf(confPath string) (ConfYaml, error) {
conf.Log.ErrorLevel = viper.GetString("log.error_level")
conf.Log.HideToken = viper.GetBool("log.hide_token")
+ // Queue Engine
+ conf.Queue.Engine = viper.GetString("queue.engine")
+ conf.Queue.NSQ.Addr = viper.GetString("queue.nsq.addr")
+ conf.Queue.NSQ.Topic = viper.GetString("queue.nsq.topic")
+ conf.Queue.NSQ.Channel = viper.GetString("queue.nsq.channel")
+ conf.Queue.NATS.Addr = viper.GetString("queue.nats.addr")
+ conf.Queue.NATS.Subj = viper.GetString("queue.nats.subj")
+ conf.Queue.NATS.Queue = viper.GetString("queue.nats.queue")
+
// Stat Engine
conf.Stat.Engine = viper.GetString("stat.engine")
+ conf.Stat.Redis.Cluster = viper.GetBool("stat.redis.cluster")
conf.Stat.Redis.Addr = viper.GetString("stat.redis.addr")
conf.Stat.Redis.Password = viper.GetString("stat.redis.password")
conf.Stat.Redis.DB = viper.GetInt("stat.redis.db")
diff --git a/config/config_test.go b/config/config_test.go
index ef7e5d372..ec3df0311 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -19,13 +19,13 @@ func TestMissingFile(t *testing.T) {
type ConfigTestSuite struct {
suite.Suite
- ConfGorushDefault ConfYaml
- ConfGorush ConfYaml
+ ConfGorushDefault *ConfYaml
+ ConfGorush *ConfYaml
}
func (suite *ConfigTestSuite) SetupTest() {
var err error
- suite.ConfGorushDefault, err = LoadConf("")
+ suite.ConfGorushDefault, err = LoadConf()
if err != nil {
panic("failed to load default config.yml")
}
@@ -88,6 +88,16 @@ func (suite *ConfigTestSuite) TestValidateConfDefault() {
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Ios.KeyID)
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Ios.TeamID)
+ // queue
+ assert.Equal(suite.T(), "local", suite.ConfGorushDefault.Queue.Engine)
+ assert.Equal(suite.T(), "127.0.0.1:4150", suite.ConfGorushDefault.Queue.NSQ.Addr)
+ assert.Equal(suite.T(), "gorush", suite.ConfGorushDefault.Queue.NSQ.Topic)
+ assert.Equal(suite.T(), "gorush", suite.ConfGorushDefault.Queue.NSQ.Channel)
+
+ assert.Equal(suite.T(), "127.0.0.1:4222", suite.ConfGorushDefault.Queue.NATS.Addr)
+ assert.Equal(suite.T(), "gorush", suite.ConfGorushDefault.Queue.NATS.Subj)
+ assert.Equal(suite.T(), "gorush", suite.ConfGorushDefault.Queue.NATS.Queue)
+
// log
assert.Equal(suite.T(), "string", suite.ConfGorushDefault.Log.Format)
assert.Equal(suite.T(), "stdout", suite.ConfGorushDefault.Log.AccessLog)
@@ -97,6 +107,7 @@ func (suite *ConfigTestSuite) TestValidateConfDefault() {
assert.Equal(suite.T(), true, suite.ConfGorushDefault.Log.HideToken)
assert.Equal(suite.T(), "memory", suite.ConfGorushDefault.Stat.Engine)
+ assert.Equal(suite.T(), false, suite.ConfGorushDefault.Stat.Redis.Cluster)
assert.Equal(suite.T(), "localhost:6379", suite.ConfGorushDefault.Stat.Redis.Addr)
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Stat.Redis.Password)
assert.Equal(suite.T(), 0, suite.ConfGorushDefault.Stat.Redis.DB)
@@ -174,6 +185,7 @@ func (suite *ConfigTestSuite) TestValidateConf() {
assert.Equal(suite.T(), true, suite.ConfGorush.Log.HideToken)
assert.Equal(suite.T(), "memory", suite.ConfGorush.Stat.Engine)
+ assert.Equal(suite.T(), false, suite.ConfGorush.Stat.Redis.Cluster)
assert.Equal(suite.T(), "localhost:6379", suite.ConfGorush.Stat.Redis.Addr)
assert.Equal(suite.T(), "", suite.ConfGorush.Stat.Redis.Password)
assert.Equal(suite.T(), 0, suite.ConfGorush.Stat.Redis.DB)
@@ -215,6 +227,6 @@ func TestLoadConfigFromEnv(t *testing.T) {
func TestLoadWrongDefaultYAMLConfig(t *testing.T) {
defaultConf = []byte(`a`)
- _, err := LoadConf("")
+ _, err := LoadConf()
assert.Error(t, err)
}
diff --git a/config/testdata/config.yml b/config/testdata/config.yml
index 34d786111..daa3b9385 100644
--- a/config/testdata/config.yml
+++ b/config/testdata/config.yml
@@ -44,11 +44,22 @@ android:
max_retry: 0 # resend fail notification, default value zero is disabled
huawei:
- enabled: true
+ enabled: false
appsecret: "YOUR_APP_SECRET"
appid: "YOUR_APP_ID"
max_retry: 0 # resend fail notification, default value zero is disabled
+queue:
+ engine: "local" # support "local", "nsq" and "nats " default value is "local"
+ nsq:
+ addr: 127.0.0.1:4150
+ topic: gorush
+ channel: gorush
+ nats:
+ addr: 127.0.0.1:4222
+ subj: gorush
+ queue: gorush
+
ios:
enabled: false
key_path: "key.pem"
@@ -72,7 +83,8 @@ log:
stat:
engine: "memory" # support memory, redis, boltdb, buntdb or leveldb
redis:
- addr: "localhost:6379"
+ cluster: false
+ addr: "localhost:6379" # if cluster is true, you may set this to "localhost:6379,localhost:6380,localhost:6381"
password: ""
db: 0
boltdb:
diff --git a/core/core.go b/core/core.go
new file mode 100644
index 000000000..4791bb025
--- /dev/null
+++ b/core/core.go
@@ -0,0 +1,17 @@
+package core
+
+const (
+ // PlatFormIos constant is 1 for iOS
+ PlatFormIos = iota + 1
+ // PlatFormAndroid constant is 2 for Android
+ PlatFormAndroid
+ // PlatFormHuawei constant is 3 for Huawei
+ PlatFormHuawei
+)
+
+const (
+ // SucceededPush is log block
+ SucceededPush = "succeeded-push"
+ // FailedPush is log block
+ FailedPush = "failed-push"
+)
diff --git a/core/queue.go b/core/queue.go
new file mode 100644
index 000000000..2e1efab17
--- /dev/null
+++ b/core/queue.go
@@ -0,0 +1,18 @@
+package core
+
+// Queue as backend
+type Queue string
+
+var (
+ // LocalQueue for channel in Go
+ LocalQueue Queue = "local"
+ // NSQ a realtime distributed messaging platform
+ NSQ Queue = "nsq"
+ // NATS Connective Technology for Adaptive Edge & Distributed Systems
+ NATS Queue = "nats"
+)
+
+// IsLocalQueue check is Local Queue
+func IsLocalQueue(q Queue) bool {
+ return q == LocalQueue
+}
diff --git a/docker/Dockerfile.linux.amd64 b/docker/Dockerfile.linux.amd64
index 33be19615..784ea73e4 100644
--- a/docker/Dockerfile.linux.amd64
+++ b/docker/Dockerfile.linux.amd64
@@ -8,7 +8,7 @@ LABEL maintainer="Bo-Yi Wu " \
COPY release/linux/amd64/gorush /bin/
EXPOSE 8088 9000
-HEALTHCHECK --start-period=2s --interval=10s --timeout=5s \
+HEALTHCHECK --start-period=1s --interval=10s --timeout=5s \
CMD ["/bin/gorush", "--ping"]
ENTRYPOINT ["/bin/gorush"]
diff --git a/docker/Dockerfile.linux.arm b/docker/Dockerfile.linux.arm
index df81791f8..7e06c24c2 100644
--- a/docker/Dockerfile.linux.arm
+++ b/docker/Dockerfile.linux.arm
@@ -8,7 +8,7 @@ LABEL maintainer="Bo-Yi Wu " \
COPY release/linux/arm/gorush /bin/
EXPOSE 8088 9000
-HEALTHCHECK --start-period=2s --interval=10s --timeout=5s \
+HEALTHCHECK --start-period=1s --interval=10s --timeout=5s \
CMD ["/bin/gorush", "--ping"]
ENTRYPOINT ["/bin/gorush"]
diff --git a/docker/Dockerfile.linux.arm64 b/docker/Dockerfile.linux.arm64
index 0372a26c4..cc4206298 100644
--- a/docker/Dockerfile.linux.arm64
+++ b/docker/Dockerfile.linux.arm64
@@ -8,7 +8,7 @@ LABEL maintainer="Bo-Yi Wu " \
COPY release/linux/arm64/gorush /bin/
EXPOSE 8088 9000
-HEALTHCHECK --start-period=2s --interval=10s --timeout=5s \
+HEALTHCHECK --start-period=1s --interval=10s --timeout=5s \
CMD ["/bin/gorush", "--ping"]
ENTRYPOINT ["/bin/gorush"]
diff --git a/docker/Dockerfile.windows.amd64 b/docker/Dockerfile.windows.amd64
index 79f8f3be0..db2faa237 100644
--- a/docker/Dockerfile.windows.amd64
+++ b/docker/Dockerfile.windows.amd64
@@ -8,7 +8,7 @@ LABEL maintainer="Bo-Yi Wu " \
COPY release/gorush.exe C:/bin/gorush.exe
EXPOSE 8088 9000
-HEALTHCHECK --start-period=2s --interval=10s --timeout=5s \
+HEALTHCHECK --start-period=1s --interval=10s --timeout=5s \
CMD ["\\gorush.exe", "--ping"]
ENTRYPOINT [ "C:\\bin\\gorush.exe" ]
diff --git a/go.mod b/go.mod
index 6f3f320bb..9ed63a10c 100644
--- a/go.mod
+++ b/go.mod
@@ -9,16 +9,22 @@ require (
github.com/appleboy/gofight/v2 v2.1.2
github.com/asdine/storm/v3 v3.2.1
github.com/buger/jsonparser v1.1.1
- github.com/dgraph-io/badger/v2 v2.2007.2
- github.com/gin-contrib/logger v0.0.2
- github.com/gin-gonic/gin v1.6.3
- github.com/go-redis/redis/v7 v7.4.0
- github.com/golang/protobuf v1.5.1
+ github.com/dgraph-io/badger/v3 v3.2103.1
+ github.com/gin-contrib/logger v0.2.0
+ github.com/gin-gonic/gin v1.7.4
+ github.com/go-redis/redis/v8 v8.11.3
+ github.com/golang-queue/nats v0.0.2
+ github.com/golang-queue/nsq v0.0.2
+ github.com/golang-queue/queue v0.0.7
+ github.com/golang/glog v0.0.0-20210429001901-424d2337a529 // indirect
+ github.com/golang/protobuf v1.5.2
+ github.com/google/flatbuffers v2.0.0+incompatible // indirect
+ github.com/json-iterator/go v1.1.10
github.com/mattn/go-isatty v0.0.12
github.com/mitchellh/mapstructure v1.4.1
- github.com/msalihkarakasli/go-hms-push v0.0.0-20200616114002-91cd23dfeed4
+ github.com/msalihkarakasli/go-hms-push v0.0.0-20210731212030-00e7b986815b
github.com/prometheus/client_golang v1.10.0
- github.com/rs/zerolog v1.21.0
+ github.com/rs/zerolog v1.23.0
github.com/sideshow/apns2 v0.20.0
github.com/sirupsen/logrus v1.8.1
github.com/spf13/viper v1.7.1
@@ -26,9 +32,9 @@ require (
github.com/syndtr/goleveldb v1.0.0
github.com/thoas/stats v0.0.0-20190407194641-965cb2de1678
github.com/tidwall/buntdb v1.2.0
- golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
- golang.org/x/net v0.0.0-20210326220855-61e056675ecf
+ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
+ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
google.golang.org/grpc v1.36.1
- google.golang.org/protobuf v1.26.0
+ google.golang.org/protobuf v1.27.1
)
diff --git a/go.sum b/go.sum
index 8b722ff68..8365407c6 100644
--- a/go.sum
+++ b/go.sum
@@ -81,6 +81,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
@@ -89,14 +90,16 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
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/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k=
-github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
-github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA=
-github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
+github.com/dgraph-io/badger/v3 v3.2103.1 h1:zaX53IRg7ycxVlkd5pYdCeFp1FynD6qBGQoQql3R3Hk=
+github.com/dgraph-io/badger/v3 v3.2103.1/go.mod h1:dULbq6ehJ5K0cGW/1TQ9iSfUk0gbSiToDWmWmTsJ53E=
+github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI=
+github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
@@ -113,20 +116,20 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fukata/golang-stats-api-handler v1.0.0 h1:N6M25vhs1yAvwGBpFY6oBmMOZeJdcWnvA+wej8pKeko=
github.com/fukata/golang-stats-api-handler v1.0.0/go.mod h1:1sIi4/rHq6s/ednWMZqTmRq3765qTUSs/c3xF6lj8J8=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gin-contrib/logger v0.0.2 h1:qT6qOR9/mp9hrHAgTEVxpjvS3anQtiUTtzJhf+NlBQM=
-github.com/gin-contrib/logger v0.0.2/go.mod h1:Eca5g93bobBwWSNeuLdTqRvNK6btb3XSHdU9ePZ+toM=
-github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
+github.com/gin-contrib/logger v0.2.0 h1:YkdOGKdm/Nnrrd3bjBjcjd3ow1kR2KUfxxP4/rlL23E=
+github.com/gin-contrib/logger v0.2.0/go.mod h1:dYxbt3GB+rvPyJSvox5lLsnKYwh8PjWrC9TQtR+hpUw=
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.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
-github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
-github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
+github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
+github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
+github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -142,19 +145,32 @@ github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTM
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
-github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
-github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
-github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4=
-github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
+github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
+github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
+github.com/go-redis/redis/v8 v8.11.3 h1:GCjoYp8c+yQTJfc0n69iwSiHjvuAdruxl7elnZCxgt8=
+github.com/go-redis/redis/v8 v8.11.3/go.mod h1:xNJ9xDG09FsIPwh3bWdk+0oDWHbtF9rPN0F/oD9XeKc=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-queue/nats v0.0.2 h1:81Ege/02a9d2a1SDN2/t1S1XIr/JpY+s8xj/pLZIHXM=
+github.com/golang-queue/nats v0.0.2/go.mod h1:dzXOwbx20CJ5oX4UiBIDyfedCiR5sBWWKJVXmiRlDYc=
+github.com/golang-queue/nsq v0.0.2 h1:kP4fMLl1K6TNlJGq3tJ4t07e703mDGiMYLLltT8F4/Q=
+github.com/golang-queue/nsq v0.0.2/go.mod h1:1Q/8y4BclWLj03sn0dApJIObatC3qMX5gLjlbo0TwXs=
+github.com/golang-queue/queue v0.0.7 h1:WENCPyPBcIWYgBFSAZ8USGtwmxeCeMkhjwuyM0MAi84=
+github.com/golang-queue/queue v0.0.7/go.mod h1:JS5tYJacahCjafcplU5idNLX2vkYioqh6wEDX5o9Nms=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/glog v0.0.0-20210429001901-424d2337a529 h1:2voWjNECnrZRbfwXxHB1/j8wa6xdKn85B5NzgVL/pTU=
+github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -172,21 +188,26 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.1 h1:jAbXjIeW2ZSW2AwFxlGTDoc2CjI2XujLkV3ArsZFCvc=
-github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/flatbuffers v1.12.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
+github.com/google/flatbuffers v2.0.0+incompatible h1:dicJ2oXwypfwUGnB2/TYWYEKiuk9eYQlQO/AnOHl5mI=
+github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-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/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -232,7 +253,6 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
@@ -252,7 +272,11 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.11.12/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU=
+github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -273,7 +297,6 @@ github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
@@ -281,6 +304,8 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0=
+github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -297,28 +322,48 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/msalihkarakasli/go-hms-push v0.0.0-20200616114002-91cd23dfeed4 h1:3cAiZwpOmIXbP+3/SAriDi9XlxBwZCGhS0UGhnlYhi0=
-github.com/msalihkarakasli/go-hms-push v0.0.0-20200616114002-91cd23dfeed4/go.mod h1:4X2lQHsWGt+e3uRK124A6ndq3IIVymTAzEI9A1kIQKc=
+github.com/msalihkarakasli/go-hms-push v0.0.0-20210731212030-00e7b986815b h1:GPoWsisltEZb9Itu1MMCXCUsYMKqC51nIG+3EqA3MdE=
+github.com/msalihkarakasli/go-hms-push v0.0.0-20210731212030-00e7b986815b/go.mod h1:4X2lQHsWGt+e3uRK124A6ndq3IIVymTAzEI9A1kIQKc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/jwt v1.2.2 h1:w3GMTO969dFg+UOKTmmyuu7IGdusK+7Ytlt//OYH/uU=
+github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q=
+github.com/nats-io/jwt/v2 v2.0.3 h1:i/O6cmIsjpcQyWDYNcq2JyZ3/VTF8SJ4JWluI5OhpvI=
+github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
+github.com/nats-io/nats-server/v2 v2.3.4 h1:WcNa6HDFX8gjZPHb8CJ9wxRHEjJSlhWUb/MKb6/mlUY=
+github.com/nats-io/nats-server/v2 v2.3.4/go.mod h1:3mtbaN5GkCo/Z5T3nNj0I0/W1fPkKzLiDC6jjWJKp98=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
+github.com/nats-io/nats.go v1.11.1-0.20210623165838-4b75fc59ae30 h1:9GqilBhZaR3xYis0JgMlJjNw933WIobdjKhilXm+Vls=
+github.com/nats-io/nats.go v1.11.1-0.20210623165838-4b75fc59ae30/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
+github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
+github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
+github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/nsqio/go-nsq v1.0.8 h1:3L2F8tNLlwXXlp2slDUrUWSBn2O3nMh8R1/KEDFTHPk=
+github.com/nsqio/go-nsq v1.0.8/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
-github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
-github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
+github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
@@ -380,9 +425,8 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
-github.com/rs/zerolog v1.16.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
-github.com/rs/zerolog v1.21.0 h1:Q3vdXlfLNT+OftyBHsU0Y445MD+8m8axjKgf2si0QcM=
-github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM=
+github.com/rs/zerolog v1.23.0 h1:UskrK+saS9P9Y789yNNulYKdARjPZuS35B8gJF2x60g=
+github.com/rs/zerolog v1.23.0/go.mod h1:6c7hFfxPOy7TacJc4Fcdi24/J0NKYGzjG8FWRI916Qo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
@@ -458,7 +502,6 @@ github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=
github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
@@ -471,8 +514,8 @@ github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaU
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
@@ -483,6 +526,8 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=
+go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -499,9 +544,11 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
-golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -521,6 +568,7 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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=
@@ -540,13 +588,14 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210326220855-61e056675ecf h1:WUcCxqQqDT0aXO4VnQbfMvp4zh7m1Gb2clVuHUAGGRE=
-golang.org/x/net v0.0.0-20210326220855-61e056675ecf/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -569,8 +618,8 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -578,12 +627,13 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -593,21 +643,26 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg=
-golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
+golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -624,7 +679,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -632,6 +686,9 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
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=
@@ -687,8 +744,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
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=
@@ -696,11 +754,9 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
-gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@@ -714,8 +770,9 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/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-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/gorush/const.go b/gorush/const.go
deleted file mode 100644
index ac1a82c45..000000000
--- a/gorush/const.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package gorush
-
-const (
- // PlatFormIos constant is 1 for iOS
- PlatFormIos = iota + 1
- // PlatFormAndroid constant is 2 for Android
- PlatFormAndroid
- // PlatFormHuawei constant is 3 for Huawei
- PlatFormHuawei
-)
-
-const (
- // SucceededPush is log block
- SucceededPush = "succeeded-push"
- // FailedPush is log block
- FailedPush = "failed-push"
-)
-
-// Stat variable for redis
-const (
- TotalCountKey = "gorush-total-count"
- IosSuccessKey = "gorush-ios-success-count"
- IosErrorKey = "gorush-ios-error-count"
- AndroidSuccessKey = "gorush-android-success-count"
- AndroidErrorKey = "gorush-android-error-count"
- HuaweiSuccessKey = "gorush-huawei-success-count"
- HuaweiErrorKey = "gorush-huawei-error-count"
-)
diff --git a/gorush/global.go b/gorush/global.go
deleted file mode 100644
index 11a2d601e..000000000
--- a/gorush/global.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package gorush
-
-import (
- "github.com/appleboy/gorush/config"
- "github.com/appleboy/gorush/storage"
-
- "github.com/appleboy/go-fcm"
- "github.com/msalihkarakasli/go-hms-push/push/core"
- "github.com/sideshow/apns2"
- "github.com/sirupsen/logrus"
-)
-
-var (
- // PushConf is gorush config
- PushConf config.ConfYaml
- // QueueNotification is chan type
- QueueNotification chan PushNotification
- // ApnsClient is apns client
- ApnsClient *apns2.Client
- // FCMClient is apns client
- FCMClient *fcm.Client
- // HMSClient is Huawei push client
- HMSClient *core.HMSClient
- // LogAccess is log server request log
- LogAccess *logrus.Logger
- // LogError is log server error log
- LogError *logrus.Logger
- // StatStorage implements the storage interface
- StatStorage storage.Storage
- // MaxConcurrentIOSPushes pool to limit the number of concurrent iOS pushes
- MaxConcurrentIOSPushes chan struct{}
-)
diff --git a/gorush/log_test.go b/gorush/log_test.go
deleted file mode 100644
index be2867af6..000000000
--- a/gorush/log_test.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package gorush
-
-import (
- "testing"
-
- "github.com/appleboy/gorush/config"
- "github.com/sirupsen/logrus"
- "github.com/stretchr/testify/assert"
-)
-
-func TestSetLogLevel(t *testing.T) {
- log := logrus.New()
-
- err := SetLogLevel(log, "debug")
- assert.Nil(t, err)
-
- err = SetLogLevel(log, "invalid")
- assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
-}
-
-func TestSetLogOut(t *testing.T) {
- log := logrus.New()
-
- err := SetLogOut(log, "stdout")
- assert.Nil(t, err)
-
- err = SetLogOut(log, "stderr")
- assert.Nil(t, err)
-
- err = SetLogOut(log, "log/access.log")
- assert.Nil(t, err)
-
- // missing create logs folder.
- err = SetLogOut(log, "logs/access.log")
- assert.NotNil(t, err)
-}
-
-func TestInitDefaultLog(t *testing.T) {
- PushConf, _ = config.LoadConf("")
-
- // no errors on default config
- assert.Nil(t, InitLog())
-
- PushConf.Log.AccessLevel = "invalid"
-
- assert.NotNil(t, InitLog())
-}
-
-func TestAccessLevel(t *testing.T) {
- PushConf, _ = config.LoadConf("")
-
- PushConf.Log.AccessLevel = "invalid"
-
- assert.NotNil(t, InitLog())
-}
-
-func TestErrorLevel(t *testing.T) {
- PushConf, _ = config.LoadConf("")
-
- PushConf.Log.ErrorLevel = "invalid"
-
- assert.NotNil(t, InitLog())
-}
-
-func TestAccessLogPath(t *testing.T) {
- PushConf, _ = config.LoadConf("")
-
- PushConf.Log.AccessLog = "logs/access.log"
-
- assert.NotNil(t, InitLog())
-}
-
-func TestErrorLogPath(t *testing.T) {
- PushConf, _ = config.LoadConf("")
-
- PushConf.Log.ErrorLog = "logs/error.log"
-
- assert.NotNil(t, InitLog())
-}
-
-func TestPlatFormType(t *testing.T) {
- assert.Equal(t, "ios", typeForPlatForm(PlatFormIos))
- assert.Equal(t, "android", typeForPlatForm(PlatFormAndroid))
- assert.Equal(t, "", typeForPlatForm(10000))
-}
-
-func TestPlatFormColor(t *testing.T) {
- assert.Equal(t, blue, colorForPlatForm(PlatFormIos))
- assert.Equal(t, yellow, colorForPlatForm(PlatFormAndroid))
- assert.Equal(t, reset, colorForPlatForm(1000000))
-}
-
-func TestHideToken(t *testing.T) {
- assert.Equal(t, "", hideToken("", 2))
- assert.Equal(t, "**345678**", hideToken("1234567890", 2))
- assert.Equal(t, "*****", hideToken("12345", 10))
-}
diff --git a/gorush/notification_hms_test.go b/gorush/notification_hms_test.go
deleted file mode 100644
index 81dcd349b..000000000
--- a/gorush/notification_hms_test.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package gorush
-
-import (
- "context"
- "log"
- "sync"
- "testing"
-
- "github.com/appleboy/gorush/config"
- "github.com/stretchr/testify/assert"
-)
-
-func init() {
- PushConf, _ = config.LoadConf("")
- if err := InitLog(); err != nil {
- log.Fatal(err)
- }
-
- ctx := context.Background()
- wg := &sync.WaitGroup{}
- wg.Add(int(PushConf.Core.WorkerNum))
- InitWorkers(ctx, wg, PushConf.Core.WorkerNum, PushConf.Core.QueueNum)
-
- if err := InitAppStatus(); err != nil {
- log.Fatal(err)
- }
-}
-
-func TestMissingHuaweiAppSecret(t *testing.T) {
- PushConf, _ = config.LoadConf("")
-
- PushConf.Huawei.Enabled = true
- PushConf.Huawei.AppSecret = ""
-
- err := CheckPushConf()
-
- assert.Error(t, err)
- assert.Equal(t, "Missing Huawei App Secret", err.Error())
-}
-
-func TestMissingHuaweiAppID(t *testing.T) {
- PushConf, _ = config.LoadConf("")
-
- PushConf.Huawei.Enabled = true
- PushConf.Huawei.AppID = ""
-
- err := CheckPushConf()
-
- assert.Error(t, err)
- assert.Equal(t, "Missing Huawei App ID", err.Error())
-}
-
-func TestMissingAppSecretForInitHMSClient(t *testing.T) {
- client, err := InitHMSClient("", "APP_SECRET")
-
- assert.Nil(t, client)
- assert.Error(t, err)
- assert.Equal(t, "Missing Huawei App Secret", err.Error())
-}
-
-func TestMissingAppIDForInitHMSClient(t *testing.T) {
- client, err := InitHMSClient("APP_ID", "")
-
- assert.Nil(t, client)
- assert.Error(t, err)
- assert.Equal(t, "Missing Huawei App ID", err.Error())
-}
diff --git a/gorush/notification_test.go b/gorush/notification_test.go
deleted file mode 100644
index ca0ff9c97..000000000
--- a/gorush/notification_test.go
+++ /dev/null
@@ -1,217 +0,0 @@
-package gorush
-
-import (
- "context"
- "os"
- "testing"
-
- "github.com/appleboy/gorush/config"
- "github.com/stretchr/testify/assert"
-)
-
-func TestCorrectConf(t *testing.T) {
- PushConf, _ = config.LoadConf("")
-
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = "xxxxx"
-
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "../certificate/certificate-valid.pem"
-
- err := CheckPushConf()
-
- assert.NoError(t, err)
-}
-
-func TestSenMultipleNotifications(t *testing.T) {
- ctx := context.Background()
- PushConf, _ = config.LoadConf("")
-
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "../certificate/certificate-valid.pem"
- err := InitAPNSClient()
- assert.Nil(t, err)
-
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
-
- androidToken := os.Getenv("ANDROID_TEST_TOKEN")
-
- req := RequestPush{
- Notifications: []PushNotification{
- // ios
- {
- Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
- Platform: PlatFormIos,
- Message: "Welcome",
- },
- // android
- {
- Tokens: []string{androidToken, "bbbbb"},
- Platform: PlatFormAndroid,
- Message: "Welcome",
- },
- },
- }
-
- count, logs := queueNotification(ctx, req)
- assert.Equal(t, 3, count)
- assert.Equal(t, 0, len(logs))
-}
-
-func TestDisabledAndroidNotifications(t *testing.T) {
- ctx := context.Background()
- PushConf, _ = config.LoadConf("")
-
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "../certificate/certificate-valid.pem"
- err := InitAPNSClient()
- assert.Nil(t, err)
-
- PushConf.Android.Enabled = false
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
-
- androidToken := os.Getenv("ANDROID_TEST_TOKEN")
-
- req := RequestPush{
- Notifications: []PushNotification{
- // ios
- {
- Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
- Platform: PlatFormIos,
- Message: "Welcome",
- },
- // android
- {
- Tokens: []string{androidToken, "bbbbb"},
- Platform: PlatFormAndroid,
- Message: "Welcome",
- },
- },
- }
-
- count, logs := queueNotification(ctx, req)
- assert.Equal(t, 1, count)
- assert.Equal(t, 0, len(logs))
-}
-
-func TestSyncModeForNotifications(t *testing.T) {
- ctx := context.Background()
- PushConf, _ = config.LoadConf("")
-
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "../certificate/certificate-valid.pem"
- err := InitAPNSClient()
- assert.Nil(t, err)
-
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
-
- // enable sync mode
- PushConf.Core.Sync = true
-
- androidToken := os.Getenv("ANDROID_TEST_TOKEN")
-
- req := RequestPush{
- Notifications: []PushNotification{
- // ios
- {
- Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
- Platform: PlatFormIos,
- Message: "Welcome",
- },
- // android
- {
- Tokens: []string{androidToken, "bbbbb"},
- Platform: PlatFormAndroid,
- Message: "Welcome",
- },
- },
- }
-
- count, logs := queueNotification(ctx, req)
- assert.Equal(t, 3, count)
- assert.Equal(t, 2, len(logs))
-}
-
-func TestSyncModeForTopicNotification(t *testing.T) {
- ctx := context.Background()
- PushConf, _ = config.LoadConf("")
-
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
- PushConf.Log.HideToken = false
-
- // enable sync mode
- PushConf.Core.Sync = true
-
- req := RequestPush{
- Notifications: []PushNotification{
- // android
- {
- // error:InvalidParameters
- // Check that the provided parameters have the right name and type.
- To: "/topics/foo-bar@@@##",
- Platform: PlatFormAndroid,
- Message: "This is a Firebase Cloud Messaging Topic Message!",
- },
- // android
- {
- // success
- To: "/topics/foo-bar",
- Platform: PlatFormAndroid,
- Message: "This is a Firebase Cloud Messaging Topic Message!",
- },
- // android
- {
- // success
- Condition: "'dogs' in topics || 'cats' in topics",
- Platform: PlatFormAndroid,
- Message: "This is a Firebase Cloud Messaging Topic Message!",
- },
- },
- }
-
- count, logs := queueNotification(ctx, req)
- assert.Equal(t, 2, count)
- assert.Equal(t, 1, len(logs))
-}
-
-func TestSyncModeForDeviceGroupNotification(t *testing.T) {
- ctx := context.Background()
- PushConf, _ = config.LoadConf("")
-
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
- PushConf.Log.HideToken = false
-
- // enable sync mode
- PushConf.Core.Sync = true
-
- req := RequestPush{
- Notifications: []PushNotification{
- // android
- {
- To: "aUniqueKey",
- Platform: PlatFormAndroid,
- Message: "This is a Firebase Cloud Messaging Device Group Message!",
- },
- },
- }
-
- count, logs := queueNotification(ctx, req)
- assert.Equal(t, 1, count)
- assert.Equal(t, 1, len(logs))
-}
-
-func TestSetProxyURL(t *testing.T) {
- err := SetProxy("87.236.233.92:8080")
- assert.Error(t, err)
- assert.Equal(t, "parse \"87.236.233.92:8080\": invalid URI for request", err.Error())
-
- err = SetProxy("a.html")
- assert.Error(t, err)
-
- err = SetProxy("http://87.236.233.92:8080")
- assert.NoError(t, err)
-}
diff --git a/gorush/server.go b/gorush/server.go
deleted file mode 100644
index 952f8e560..000000000
--- a/gorush/server.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package gorush
-
-import (
- "context"
- "crypto/tls"
- "fmt"
- "net/http"
- "os"
- "regexp"
-
- api "github.com/appleboy/gin-status-api"
- "github.com/gin-contrib/logger"
- "github.com/gin-gonic/gin"
- "github.com/gin-gonic/gin/binding"
- "github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/promhttp"
- "github.com/rs/zerolog"
- "github.com/rs/zerolog/log"
- "golang.org/x/crypto/acme/autocert"
-)
-
-var rxURL = regexp.MustCompile(`^/healthz$`)
-
-func init() {
- // Support metrics
- m := NewMetrics()
- prometheus.MustRegister(m)
-}
-
-func abortWithError(c *gin.Context, code int, message string) {
- c.AbortWithStatusJSON(code, gin.H{
- "code": code,
- "message": message,
- })
-}
-
-func rootHandler(c *gin.Context) {
- c.JSON(http.StatusOK, gin.H{
- "text": "Welcome to notification server.",
- })
-}
-
-func heartbeatHandler(c *gin.Context) {
- c.AbortWithStatus(http.StatusOK)
-}
-
-func versionHandler(c *gin.Context) {
- c.JSON(http.StatusOK, gin.H{
- "source": "https://github.com/appleboy/gorush",
- "version": GetVersion(),
- })
-}
-
-func pushHandler(c *gin.Context) {
- var form RequestPush
- var msg string
-
- if err := c.ShouldBindWith(&form, binding.JSON); err != nil {
- msg = "Missing notifications field."
- LogAccess.Debug(err)
- abortWithError(c, http.StatusBadRequest, msg)
- return
- }
-
- if len(form.Notifications) == 0 {
- msg = "Notifications field is empty."
- LogAccess.Debug(msg)
- abortWithError(c, http.StatusBadRequest, msg)
- return
- }
-
- if int64(len(form.Notifications)) > PushConf.Core.MaxNotification {
- msg = fmt.Sprintf("Number of notifications(%d) over limit(%d)", len(form.Notifications), PushConf.Core.MaxNotification)
- LogAccess.Debug(msg)
- abortWithError(c, http.StatusBadRequest, msg)
- return
- }
-
- ctx, cancel := context.WithCancel(context.Background())
- go func() {
- // Deprecated: the CloseNotifier interface predates Go's context package.
- // New code should use Request.Context instead.
- // Change to context package
- <-c.Request.Context().Done()
- // Don't send notification after client timeout or disconnected.
- // See the following issue for detail information.
- // https://github.com/appleboy/gorush/issues/422
- if PushConf.Core.Sync {
- cancel()
- }
- }()
-
- counts, logs := queueNotification(ctx, form)
-
- c.JSON(http.StatusOK, gin.H{
- "success": "ok",
- "counts": counts,
- "logs": logs,
- })
-}
-
-func configHandler(c *gin.Context) {
- c.YAML(http.StatusCreated, PushConf)
-}
-
-func metricsHandler(c *gin.Context) {
- promhttp.Handler().ServeHTTP(c.Writer, c.Request)
-}
-
-func autoTLSServer() *http.Server {
- m := autocert.Manager{
- Prompt: autocert.AcceptTOS,
- HostPolicy: autocert.HostWhitelist(PushConf.Core.AutoTLS.Host),
- Cache: autocert.DirCache(PushConf.Core.AutoTLS.Folder),
- }
-
- return &http.Server{
- Addr: ":https",
- TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
- Handler: routerEngine(),
- }
-}
-
-func routerEngine() *gin.Engine {
- zerolog.SetGlobalLevel(zerolog.InfoLevel)
- if PushConf.Core.Mode == "debug" {
- zerolog.SetGlobalLevel(zerolog.DebugLevel)
- }
-
- log.Logger = zerolog.New(os.Stdout).With().Timestamp().Logger()
-
- if isTerm {
- log.Logger = log.Output(
- zerolog.ConsoleWriter{
- Out: os.Stdout,
- NoColor: false,
- },
- )
- }
-
- // set server mode
- gin.SetMode(PushConf.Core.Mode)
-
- r := gin.New()
-
- // Global middleware
- r.Use(logger.SetLogger(logger.Config{
- UTC: true,
- SkipPathRegexp: rxURL,
- }))
- r.Use(gin.Recovery())
- r.Use(VersionMiddleware())
- r.Use(StatMiddleware())
-
- r.GET(PushConf.API.StatGoURI, api.GinHandler)
- r.GET(PushConf.API.StatAppURI, appStatusHandler)
- r.GET(PushConf.API.ConfigURI, configHandler)
- r.GET(PushConf.API.SysStatURI, sysStatsHandler)
- r.POST(PushConf.API.PushURI, pushHandler)
- r.GET(PushConf.API.MetricURI, metricsHandler)
- r.GET(PushConf.API.HealthURI, heartbeatHandler)
- r.HEAD(PushConf.API.HealthURI, heartbeatHandler)
- r.GET("/version", versionHandler)
- r.GET("/", rootHandler)
-
- return r
-}
diff --git a/gorush/server_lambda.go b/gorush/server_lambda.go
deleted file mode 100644
index b4bdbc212..000000000
--- a/gorush/server_lambda.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// +build lambda
-
-package gorush
-
-import (
- "context"
-
- "github.com/apex/gateway"
-)
-
-// RunHTTPServer provide run http or https protocol.
-func RunHTTPServer(ctx context.Context) error {
- if !PushConf.Core.Enabled {
- LogAccess.Debug("httpd server is disabled.")
- return nil
- }
-
- LogAccess.Info("HTTPD server is running on " + PushConf.Core.Port + " port.")
-
- return gateway.ListenAndServe(PushConf.Core.Address+":"+PushConf.Core.Port, routerEngine())
-}
diff --git a/gorush/server_normal.go b/gorush/server_normal.go
deleted file mode 100644
index d596e5fd4..000000000
--- a/gorush/server_normal.go
+++ /dev/null
@@ -1,118 +0,0 @@
-// +build !lambda
-
-package gorush
-
-import (
- "context"
- "crypto/tls"
- "encoding/base64"
- "errors"
- "net/http"
- "time"
-
- "golang.org/x/sync/errgroup"
-)
-
-// RunHTTPServer provide run http or https protocol.
-func RunHTTPServer(ctx context.Context) (err error) {
- if !PushConf.Core.Enabled {
- LogAccess.Info("httpd server is disabled.")
- return nil
- }
-
- server := &http.Server{
- Addr: PushConf.Core.Address + ":" + PushConf.Core.Port,
- Handler: routerEngine(),
- }
-
- LogAccess.Info("HTTPD server is running on " + PushConf.Core.Port + " port.")
- if PushConf.Core.AutoTLS.Enabled {
- return startServer(ctx, autoTLSServer())
- } else if PushConf.Core.SSL {
- config := &tls.Config{
- MinVersion: tls.VersionTLS10,
- }
-
- if config.NextProtos == nil {
- config.NextProtos = []string{"http/1.1"}
- }
-
- config.Certificates = make([]tls.Certificate, 1)
- if PushConf.Core.CertPath != "" && PushConf.Core.KeyPath != "" {
- config.Certificates[0], err = tls.LoadX509KeyPair(PushConf.Core.CertPath, PushConf.Core.KeyPath)
- if err != nil {
- LogError.Error("Failed to load https cert file: ", err)
- return err
- }
- } else if PushConf.Core.CertBase64 != "" && PushConf.Core.KeyBase64 != "" {
- cert, err := base64.StdEncoding.DecodeString(PushConf.Core.CertBase64)
- if err != nil {
- LogError.Error("base64 decode error:", err.Error())
- return err
- }
- key, err := base64.StdEncoding.DecodeString(PushConf.Core.KeyBase64)
- if err != nil {
- LogError.Error("base64 decode error:", err.Error())
- return err
- }
- if config.Certificates[0], err = tls.X509KeyPair(cert, key); err != nil {
- LogError.Error("tls key pair error:", err.Error())
- return err
- }
- } else {
- return errors.New("missing https cert config")
- }
-
- server.TLSConfig = config
- }
-
- return startServer(ctx, server)
-}
-
-func listenAndServe(ctx context.Context, s *http.Server) error {
- var g errgroup.Group
- g.Go(func() error {
- select {
- case <-ctx.Done():
- timeout := time.Duration(PushConf.Core.ShutdownTimeout) * time.Second
- ctx, cancel := context.WithTimeout(context.Background(), timeout)
- defer cancel()
- return s.Shutdown(ctx)
- }
- })
- g.Go(func() error {
- if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed {
- return err
- }
- return nil
- })
- return g.Wait()
-}
-
-func listenAndServeTLS(ctx context.Context, s *http.Server) error {
- var g errgroup.Group
- g.Go(func() error {
- select {
- case <-ctx.Done():
- timeout := time.Duration(PushConf.Core.ShutdownTimeout) * time.Second
- ctx, cancel := context.WithTimeout(context.Background(), timeout)
- defer cancel()
- return s.Shutdown(ctx)
- }
- })
- g.Go(func() error {
- if err := s.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
- return err
- }
- return nil
- })
- return g.Wait()
-}
-
-func startServer(ctx context.Context, s *http.Server) error {
- if s.TLSConfig == nil {
- return listenAndServe(ctx, s)
- }
-
- return listenAndServeTLS(ctx, s)
-}
diff --git a/gorush/server_test.go b/gorush/server_test.go
deleted file mode 100644
index b2769b9a0..000000000
--- a/gorush/server_test.go
+++ /dev/null
@@ -1,398 +0,0 @@
-package gorush
-
-import (
- "context"
- "crypto/tls"
- "io/ioutil"
- "log"
- "net/http"
- "os"
- "runtime"
- "testing"
- "time"
-
- "github.com/appleboy/gorush/config"
-
- "github.com/appleboy/gofight/v2"
- "github.com/buger/jsonparser"
- "github.com/gin-gonic/gin"
- "github.com/stretchr/testify/assert"
-)
-
-var goVersion = runtime.Version()
-
-func initTest() {
- PushConf, _ = config.LoadConf("")
- PushConf.Core.Mode = "test"
-}
-
-// testRequest is testing url string if server is running
-func testRequest(t *testing.T, url string) {
- tr := &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
- }
- client := &http.Client{
- Timeout: time.Second * 10,
- Transport: tr,
- }
-
- resp, err := client.Get(url)
- defer func() {
- if err := resp.Body.Close(); err != nil {
- log.Println("close body err:", err)
- }
- }()
-
- assert.NoError(t, err)
-
- _, ioerr := ioutil.ReadAll(resp.Body)
- assert.NoError(t, ioerr)
- assert.Equal(t, "200 OK", resp.Status, "should get a 200")
-}
-
-func TestPrintGoRushVersion(t *testing.T) {
- SetVersion("3.0.0")
- ver := GetVersion()
- PrintGoRushVersion()
-
- assert.Equal(t, "3.0.0", ver)
-}
-
-func TestRunNormalServer(t *testing.T) {
- initTest()
-
- gin.SetMode(gin.TestMode)
-
- go func() {
- assert.NoError(t, RunHTTPServer(context.Background()))
- }()
- // have to wait for the goroutine to start and run the server
- // otherwise the main thread will complete
- time.Sleep(5 * time.Millisecond)
-
- testRequest(t, "http://localhost:8088/api/stat/go")
-}
-
-func TestRunTLSServer(t *testing.T) {
- initTest()
-
- PushConf.Core.SSL = true
- PushConf.Core.Port = "8087"
- PushConf.Core.CertPath = "../certificate/localhost.cert"
- PushConf.Core.KeyPath = "../certificate/localhost.key"
-
- go func() {
- assert.NoError(t, RunHTTPServer(context.Background()))
- }()
- // have to wait for the goroutine to start and run the server
- // otherwise the main thread will complete
- time.Sleep(5 * time.Millisecond)
-
- testRequest(t, "https://localhost:8087/api/stat/go")
-}
-
-func TestRunTLSBase64Server(t *testing.T) {
- cert := `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMrekNDQWVPZ0F3SUJBZ0lKQUxiWkVEdlVRckZLTUEwR0NTcUdTSWIzRFFFQkJRVUFNQlF4RWpBUUJnTlYKQkFNTUNXeHZZMkZzYUc5emREQWVGdzB4TmpBek1qZ3dNek13TkRGYUZ3MHlOakF6TWpZd016TXdOREZhTUJReApFakFRQmdOVkJBTU1DV3h2WTJGc2FHOXpkRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DCmdnRUJBTWoxK3hnNGpWTHpWbkI1ajduMXVsMzBXRUU0QkN6Y05GeGc1QU9CNUg1cSt3amUwWVlpVkZnNlBReXYKR0NpcHFJUlhWUmRWUTFoSFNldW5ZR0tlOGxxM1NiMVg4UFVKMTJ2OXVSYnBTOURLMU93cWs4cnNQRHU2c1ZUTApxS0tnSDFaOHlhenphUzBBYlh1QTVlOWdPL1J6aWpibnBFUCtxdU00ZHVlaU1QVkVKeUxxK0VvSVFZK01NOE1QCjhkWnpMNFhabDd3TDRVc0NON3JQY082VzN0bG5UMGlPM2g5Yy9ZbTJoRmh6K0tOSjlLUlJDdnRQR1pFU2lndEsKYkhzWEgwOTlXRG84di9XcDUvZXZCdy8rSkQwb3B4bUNmSElCQUxIdDl2NTNSdnZzRFoxdDMzUnB1NUM4em5FWQpZMkF5N05neGhxanFvV0pxQTQ4bEplQTBjbHNDQXdFQUFhTlFNRTR3SFFZRFZSME9CQllFRkMwYlRVMVhvZmVoCk5LSWVsYXNoSXNxS2lkRFlNQjhHQTFVZEl3UVlNQmFBRkMwYlRVMVhvZmVoTktJZWxhc2hJc3FLaWREWU1Bd0cKQTFVZEV3UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ2dFQkFBaUpMOElNVHdOWDlYcVFXWURGZ2tHNApBbnJWd1FocmVBcUM5clN4RENqcXFuTUhQSEd6Y0NlRE1MQU1vaDBrT3kyMG5vd1VHTnRDWjB1QnZuWDJxMWJOCmcxanQrR0JjTEpEUjNMTDRDcE5PbG0zWWhPeWN1TmZXTXhUQTdCWGttblNyWkQvN0toQXJzQkVZOGF1bHh3S0oKSFJnTmxJd2Uxb0ZEMVlkWDFCUzVwcDR0MjVCNlZxNEEzRk1NVWtWb1dFNjg4bkUxNjhodlFnd2pySGtnSGh3ZQplTjhsR0UyRGhGcmFYbldtRE1kd2FIRDNIUkZHaHlwcElGTitmN0JxYldYOWdNK1QyWVJUZk9iSVhMV2JxSkxECjNNay9Oa3hxVmNnNGVZNTR3SjF1ZkNVR0FZQUlhWTZmUXFpTlV6OG5od0szdDQ1TkJWVDl5L3VKWHFuVEx5WT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=`
- key := `LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBeVBYN0dEaU5Vdk5XY0htUHVmVzZYZlJZUVRnRUxOdzBYR0RrQTRIa2ZtcjdDTjdSCmhpSlVXRG85REs4WUtLbW9oRmRWRjFWRFdFZEo2NmRnWXA3eVdyZEp2VmZ3OVFuWGEvMjVGdWxMME1yVTdDcVQKeXV3OE83cXhWTXVvb3FBZlZuekpyUE5wTFFCdGU0RGw3MkE3OUhPS051ZWtRLzZxNHpoMjU2SXc5VVFuSXVyNApTZ2hCajR3end3L3gxbk12aGRtWHZBdmhTd0kzdXM5dzdwYmUyV2RQU0k3ZUgxejlpYmFFV0hQNG8wbjBwRkVLCiswOFprUktLQzBwc2V4Y2ZUMzFZT2p5Lzlhbm45NjhIRC80a1BTaW5HWUo4Y2dFQXNlMzIvbmRHKyt3Tm5XM2YKZEdtN2tMek9jUmhqWURMczJER0dxT3FoWW1vRGp5VWw0RFJ5V3dJREFRQUJBb0lCQUdUS3FzTjlLYlNmQTQycQpDcUkwVXVMb3VKTU5hMXFzbno1dUFpNllLV2dXZEE0QTQ0bXBFakNtRlJTVmhVSnZ4V3VLK2N5WUlRelh4SVdECkQxNm5aZHFGNzJBZUNXWjlKeVNzdnZaMDBHZktNM3kzNWlSeTA4c0pXZ096bWNMbkdKQ2lTZXlLc1FlM0hUSkMKZGhEWGJYcXZzSFRWUFpnMDFMVGVEeFVpVGZmVThOTUtxUjJBZWNRMnNURHdYRWhBblR5QXRuemwvWGFCZ0Z6dQpVNkc3RnpHTTV5OWJ4a2ZRVmt2eStERUprSEdOT2p6d2NWZkJ5eVZsNjEwaXhtRzF2bXhWajlQYldtSVBzVVY4CnlTbWpodkRRYk9mb3hXMGg5dlRsVHFHdFFjQnc5NjJvc25ERE1XRkNkTTdsek8wVDdSUm5QVkdJUnBDSk9LaHEKa2VxSEt3RUNnWUVBOHd3SS9pWnVnaG9UWFRORzlMblFRL1dBdHNxTzgwRWpNVFVoZW81STFrT3ptVXowOXB5aAppQXNVRG9OMC8yNnRaNVdOamxueVp1N2R2VGMveDNkVFpwbU5ub284Z2NWYlFORUNEUnpxZnVROVBQWG0xU041CjZwZUJxQXZCdjc4aGpWMDVhWHpQRy9WQmJlaWc3bDI5OUVhckVBK2Evb0gzS3JnRG9xVnFFMEVDZ1lFQTA2dkEKWUptZ2c0ZlpSdWNBWW9hWXNMejlaOXJDRmpUZTFQQlRtVUprYk9SOHZGSUhIVFRFV2kvU3V4WEwwd0RTZW9FMgo3QlFtODZnQ0M3L0tnUmRyem9CcVo1cVM5TXYyZHNMZ1k2MzVWU2dqamZaa1ZMaUgxVlJScFNRT2JZbmZveXNnCmdhdGNIU0tNRXhkNFNMUUJ5QXVJbVhQK0w1YXlEQmNFSmZicVNwc0NnWUI3OElzMWIwdXpOTERqT2g3WTlWaHIKRDJxUHpFT1JjSW9Oc2RaY3RPb1h1WGFBbW1uZ3lJYm01UjlaTjFnV1djNDdvRndMVjNyeFdxWGdzNmZtZzhjWAo3djMwOXZGY0M5UTQvVnhhYTRCNUxOSzluM2dUQUlCUFRPdGxVbmwrMm15MXRmQnRCcVJtMFc2SUtiVEhXUzVnCnZ4akVtL0NpRUl5R1VFZ3FUTWdIQVFLQmdCS3VYZFFvdXRuZzYzUXVmd0l6RHRiS1Z6TUxRNFhpTktobWJYcGgKT2F2Q25wK2dQYkIrTDdZbDhsdEFtVFNPSmdWWjBoY1QwRHhBMzYxWngrMk11NThHQmw0T2JsbmNobXdFMXZqMQpLY1F5UHJFUXhkb1VUeWlzd0dmcXZyczhKOWltdmIrejkvVTZUMUtBQjhXaTNXVmlYelByNE1zaWFhUlhnNjQyCkZJZHhBb0dBWjcvNzM1ZGtoSmN5T2ZzK0xLc0xyNjhKU3N0b29yWE9ZdmRNdTErSkdhOWlMdWhuSEVjTVZXQzgKSXVpaHpQZmxvWnRNYkdZa1pKbjhsM0JlR2Q4aG1mRnRnVGdaR1BvVlJldGZ0MkxERkxuUHhwMnNFSDVPRkxzUQpSK0sva0FPdWw4ZVN0V3VNWE9GQTlwTXpHa0dFZ0lGSk1KT3lhSk9OM2tlZFFJOGRlQ009Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==`
- initTest()
-
- PushConf.Core.SSL = true
- PushConf.Core.Port = "8089"
- PushConf.Core.CertPath = ""
- PushConf.Core.KeyPath = ""
- PushConf.Core.CertBase64 = cert
- PushConf.Core.KeyBase64 = key
-
- go func() {
- assert.NoError(t, RunHTTPServer(context.Background()))
- }()
- // have to wait for the goroutine to start and run the server
- // otherwise the main thread will complete
- time.Sleep(5 * time.Millisecond)
-
- testRequest(t, "https://localhost:8089/api/stat/go")
-}
-
-func TestRunAutoTLSServer(t *testing.T) {
- initTest()
- PushConf.Core.AutoTLS.Enabled = true
- go func() {
- assert.NoError(t, RunHTTPServer(context.Background()))
- }()
- // have to wait for the goroutine to start and run the server
- // otherwise the main thread will complete
- time.Sleep(5 * time.Millisecond)
-}
-
-func TestLoadTLSCertError(t *testing.T) {
- initTest()
-
- PushConf.Core.SSL = true
- PushConf.Core.Port = "8087"
- PushConf.Core.CertPath = "../config/config.yml"
- PushConf.Core.KeyPath = "../config/config.yml"
-
- assert.Error(t, RunHTTPServer(context.Background()))
-}
-
-func TestMissingTLSCertConfg(t *testing.T) {
- initTest()
-
- PushConf.Core.SSL = true
- PushConf.Core.Port = "8087"
- PushConf.Core.CertPath = ""
- PushConf.Core.KeyPath = ""
- PushConf.Core.CertBase64 = ""
- PushConf.Core.KeyBase64 = ""
-
- err := RunHTTPServer(context.Background())
- assert.Error(t, RunHTTPServer(context.Background()))
- assert.Equal(t, "missing https cert config", err.Error())
-}
-
-func TestRootHandler(t *testing.T) {
- initTest()
-
- r := gofight.New()
-
- // log for json
- PushConf.Log.Format = "json"
-
- r.GET("/").
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- data := r.Body.Bytes()
-
- value, _ := jsonparser.GetString(data, "text")
-
- assert.Equal(t, "Welcome to notification server.", value)
- assert.Equal(t, http.StatusOK, r.Code)
- assert.Equal(t, "application/json; charset=utf-8", r.HeaderMap.Get("Content-Type"))
- })
-}
-
-func TestAPIStatusGoHandler(t *testing.T) {
- initTest()
-
- r := gofight.New()
-
- r.GET("/api/stat/go").
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- data := r.Body.Bytes()
-
- value, _ := jsonparser.GetString(data, "go_version")
-
- assert.Equal(t, goVersion, value)
- assert.Equal(t, http.StatusOK, r.Code)
- })
-}
-
-func TestAPIStatusAppHandler(t *testing.T) {
- initTest()
-
- r := gofight.New()
-
- appVersion := "v1.0.0"
- SetVersion(appVersion)
-
- r.GET("/api/stat/app").
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- data := r.Body.Bytes()
-
- value, _ := jsonparser.GetString(data, "version")
-
- assert.Equal(t, appVersion, value)
- assert.Equal(t, http.StatusOK, r.Code)
- })
-}
-
-func TestAPIConfigHandler(t *testing.T) {
- initTest()
-
- r := gofight.New()
-
- r.GET("/api/config").
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- assert.Equal(t, http.StatusCreated, r.Code)
- })
-}
-
-func TestMissingNotificationsParameter(t *testing.T) {
- initTest()
-
- r := gofight.New()
-
- // missing notifications parameter.
- r.POST("/api/push").
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- assert.Equal(t, http.StatusBadRequest, r.Code)
- assert.Equal(t, "application/json; charset=utf-8", r.HeaderMap.Get("Content-Type"))
- })
-}
-
-func TestEmptyNotifications(t *testing.T) {
- initTest()
-
- r := gofight.New()
-
- // notifications is empty.
- r.POST("/api/push").
- SetJSON(gofight.D{
- "notifications": []PushNotification{},
- }).
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- assert.Equal(t, http.StatusBadRequest, r.Code)
- })
-}
-
-func TestMutableContent(t *testing.T) {
- initTest()
-
- r := gofight.New()
-
- // notifications is empty.
- r.POST("/api/push").
- SetJSON(gofight.D{
- "notifications": []gofight.D{
- {
- "tokens": []string{"aaaaa", "bbbbb"},
- "platform": PlatFormAndroid,
- "message": "Welcome",
- "mutable_content": 1,
- "topic": "test",
- "badge": 1,
- "alert": gofight.D{
- "title": "title",
- "body": "body",
- },
- },
- },
- }).
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- // json: cannot unmarshal number into Go struct field PushNotification.mutable_content of type bool
- assert.Equal(t, http.StatusBadRequest, r.Code)
- })
-}
-
-func TestOutOfRangeMaxNotifications(t *testing.T) {
- initTest()
-
- PushConf.Core.MaxNotification = int64(1)
-
- r := gofight.New()
-
- // notifications is empty.
- r.POST("/api/push").
- SetJSON(gofight.D{
- "notifications": []gofight.D{
- {
- "tokens": []string{"aaaaa", "bbbbb"},
- "platform": PlatFormAndroid,
- "message": "Welcome",
- },
- {
- "tokens": []string{"aaaaa", "bbbbb"},
- "platform": PlatFormAndroid,
- "message": "Welcome",
- },
- },
- }).
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- assert.Equal(t, http.StatusBadRequest, r.Code)
- })
-}
-
-func TestSuccessPushHandler(t *testing.T) {
- t.Skip()
- initTest()
-
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
-
- androidToken := os.Getenv("ANDROID_TEST_TOKEN")
-
- r := gofight.New()
-
- r.POST("/api/push").
- SetJSON(gofight.D{
- "notifications": []gofight.D{
- {
- "tokens": []string{androidToken, "bbbbb"},
- "platform": PlatFormAndroid,
- "message": "Welcome",
- },
- },
- }).
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- assert.Equal(t, http.StatusOK, r.Code)
- })
-}
-
-func TestSysStatsHandler(t *testing.T) {
- initTest()
-
- r := gofight.New()
-
- r.GET("/sys/stats").
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- assert.Equal(t, http.StatusOK, r.Code)
- })
-}
-
-func TestMetricsHandler(t *testing.T) {
- initTest()
-
- r := gofight.New()
-
- r.GET("/metrics").
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- assert.Equal(t, http.StatusOK, r.Code)
- })
-}
-
-func TestGETHeartbeatHandler(t *testing.T) {
- initTest()
-
- r := gofight.New()
-
- r.GET("/healthz").
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- assert.Equal(t, http.StatusOK, r.Code)
- })
-}
-
-func TestHEADHeartbeatHandler(t *testing.T) {
- initTest()
-
- r := gofight.New()
-
- r.HEAD("/healthz").
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- assert.Equal(t, http.StatusOK, r.Code)
- })
-}
-
-func TestVersionHandler(t *testing.T) {
- SetVersion("3.0.0")
- initTest()
-
- r := gofight.New()
-
- r.GET("/version").
- Run(routerEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
- assert.Equal(t, http.StatusOK, r.Code)
- data := r.Body.Bytes()
-
- value, _ := jsonparser.GetString(data, "version")
-
- assert.Equal(t, "3.0.0", value)
- })
-}
-
-func TestDisabledHTTPServer(t *testing.T) {
- initTest()
- PushConf.Core.Enabled = false
- err := RunHTTPServer(context.Background())
- PushConf.Core.Enabled = true
-
- assert.Nil(t, err)
-}
diff --git a/gorush/status.go b/gorush/status.go
deleted file mode 100644
index 7495411d9..000000000
--- a/gorush/status.go
+++ /dev/null
@@ -1,108 +0,0 @@
-package gorush
-
-import (
- "errors"
- "net/http"
-
- "github.com/appleboy/gorush/storage/badger"
- "github.com/appleboy/gorush/storage/boltdb"
- "github.com/appleboy/gorush/storage/buntdb"
- "github.com/appleboy/gorush/storage/leveldb"
- "github.com/appleboy/gorush/storage/memory"
- "github.com/appleboy/gorush/storage/redis"
-
- "github.com/gin-gonic/gin"
- "github.com/thoas/stats"
-)
-
-// Stats provide response time, status code count, etc.
-var Stats = stats.New()
-
-// StatusApp is app status structure
-type StatusApp struct {
- Version string `json:"version"`
- QueueMax int `json:"queue_max"`
- QueueUsage int `json:"queue_usage"`
- TotalCount int64 `json:"total_count"`
- Ios IosStatus `json:"ios"`
- Android AndroidStatus `json:"android"`
- Huawei HuaweiStatus `json:"huawei"`
-}
-
-// AndroidStatus is android structure
-type AndroidStatus struct {
- PushSuccess int64 `json:"push_success"`
- PushError int64 `json:"push_error"`
-}
-
-// IosStatus is iOS structure
-type IosStatus struct {
- PushSuccess int64 `json:"push_success"`
- PushError int64 `json:"push_error"`
-}
-
-// HuaweiStatus is huawei structure
-type HuaweiStatus struct {
- PushSuccess int64 `json:"push_success"`
- PushError int64 `json:"push_error"`
-}
-
-// InitAppStatus for initialize app status
-func InitAppStatus() error {
- LogAccess.Info("Init App Status Engine as ", PushConf.Stat.Engine)
- switch PushConf.Stat.Engine {
- case "memory":
- StatStorage = memory.New()
- case "redis":
- StatStorage = redis.New(PushConf)
- case "boltdb":
- StatStorage = boltdb.New(PushConf)
- case "buntdb":
- StatStorage = buntdb.New(PushConf)
- case "leveldb":
- StatStorage = leveldb.New(PushConf)
- case "badger":
- StatStorage = badger.New(PushConf)
- default:
- LogError.Error("storage error: can't find storage driver")
- return errors.New("can't find storage driver")
- }
-
- if err := StatStorage.Init(); err != nil {
- LogError.Error("storage error: " + err.Error())
-
- return err
- }
-
- return nil
-}
-
-func appStatusHandler(c *gin.Context) {
- result := StatusApp{}
-
- result.Version = GetVersion()
- result.QueueMax = cap(QueueNotification)
- result.QueueUsage = len(QueueNotification)
- result.TotalCount = StatStorage.GetTotalCount()
- result.Ios.PushSuccess = StatStorage.GetIosSuccess()
- result.Ios.PushError = StatStorage.GetIosError()
- result.Android.PushSuccess = StatStorage.GetAndroidSuccess()
- result.Android.PushError = StatStorage.GetAndroidError()
- result.Huawei.PushSuccess = StatStorage.GetHuaweiSuccess()
- result.Huawei.PushError = StatStorage.GetHuaweiError()
-
- c.JSON(http.StatusOK, result)
-}
-
-func sysStatsHandler(c *gin.Context) {
- c.JSON(http.StatusOK, Stats.Data())
-}
-
-// StatMiddleware response time, status code count, etc.
-func StatMiddleware() gin.HandlerFunc {
- return func(c *gin.Context) {
- beginning, recorder := Stats.Begin(c.Writer)
- c.Next()
- Stats.End(beginning, stats.WithRecorder(recorder))
- }
-}
diff --git a/gorush/worker.go b/gorush/worker.go
deleted file mode 100644
index 362ae4b82..000000000
--- a/gorush/worker.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package gorush
-
-import (
- "context"
- "errors"
- "sync"
-)
-
-// InitWorkers for initialize all workers.
-func InitWorkers(ctx context.Context, wg *sync.WaitGroup, workerNum, queueNum int64) {
- LogAccess.Info("worker number is ", workerNum, ", queue number is ", queueNum)
- QueueNotification = make(chan PushNotification, queueNum)
- for i := int64(0); i < workerNum; i++ {
- go startWorker(ctx, wg, i)
- }
-}
-
-// SendNotification is send message to iOS, Android or Huawei
-func SendNotification(ctx context.Context, req PushNotification) {
- if PushConf.Core.Sync {
- defer req.WaitDone()
- }
-
- switch req.Platform {
- case PlatFormIos:
- PushToIOS(req)
- case PlatFormAndroid:
- PushToAndroid(req)
- case PlatFormHuawei:
- PushToHuawei(req)
- }
-}
-
-func startWorker(ctx context.Context, wg *sync.WaitGroup, num int64) {
- defer wg.Done()
- for notification := range QueueNotification {
- SendNotification(ctx, notification)
- }
- LogAccess.Info("closed the worker num ", num)
-}
-
-// markFailedNotification adds failure logs for all tokens in push notification
-func markFailedNotification(notification *PushNotification, reason string) {
- LogError.Error(reason)
- for _, token := range notification.Tokens {
- notification.AddLog(getLogPushEntry(FailedPush, token, *notification, errors.New(reason)))
- }
- notification.WaitDone()
-}
-
-// queueNotification add notification to queue list.
-func queueNotification(ctx context.Context, req RequestPush) (int, []LogPushEntry) {
- var count int
- wg := sync.WaitGroup{}
- newNotification := []*PushNotification{}
- for i := range req.Notifications {
- notification := &req.Notifications[i]
- switch notification.Platform {
- case PlatFormIos:
- if !PushConf.Ios.Enabled {
- continue
- }
- case PlatFormAndroid:
- if !PushConf.Android.Enabled {
- continue
- }
- case PlatFormHuawei:
- if !PushConf.Huawei.Enabled {
- continue
- }
- }
- newNotification = append(newNotification, notification)
- }
-
- log := make([]LogPushEntry, 0, count)
- for _, notification := range newNotification {
- if PushConf.Core.Sync {
- notification.wg = &wg
- notification.log = &log
- notification.AddWaitCount()
- }
- if !tryEnqueue(*notification, QueueNotification) {
- markFailedNotification(notification, "max capacity reached")
- }
- count += len(notification.Tokens)
- // Count topic message
- if notification.To != "" {
- count++
- }
- }
-
- if PushConf.Core.Sync {
- wg.Wait()
- }
-
- StatStorage.AddTotalCount(int64(count))
-
- return count, log
-}
-
-// tryEnqueue tries to enqueue a job to the given job channel. Returns true if
-// the operation was successful, and false if enqueuing would not have been
-// possible without blocking. Job is not enqueued in the latter case.
-func tryEnqueue(job PushNotification, jobChan chan<- PushNotification) bool {
- select {
- case jobChan <- job:
- return true
- default:
- return false
- }
-}
diff --git a/gorush/worker_test.go b/gorush/worker_test.go
deleted file mode 100644
index 1f223194b..000000000
--- a/gorush/worker_test.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package gorush
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestTryEnqueue(t *testing.T) {
- chn := make(chan PushNotification, 2)
- assert.True(t, tryEnqueue(PushNotification{}, chn))
- assert.Equal(t, 1, len(chn))
- assert.True(t, tryEnqueue(PushNotification{}, chn))
- assert.Equal(t, 2, len(chn))
- assert.False(t, tryEnqueue(PushNotification{}, chn))
- assert.Equal(t, 2, len(chn))
-}
diff --git a/helm/gorush/.helmignore b/helm/gorush/.helmignore
new file mode 100644
index 000000000..0e8a0eb36
--- /dev/null
+++ b/helm/gorush/.helmignore
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/helm/gorush/Chart.yaml b/helm/gorush/Chart.yaml
new file mode 100644
index 000000000..ea3df48bd
--- /dev/null
+++ b/helm/gorush/Chart.yaml
@@ -0,0 +1,11 @@
+apiVersion: v2
+name: gorush
+description: A push notification micro server using Gin framework written in Go (Golang)
+type: application
+version: 0.1.0
+appVersion: "1.14.0"
+dependencies:
+ - name: redis
+ version: ~14.1
+ repository: https://charts.bitnami.com/bitnami
+ condition: redis.enabled
diff --git a/helm/gorush/templates/NOTES.txt b/helm/gorush/templates/NOTES.txt
new file mode 100644
index 000000000..2d942df59
--- /dev/null
+++ b/helm/gorush/templates/NOTES.txt
@@ -0,0 +1,22 @@
+1. Get the application URL by running these commands:
+{{- if .Values.ingress.enabled }}
+{{- range $host := .Values.ingress.hosts }}
+ {{- range .paths }}
+ http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
+ {{- end }}
+{{- end }}
+{{- else if contains "NodePort" .Values.service.type }}
+ export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "gorush.fullname" . }})
+ export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+ echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+ NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+ You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "gorush.fullname" . }}'
+ export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "gorush.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+ echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+ export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "gorush.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+ export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
+ echo "Visit http://127.0.0.1:8080 to use your application"
+ kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
+{{- end }}
diff --git a/helm/gorush/templates/_helpers.tpl b/helm/gorush/templates/_helpers.tpl
new file mode 100644
index 000000000..f46bea8a4
--- /dev/null
+++ b/helm/gorush/templates/_helpers.tpl
@@ -0,0 +1,62 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "gorush.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "gorush.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "gorush.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "gorush.labels" -}}
+helm.sh/chart: {{ include "gorush.chart" . }}
+{{ include "gorush.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "gorush.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "gorush.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "gorush.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "gorush.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/helm/gorush/templates/configmap.yml b/helm/gorush/templates/configmap.yml
new file mode 100644
index 000000000..ba9617661
--- /dev/null
+++ b/helm/gorush/templates/configmap.yml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ .Chart.Name }}
+ namespace: {{ .Chart.Name }}
+data:
+ # stat
+ stats:
+ engine: {{ .Values.stat.engine }}
+ {{- if .Values.redis.enabled }}
+ redis:
+ host: {{ .Values.redis.host }}:{{ .Values.redis.port }}
+ {{- end }}
diff --git a/helm/gorush/templates/deployment.yaml b/helm/gorush/templates/deployment.yaml
new file mode 100644
index 000000000..3d9849071
--- /dev/null
+++ b/helm/gorush/templates/deployment.yaml
@@ -0,0 +1,75 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ .Chart.Name }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "gorush.labels" . | nindent 4 }}
+spec:
+ replicas: {{ .Values.replicaCount }}
+ selector:
+ matchLabels:
+ {{- include "gorush.selectorLabels" . | nindent 6 }}
+ template:
+ metadata:
+ {{- with .Values.podAnnotations }}
+ annotations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ labels:
+ {{- include "gorush.selectorLabels" . | nindent 8 }}
+ spec:
+ {{- with .Values.imagePullSecrets }}
+ imagePullSecrets:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ serviceAccountName: {{ include "gorush.serviceAccountName" . }}
+ securityContext:
+ {{- toYaml .Values.podSecurityContext | nindent 8 }}
+ containers:
+ - name: {{ .Chart.Name }}
+ securityContext:
+ {{- toYaml .Values.securityContext | nindent 12 }}
+ image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+ imagePullPolicy: {{ .Values.image.pullPolicy }}
+ ports:
+ - name: http
+ containerPort: {{ .Values.service.port }}
+ protocol: TCP
+ livenessProbe:
+ httpGet:
+ path: /healthz
+ port: http
+ initialDelaySeconds: 15
+ periodSeconds: 15
+ env:
+ - name: GORUSH_STAT_ENGINE
+ valueFrom:
+ configMapKeyRef:
+ name: {{ .Chart.Name }}-config
+ key: stat.engine
+ {{- if .Values.redis.enabled }}
+ - name: GORUSH_STAT_REDIS_ADDR
+ valueFrom:
+ configMapKeyRef:
+ name: {{ .Chart.Name }}-config
+ key: stat.redis.host
+ {{- end }}
+ readinessProbe:
+ httpGet:
+ path: /
+ port: http
+ resources:
+ {{- toYaml .Values.resources | nindent 12 }}
+ {{- with .Values.nodeSelector }}
+ nodeSelector:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.affinity }}
+ affinity:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.tolerations }}
+ tolerations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
diff --git a/helm/gorush/templates/hpa.yaml b/helm/gorush/templates/hpa.yaml
new file mode 100644
index 000000000..b8d1df76b
--- /dev/null
+++ b/helm/gorush/templates/hpa.yaml
@@ -0,0 +1,29 @@
+{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v2beta1
+kind: HorizontalPodAutoscaler
+metadata:
+ name: {{ .Chart.Name }}
+ namespace: {{ .Chart.Name }}
+ labels:
+ {{- include "gorush.labels" . | nindent 4 }}
+spec:
+ scaleTargetRef:
+ apiVersion: apps/v1
+ kind: Deployment
+ name: {{ .Chart.Name }}
+ minReplicas: {{ .Values.autoscaling.minReplicas }}
+ maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+ metrics:
+ {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
+ - type: Resource
+ resource:
+ name: cpu
+ targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
+ {{- end }}
+ {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
+ - type: Resource
+ resource:
+ name: memory
+ targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
+ {{- end }}
+{{- end }}
diff --git a/helm/gorush/templates/ingress.yaml b/helm/gorush/templates/ingress.yaml
new file mode 100644
index 000000000..623586316
--- /dev/null
+++ b/helm/gorush/templates/ingress.yaml
@@ -0,0 +1,44 @@
+{{- if .Values.ingress.enabled -}}
+{{- $svcPort := .Values.service.port -}}
+{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1
+{{- else -}}
+apiVersion: extensions/v1beta1
+{{- end }}
+kind: Ingress
+metadata:
+ name: {{ .Chart.Name }}
+ namespace: {{ .Chart.Name }}
+ labels:
+ {{- include "gorush.labels" . | nindent 4 }}
+ {{- with .Values.ingress.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ {{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ {{- range .hosts }}
+ - {{ . | quote }}
+ {{- end }}
+ secretName: {{ .secretName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ {{- range .Values.ingress.hosts }}
+ - host: {{ .host | quote }}
+ http:
+ paths:
+ {{- range .paths }}
+ - path: {{ .path }}
+ pathType: Prefix
+ backend:
+ service:
+ name: gorush
+ port:
+ number: {{ $svcPort }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
diff --git a/helm/gorush/templates/service.yaml b/helm/gorush/templates/service.yaml
new file mode 100644
index 000000000..d3846cebd
--- /dev/null
+++ b/helm/gorush/templates/service.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Chart.Name }}
+ namespace: {{ .Chart.Name }}
+ labels:
+ {{- include "gorush.labels" . | nindent 4 }}
+spec:
+ type: {{ .Values.service.type }}
+ ports:
+ - port: {{ .Values.service.port }}
+ targetPort: http
+ protocol: TCP
+ name: http
+ selector:
+ {{- include "gorush.selectorLabels" . | nindent 4 }}
diff --git a/helm/gorush/templates/serviceaccount.yaml b/helm/gorush/templates/serviceaccount.yaml
new file mode 100644
index 000000000..67a5df568
--- /dev/null
+++ b/helm/gorush/templates/serviceaccount.yaml
@@ -0,0 +1,13 @@
+{{- if .Values.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ include "gorush.serviceAccountName" . }}
+ namespace: {{ .Chart.Name }}
+ labels:
+ {{- include "gorush.labels" . | nindent 4 }}
+ {{- with .Values.serviceAccount.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{- end }}
diff --git a/helm/gorush/values.yaml b/helm/gorush/values.yaml
new file mode 100644
index 000000000..6fc42db1f
--- /dev/null
+++ b/helm/gorush/values.yaml
@@ -0,0 +1,73 @@
+# Default values for gorush.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+image:
+ repository: appleboy/gorush
+ pullPolicy: Always
+ # Overrides the image tag whose default is the chart appVersion.
+ tag: ""
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+ # Specifies whether a service account should be created
+ create: false
+ # Annotations to add to the service account
+ annotations: {}
+ # The name of the service account to use.
+ # If not set and create is true, a name is generated using the fullname template
+ name: ""
+
+podAnnotations: {}
+
+podSecurityContext: {}
+ # fsGroup: 2000
+
+securityContext: {}
+ # capabilities:
+ # drop:
+ # - ALL
+ # readOnlyRootFilesystem: true
+ # runAsNonRoot: true
+ # runAsUser: 1000
+
+service:
+ type: ClusterIP
+ port: 8088
+
+stats:
+ engine: memory
+
+redis:
+ enabled: false
+ host: redis
+ port: 6379
+
+ingress:
+ enabled: false
+ annotations: {}
+ hosts:
+ - host: gorush.example.com
+ paths:
+ - path: /
+ tls: []
+
+resources: {}
+
+autoscaling:
+ enabled: false
+ minReplicas: 1
+ maxReplicas: 10
+ targetCPUUtilizationPercentage: 80
+ # targetMemoryUtilizationPercentage: 80
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/gorush/log.go b/logx/log.go
similarity index 66%
rename from gorush/log.go
rename to logx/log.go
index 9364e0b23..056ac5b67 100644
--- a/gorush/log.go
+++ b/logx/log.go
@@ -1,4 +1,4 @@
-package gorush
+package logx
import (
"encoding/json"
@@ -7,19 +7,18 @@ import (
"os"
"strings"
+ "github.com/appleboy/gorush/core"
+
"github.com/mattn/go-isatty"
"github.com/sirupsen/logrus"
)
var (
- green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
- white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
- yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
- red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
- blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
- magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
- cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
- reset = string([]byte{27, 91, 48, 109})
+ green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
+ yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
+ red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
+ blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
+ reset = string([]byte{27, 91, 48, 109})
)
// LogPushEntry is push response log
@@ -38,13 +37,16 @@ func init() {
isTerm = isatty.IsTerminal(os.Stdout.Fd())
}
-// InitLog use for initial log module
-func InitLog() error {
- var err error
-
- // init logger
+var (
+ // LogAccess is log server request log
LogAccess = logrus.New()
+ // LogError is log server error log
LogError = logrus.New()
+)
+
+// InitLog use for initial log module
+func InitLog(accessLevel, accessLog, errorLevel, errorLog string) error {
+ var err error
if !isTerm {
LogAccess.SetFormatter(&logrus.JSONFormatter{})
@@ -62,19 +64,19 @@ func InitLog() error {
}
// set logger
- if err = SetLogLevel(LogAccess, PushConf.Log.AccessLevel); err != nil {
+ if err = SetLogLevel(LogAccess, accessLevel); err != nil {
return errors.New("Set access log level error: " + err.Error())
}
- if err = SetLogLevel(LogError, PushConf.Log.ErrorLevel); err != nil {
+ if err = SetLogLevel(LogError, errorLevel); err != nil {
return errors.New("Set error log level error: " + err.Error())
}
- if err = SetLogOut(LogAccess, PushConf.Log.AccessLog); err != nil {
+ if err = SetLogOut(LogAccess, accessLog); err != nil {
return errors.New("Set access log path error: " + err.Error())
}
- if err = SetLogOut(LogError, PushConf.Log.ErrorLog); err != nil {
+ if err = SetLogOut(LogError, errorLog); err != nil {
return errors.New("Set error log path error: " + err.Error())
}
@@ -115,11 +117,11 @@ func SetLogLevel(log *logrus.Logger, levelString string) error {
func colorForPlatForm(platform int) string {
switch platform {
- case PlatFormIos:
+ case core.PlatFormIos:
return blue
- case PlatFormAndroid:
+ case core.PlatFormAndroid:
return yellow
- case PlatFormHuawei:
+ case core.PlatFormHuawei:
return green
default:
return reset
@@ -128,11 +130,11 @@ func colorForPlatForm(platform int) string {
func typeForPlatForm(platform int) string {
switch platform {
- case PlatFormIos:
+ case core.PlatFormIos:
return "ios"
- case PlatFormAndroid:
+ case core.PlatFormAndroid:
return "android"
- case PlatFormHuawei:
+ case core.PlatFormHuawei:
return "huawei"
default:
return ""
@@ -157,48 +159,62 @@ func hideToken(token string, markLen int) string {
return result
}
-func getLogPushEntry(status, token string, req PushNotification, errPush error) LogPushEntry {
+// GetLogPushEntry get push data into log structure
+func GetLogPushEntry(input *InputLog) LogPushEntry {
var errMsg string
+ var token string
- plat := typeForPlatForm(req.Platform)
+ plat := typeForPlatForm(input.Platform)
- if errPush != nil {
- errMsg = errPush.Error()
+ if input.Error != nil {
+ errMsg = input.Error.Error()
}
- if PushConf.Log.HideToken {
- token = hideToken(token, 10)
+ if input.HideToken {
+ token = hideToken(input.Token, 10)
}
return LogPushEntry{
- ID: req.ID,
- Type: status,
+ ID: input.ID,
+ Type: input.Status,
Platform: plat,
Token: token,
- Message: req.Message,
+ Message: input.Message,
Error: errMsg,
}
}
+// InputLog log request
+type InputLog struct {
+ ID string
+ Status string
+ Token string
+ Message string
+ Platform int
+ Error error
+ HideToken bool
+ Format string
+}
+
// LogPush record user push request and server response.
-func LogPush(status, token string, req PushNotification, errPush error) {
+func LogPush(input *InputLog) LogPushEntry {
var platColor, resetColor, output string
if isTerm {
- platColor = colorForPlatForm(req.Platform)
+ platColor = colorForPlatForm(input.Platform)
resetColor = reset
}
- log := getLogPushEntry(status, token, req, errPush)
+ log := GetLogPushEntry(input)
- if PushConf.Log.Format == "json" {
+ if input.Format == "json" {
logJSON, _ := json.Marshal(log)
output = string(logJSON)
} else {
var typeColor string
- switch status {
- case SucceededPush:
+ switch input.Status {
+ case core.SucceededPush:
if isTerm {
typeColor = green
}
@@ -209,7 +225,7 @@ func LogPush(status, token string, req PushNotification, errPush error) {
log.Token,
log.Message,
)
- case FailedPush:
+ case core.FailedPush:
if isTerm {
typeColor = red
}
@@ -224,10 +240,12 @@ func LogPush(status, token string, req PushNotification, errPush error) {
}
}
- switch status {
- case SucceededPush:
+ switch input.Status {
+ case core.SucceededPush:
LogAccess.Info(output)
- case FailedPush:
+ case core.FailedPush:
LogError.Error(output)
}
+
+ return log
}
diff --git a/gorush/log/.gitkeep b/logx/log/.gitkeep
similarity index 100%
rename from gorush/log/.gitkeep
rename to logx/log/.gitkeep
diff --git a/logx/log/access.log b/logx/log/access.log
new file mode 100644
index 000000000..e69de29bb
diff --git a/logx/log_interface.go b/logx/log_interface.go
new file mode 100644
index 000000000..51a564cb3
--- /dev/null
+++ b/logx/log_interface.go
@@ -0,0 +1,45 @@
+package logx
+
+import (
+ "fmt"
+
+ "github.com/sirupsen/logrus"
+)
+
+// QueueLogger for simple logger.
+func QueueLogger() DefaultQueueLogger {
+ return DefaultQueueLogger{
+ accessLogger: LogAccess,
+ errorLogger: LogError,
+ }
+}
+
+// DefaultQueueLogger for queue custom logger
+type DefaultQueueLogger struct {
+ accessLogger *logrus.Logger
+ errorLogger *logrus.Logger
+}
+
+func (l DefaultQueueLogger) Infof(format string, args ...interface{}) {
+ l.accessLogger.Printf(format, args...)
+}
+
+func (l DefaultQueueLogger) Errorf(format string, args ...interface{}) {
+ l.errorLogger.Printf(format, args...)
+}
+
+func (l DefaultQueueLogger) Fatalf(format string, args ...interface{}) {
+ l.errorLogger.Fatalf(format, args...)
+}
+
+func (l DefaultQueueLogger) Info(args ...interface{}) {
+ l.accessLogger.Println(fmt.Sprint(args...))
+}
+
+func (l DefaultQueueLogger) Error(args ...interface{}) {
+ l.errorLogger.Println(fmt.Sprint(args...))
+}
+
+func (l DefaultQueueLogger) Fatal(args ...interface{}) {
+ l.errorLogger.Println(fmt.Sprint(args...))
+}
diff --git a/logx/log_test.go b/logx/log_test.go
new file mode 100644
index 000000000..ee1ed3365
--- /dev/null
+++ b/logx/log_test.go
@@ -0,0 +1,129 @@
+package logx
+
+import (
+ "testing"
+
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/core"
+
+ "github.com/sirupsen/logrus"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSetLogLevel(t *testing.T) {
+ log := logrus.New()
+
+ err := SetLogLevel(log, "debug")
+ assert.Nil(t, err)
+
+ err = SetLogLevel(log, "invalid")
+ assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
+}
+
+func TestSetLogOut(t *testing.T) {
+ log := logrus.New()
+
+ err := SetLogOut(log, "stdout")
+ assert.Nil(t, err)
+
+ err = SetLogOut(log, "stderr")
+ assert.Nil(t, err)
+
+ err = SetLogOut(log, "log/access.log")
+ assert.Nil(t, err)
+
+ // missing create logs folder.
+ err = SetLogOut(log, "logs/access.log")
+ assert.NotNil(t, err)
+}
+
+func TestInitDefaultLog(t *testing.T) {
+ cfg, _ := config.LoadConf()
+
+ // no errors on default config
+ assert.Nil(t, InitLog(
+ cfg.Log.AccessLevel,
+ cfg.Log.AccessLog,
+ cfg.Log.ErrorLevel,
+ cfg.Log.ErrorLog,
+ ))
+
+ cfg.Log.AccessLevel = "invalid"
+
+ assert.NotNil(t, InitLog(
+ cfg.Log.AccessLevel,
+ cfg.Log.AccessLog,
+ cfg.Log.ErrorLevel,
+ cfg.Log.ErrorLog,
+ ))
+}
+
+func TestAccessLevel(t *testing.T) {
+ cfg, _ := config.LoadConf()
+
+ cfg.Log.AccessLevel = "invalid"
+
+ assert.NotNil(t, InitLog(
+ cfg.Log.AccessLevel,
+ cfg.Log.AccessLog,
+ cfg.Log.ErrorLevel,
+ cfg.Log.ErrorLog,
+ ))
+}
+
+func TestErrorLevel(t *testing.T) {
+ cfg, _ := config.LoadConf()
+
+ cfg.Log.ErrorLevel = "invalid"
+
+ assert.NotNil(t, InitLog(
+ cfg.Log.AccessLevel,
+ cfg.Log.AccessLog,
+ cfg.Log.ErrorLevel,
+ cfg.Log.ErrorLog,
+ ))
+}
+
+func TestAccessLogPath(t *testing.T) {
+ cfg, _ := config.LoadConf()
+
+ cfg.Log.AccessLog = "logs/access.log"
+
+ assert.NotNil(t, InitLog(
+ cfg.Log.AccessLevel,
+ cfg.Log.AccessLog,
+ cfg.Log.ErrorLevel,
+ cfg.Log.ErrorLog,
+ ))
+}
+
+func TestErrorLogPath(t *testing.T) {
+ cfg, _ := config.LoadConf()
+
+ cfg.Log.ErrorLog = "logs/error.log"
+
+ assert.NotNil(t, InitLog(
+ cfg.Log.AccessLevel,
+ cfg.Log.AccessLog,
+ cfg.Log.ErrorLevel,
+ cfg.Log.ErrorLog,
+ ))
+}
+
+func TestPlatFormType(t *testing.T) {
+ assert.Equal(t, "ios", typeForPlatForm(core.PlatFormIos))
+ assert.Equal(t, "android", typeForPlatForm(core.PlatFormAndroid))
+ assert.Equal(t, "", typeForPlatForm(10000))
+}
+
+func TestPlatFormColor(t *testing.T) {
+ assert.Equal(t, blue, colorForPlatForm(core.PlatFormIos))
+ assert.Equal(t, yellow, colorForPlatForm(core.PlatFormAndroid))
+ assert.Equal(t, reset, colorForPlatForm(1000000))
+}
+
+func TestHideToken(t *testing.T) {
+ assert.Equal(t, "", hideToken("", 2))
+ assert.Equal(t, "**345678**", hideToken("1234567890", 2))
+ assert.Equal(t, "*****", hideToken("12345", 10))
+}
diff --git a/main.go b/main.go
index c518e785d..b4dab1cd7 100644
--- a/main.go
+++ b/main.go
@@ -11,14 +11,20 @@ import (
"os/signal"
"path/filepath"
"strconv"
- "sync"
"syscall"
"time"
"github.com/appleboy/gorush/config"
- "github.com/appleboy/gorush/gorush"
+ "github.com/appleboy/gorush/core"
+ "github.com/appleboy/gorush/logx"
+ "github.com/appleboy/gorush/notify"
+ "github.com/appleboy/gorush/router"
"github.com/appleboy/gorush/rpc"
+ "github.com/appleboy/gorush/status"
+ "github.com/golang-queue/nats"
+ "github.com/golang-queue/nsq"
+ "github.com/golang-queue/queue"
"golang.org/x/sync/errgroup"
)
@@ -54,7 +60,7 @@ func main() {
)
flag.BoolVar(&showVersion, "version", false, "Print version information.")
- flag.BoolVar(&showVersion, "v", false, "Print version information.")
+ flag.BoolVar(&showVersion, "V", false, "Print version information.")
flag.StringVar(&configFile, "c", "", "Configuration file path.")
flag.StringVar(&configFile, "config", "", "Configuration file path.")
flag.StringVar(&opts.Core.PID.Path, "pid", "", "PID file path.")
@@ -93,18 +99,16 @@ func main() {
flag.Usage = usage
flag.Parse()
- gorush.SetVersion(Version)
+ router.SetVersion(Version)
// Show version and exit
if showVersion {
- gorush.PrintGoRushVersion()
+ router.PrintGoRushVersion()
os.Exit(0)
}
- var err error
-
// set default parameters.
- gorush.PushConf, err = config.LoadConf(configFile)
+ cfg, err := config.LoadConf(configFile)
if err != nil {
log.Printf("Load yaml config file error: '%v'", err)
@@ -112,80 +116,85 @@ func main() {
}
// Initialize push slots for concurrent iOS pushes
- gorush.MaxConcurrentIOSPushes = make(chan struct{}, gorush.PushConf.Ios.MaxConcurrentPushes)
+ notify.MaxConcurrentIOSPushes = make(chan struct{}, cfg.Ios.MaxConcurrentPushes)
if opts.Ios.KeyPath != "" {
- gorush.PushConf.Ios.KeyPath = opts.Ios.KeyPath
+ cfg.Ios.KeyPath = opts.Ios.KeyPath
}
if opts.Ios.KeyID != "" {
- gorush.PushConf.Ios.KeyID = opts.Ios.KeyID
+ cfg.Ios.KeyID = opts.Ios.KeyID
}
if opts.Ios.TeamID != "" {
- gorush.PushConf.Ios.TeamID = opts.Ios.TeamID
+ cfg.Ios.TeamID = opts.Ios.TeamID
}
if opts.Ios.Password != "" {
- gorush.PushConf.Ios.Password = opts.Ios.Password
+ cfg.Ios.Password = opts.Ios.Password
}
if opts.Android.APIKey != "" {
- gorush.PushConf.Android.APIKey = opts.Android.APIKey
+ cfg.Android.APIKey = opts.Android.APIKey
}
if opts.Huawei.AppSecret != "" {
- gorush.PushConf.Huawei.AppSecret = opts.Huawei.AppSecret
+ cfg.Huawei.AppSecret = opts.Huawei.AppSecret
}
if opts.Huawei.AppID != "" {
- gorush.PushConf.Huawei.AppID = opts.Huawei.AppID
+ cfg.Huawei.AppID = opts.Huawei.AppID
}
if opts.Stat.Engine != "" {
- gorush.PushConf.Stat.Engine = opts.Stat.Engine
+ cfg.Stat.Engine = opts.Stat.Engine
}
if opts.Stat.Redis.Addr != "" {
- gorush.PushConf.Stat.Redis.Addr = opts.Stat.Redis.Addr
+ cfg.Stat.Redis.Addr = opts.Stat.Redis.Addr
}
// overwrite server port and address
if opts.Core.Port != "" {
- gorush.PushConf.Core.Port = opts.Core.Port
+ cfg.Core.Port = opts.Core.Port
}
if opts.Core.Address != "" {
- gorush.PushConf.Core.Address = opts.Core.Address
+ cfg.Core.Address = opts.Core.Address
}
- if err = gorush.InitLog(); err != nil {
- log.Fatalf("Can't load log module, error: %v", err)
+ if err = logx.InitLog(
+ cfg.Log.AccessLevel,
+ cfg.Log.AccessLog,
+ cfg.Log.ErrorLevel,
+ cfg.Log.ErrorLog,
+ ); err != nil {
+ log.Fatalf("can't load log module, error: %v", err)
}
if opts.Core.HTTPProxy != "" {
- gorush.PushConf.Core.HTTPProxy = opts.Core.HTTPProxy
+ cfg.Core.HTTPProxy = opts.Core.HTTPProxy
}
- if gorush.PushConf.Core.HTTPProxy != "" {
- err = gorush.SetProxy(gorush.PushConf.Core.HTTPProxy)
+ if cfg.Core.HTTPProxy != "" {
+ err = notify.SetProxy(cfg.Core.HTTPProxy)
if err != nil {
- gorush.LogError.Fatalf("Set Proxy error: %v", err)
+ logx.LogError.Fatalf("Set Proxy error: %v", err)
}
}
if ping {
- if err := pinger(); err != nil {
- gorush.LogError.Warnf("ping server error: %v", err)
+ if err := pinger(cfg); err != nil {
+ logx.LogError.Warnf("ping server error: %v", err)
}
return
}
// send android notification
if opts.Android.Enabled {
- gorush.PushConf.Android.Enabled = opts.Android.Enabled
- req := gorush.PushNotification{
- Platform: gorush.PlatFormAndroid,
+ cfg.Android.Enabled = opts.Android.Enabled
+ req := ¬ify.PushNotification{
+ Platform: core.PlatFormAndroid,
Message: message,
Title: title,
}
@@ -200,25 +209,27 @@ func main() {
req.To = topic
}
- err := gorush.CheckMessage(req)
+ err := notify.CheckMessage(req)
if err != nil {
- gorush.LogError.Fatal(err)
+ logx.LogError.Fatal(err)
}
- if err := gorush.InitAppStatus(); err != nil {
+ if err := status.InitAppStatus(cfg); err != nil {
return
}
- gorush.PushToAndroid(req)
+ if _, err := notify.PushToAndroid(req, cfg); err != nil {
+ return
+ }
return
}
// send huawei notification
if opts.Huawei.Enabled {
- gorush.PushConf.Huawei.Enabled = opts.Huawei.Enabled
- req := gorush.PushNotification{
- Platform: gorush.PlatFormHuawei,
+ cfg.Huawei.Enabled = opts.Huawei.Enabled
+ req := ¬ify.PushNotification{
+ Platform: core.PlatFormHuawei,
Message: message,
Title: title,
}
@@ -233,16 +244,18 @@ func main() {
req.To = topic
}
- err := gorush.CheckMessage(req)
+ err := notify.CheckMessage(req)
if err != nil {
- gorush.LogError.Fatal(err)
+ logx.LogError.Fatal(err)
}
- if err := gorush.InitAppStatus(); err != nil {
+ if err := status.InitAppStatus(cfg); err != nil {
return
}
- gorush.PushToHuawei(req)
+ if _, err := notify.PushToHuawei(req, cfg); err != nil {
+ return
+ }
return
}
@@ -250,12 +263,12 @@ func main() {
// send ios notification
if opts.Ios.Enabled {
if opts.Ios.Production {
- gorush.PushConf.Ios.Production = opts.Ios.Production
+ cfg.Ios.Production = opts.Ios.Production
}
- gorush.PushConf.Ios.Enabled = opts.Ios.Enabled
- req := gorush.PushNotification{
- Platform: gorush.PlatFormIos,
+ cfg.Ios.Enabled = opts.Ios.Enabled
+ req := ¬ify.PushNotification{
+ Platform: core.PlatFormIos,
Message: message,
Title: title,
}
@@ -270,74 +283,107 @@ func main() {
req.Topic = topic
}
- err := gorush.CheckMessage(req)
+ err := notify.CheckMessage(req)
if err != nil {
- gorush.LogError.Fatal(err)
+ logx.LogError.Fatal(err)
}
- if err := gorush.InitAppStatus(); err != nil {
+ if err := status.InitAppStatus(cfg); err != nil {
return
}
- if err := gorush.InitAPNSClient(); err != nil {
+ if err := notify.InitAPNSClient(cfg); err != nil {
+ return
+ }
+
+ if _, err := notify.PushToIOS(req, cfg); err != nil {
return
}
- gorush.PushToIOS(req)
return
}
- if err = gorush.CheckPushConf(); err != nil {
- gorush.LogError.Fatal(err)
+ if err = notify.CheckPushConf(cfg); err != nil {
+ logx.LogError.Fatal(err)
}
if opts.Core.PID.Path != "" {
- gorush.PushConf.Core.PID.Path = opts.Core.PID.Path
- gorush.PushConf.Core.PID.Enabled = true
- gorush.PushConf.Core.PID.Override = true
- }
-
- if err = createPIDFile(); err != nil {
- gorush.LogError.Fatal(err)
- }
-
- if err = gorush.InitAppStatus(); err != nil {
- gorush.LogError.Fatal(err)
- }
+ cfg.Core.PID.Path = opts.Core.PID.Path
+ cfg.Core.PID.Enabled = true
+ cfg.Core.PID.Override = true
+ }
+
+ if err = createPIDFile(cfg); err != nil {
+ logx.LogError.Fatal(err)
+ }
+
+ if err = status.InitAppStatus(cfg); err != nil {
+ logx.LogError.Fatal(err)
+ }
+
+ var w queue.Worker
+ switch core.Queue(cfg.Queue.Engine) {
+ case core.LocalQueue:
+ w = queue.NewConsumer(
+ queue.WithQueueSize(int(cfg.Core.QueueNum)),
+ queue.WithFn(notify.Run(cfg)),
+ queue.WithLogger(logx.QueueLogger()),
+ )
+ case core.NSQ:
+ w = nsq.NewWorker(
+ nsq.WithAddr(cfg.Queue.NSQ.Addr),
+ nsq.WithTopic(cfg.Queue.NSQ.Topic),
+ nsq.WithChannel(cfg.Queue.NSQ.Channel),
+ nsq.WithMaxInFlight(int(cfg.Core.WorkerNum)),
+ nsq.WithRunFunc(notify.Run(cfg)),
+ nsq.WithLogger(logx.QueueLogger()),
+ )
+ case core.NATS:
+ w = nats.NewWorker(
+ nats.WithAddr(cfg.Queue.NATS.Addr),
+ nats.WithSubj(cfg.Queue.NATS.Subj),
+ nats.WithQueue(cfg.Queue.NATS.Queue),
+ nats.WithRunFunc(notify.Run(cfg)),
+ nats.WithLogger(logx.QueueLogger()),
+ )
+ default:
+ logx.LogError.Fatalf("we don't support queue engine: %s", cfg.Queue.Engine)
+ }
+
+ q := queue.NewPool(
+ int(cfg.Core.WorkerNum),
+ queue.WithWorker(w),
+ queue.WithLogger(logx.QueueLogger()),
+ )
finished := make(chan struct{})
- wg := &sync.WaitGroup{}
- wg.Add(int(gorush.PushConf.Core.WorkerNum))
ctx := withContextFunc(context.Background(), func() {
- gorush.LogAccess.Info("close the notification queue channel, current queue len: ", len(gorush.QueueNotification))
- close(gorush.QueueNotification)
- wg.Wait()
- gorush.LogAccess.Info("the notification queue has been clear")
+ logx.LogAccess.Info("close the queue system, current queue usage: ", q.Usage())
+ // stop queue system and wait job completed
+ q.Release()
close(finished)
// close the connection with storage
- gorush.LogAccess.Info("close the storage connection: ", gorush.PushConf.Stat.Engine)
- if err := gorush.StatStorage.Close(); err != nil {
- gorush.LogError.Fatal("can't close the storage connection: ", err.Error())
+ logx.LogAccess.Info("close the storage connection: ", cfg.Stat.Engine)
+ if err := status.StatStorage.Close(); err != nil {
+ logx.LogError.Fatal("can't close the storage connection: ", err.Error())
}
})
- gorush.InitWorkers(ctx, wg, gorush.PushConf.Core.WorkerNum, gorush.PushConf.Core.QueueNum)
-
- if gorush.PushConf.Ios.Enabled {
- if err = gorush.InitAPNSClient(); err != nil {
- gorush.LogError.Fatal(err)
+ if cfg.Ios.Enabled {
+ if err = notify.InitAPNSClient(cfg); err != nil {
+ logx.LogError.Fatal(err)
}
}
- if gorush.PushConf.Android.Enabled {
- if _, err = gorush.InitFCMClient(gorush.PushConf.Android.APIKey); err != nil {
- gorush.LogError.Fatal(err)
+ if cfg.Android.Enabled {
+ if _, err = notify.InitFCMClient(cfg, cfg.Android.APIKey); err != nil {
+ logx.LogError.Fatal(err)
}
}
- if gorush.PushConf.Huawei.Enabled {
- if _, err = gorush.InitHMSClient(gorush.PushConf.Huawei.AppSecret, gorush.PushConf.Huawei.AppID); err != nil {
- gorush.LogError.Fatal(err)
+ if cfg.Huawei.Enabled {
+ if _, err = notify.InitHMSClient(cfg, cfg.Huawei.AppSecret, cfg.Huawei.AppID); err != nil {
+ logx.LogError.Fatal(err)
}
}
@@ -345,28 +391,26 @@ func main() {
// Run httpd server
g.Go(func() error {
- return gorush.RunHTTPServer(ctx)
+ return router.RunHTTPServer(ctx, cfg, q)
})
// Run gRPC internal server
g.Go(func() error {
- return rpc.RunGRPCServer(ctx)
+ return rpc.RunGRPCServer(ctx, cfg)
})
// check job completely
g.Go(func() error {
- select {
- case <-finished:
- }
+ <-finished
return nil
})
if err = g.Wait(); err != nil {
- gorush.LogError.Fatal(err)
+ logx.LogError.Fatal(err)
}
}
-// Version control for gorush.
+// Version control for notify.
var Version = "No Version Provided"
var usageStr = `
@@ -406,7 +450,7 @@ Huawei Options:
Common Options:
--topic iOS, Android or Huawei topic message
-h, --help Show this message
- -v, --version Show version
+ -V, --version Show version
`
// usage will print out the flag options for the server.
@@ -417,7 +461,7 @@ func usage() {
// handles pinging the endpoint and returns an error if the
// agent is in an unhealthy state.
-func pinger() error {
+func pinger(cfg *config.ConfYaml) error {
transport := &http.Transport{
Dial: (&net.Dialer{
Timeout: 5 * time.Second,
@@ -428,7 +472,7 @@ func pinger() error {
Timeout: time.Second * 10,
Transport: transport,
}
- resp, err := client.Get("http://localhost:" + gorush.PushConf.Core.Port + gorush.PushConf.API.HealthURI)
+ resp, err := client.Get("http://localhost:" + cfg.Core.Port + cfg.API.HealthURI)
if err != nil {
return err
}
@@ -439,26 +483,26 @@ func pinger() error {
return nil
}
-func createPIDFile() error {
- if !gorush.PushConf.Core.PID.Enabled {
+func createPIDFile(cfg *config.ConfYaml) error {
+ if !cfg.Core.PID.Enabled {
return nil
}
- pidPath := gorush.PushConf.Core.PID.Path
+ pidPath := cfg.Core.PID.Path
_, err := os.Stat(pidPath)
- if os.IsNotExist(err) || gorush.PushConf.Core.PID.Override {
+ if os.IsNotExist(err) || cfg.Core.PID.Override {
currentPid := os.Getpid()
if err := os.MkdirAll(filepath.Dir(pidPath), os.ModePerm); err != nil {
- return fmt.Errorf("Can't create PID folder on %v", err)
+ return fmt.Errorf("can't create PID folder on %v", err)
}
file, err := os.Create(pidPath)
if err != nil {
- return fmt.Errorf("Can't create PID file: %v", err)
+ return fmt.Errorf("can't create PID file: %v", err)
}
defer file.Close()
if _, err := file.WriteString(strconv.FormatInt(int64(currentPid), 10)); err != nil {
- return fmt.Errorf("Can't write PID information on %s: %v", pidPath, err)
+ return fmt.Errorf("can't write PID information on %s: %v", pidPath, err)
}
} else {
return fmt.Errorf("%s already exists", pidPath)
diff --git a/gorush/metrics.go b/metric/metrics.go
similarity index 79%
rename from gorush/metrics.go
rename to metric/metrics.go
index 0f4705390..e717ef043 100644
--- a/gorush/metrics.go
+++ b/metric/metrics.go
@@ -1,6 +1,8 @@
-package gorush
+package metric
import (
+ "github.com/appleboy/gorush/status"
+
"github.com/prometheus/client_golang/prometheus"
)
@@ -17,11 +19,14 @@ type Metrics struct {
HuaweiSuccess *prometheus.Desc
HuaweiError *prometheus.Desc
QueueUsage *prometheus.Desc
+ GetQueueUsage func() int
}
+var getGetQueueUsage = func() int { return 0 }
+
// NewMetrics returns a new Metrics with all prometheus.Desc initialized
-func NewMetrics() Metrics {
- return Metrics{
+func NewMetrics(c ...func() int) Metrics {
+ m := Metrics{
TotalPushCount: prometheus.NewDesc(
namespace+"total_push_count",
"Number of push count",
@@ -62,7 +67,14 @@ func NewMetrics() Metrics {
"Length of internal queue",
nil, nil,
),
+ GetQueueUsage: getGetQueueUsage,
}
+
+ if len(c) > 0 {
+ m.GetQueueUsage = c[0]
+ }
+
+ return m
}
// Describe returns all possible prometheus.Desc
@@ -82,41 +94,41 @@ func (c Metrics) Collect(ch chan<- prometheus.Metric) {
ch <- prometheus.MustNewConstMetric(
c.TotalPushCount,
prometheus.CounterValue,
- float64(StatStorage.GetTotalCount()),
+ float64(status.StatStorage.GetTotalCount()),
)
ch <- prometheus.MustNewConstMetric(
c.IosSuccess,
prometheus.CounterValue,
- float64(StatStorage.GetIosSuccess()),
+ float64(status.StatStorage.GetIosSuccess()),
)
ch <- prometheus.MustNewConstMetric(
c.IosError,
prometheus.CounterValue,
- float64(StatStorage.GetIosError()),
+ float64(status.StatStorage.GetIosError()),
)
ch <- prometheus.MustNewConstMetric(
c.AndroidSuccess,
prometheus.CounterValue,
- float64(StatStorage.GetAndroidSuccess()),
+ float64(status.StatStorage.GetAndroidSuccess()),
)
ch <- prometheus.MustNewConstMetric(
c.AndroidError,
prometheus.CounterValue,
- float64(StatStorage.GetAndroidError()),
+ float64(status.StatStorage.GetAndroidError()),
)
ch <- prometheus.MustNewConstMetric(
c.HuaweiSuccess,
prometheus.CounterValue,
- float64(StatStorage.GetHuaweiSuccess()),
+ float64(status.StatStorage.GetHuaweiSuccess()),
)
ch <- prometheus.MustNewConstMetric(
c.HuaweiError,
prometheus.CounterValue,
- float64(StatStorage.GetHuaweiError()),
+ float64(status.StatStorage.GetHuaweiError()),
)
ch <- prometheus.MustNewConstMetric(
c.QueueUsage,
prometheus.GaugeValue,
- float64(len(QueueNotification)),
+ float64(c.GetQueueUsage()),
)
}
diff --git a/metric/metrics_test.go b/metric/metrics_test.go
new file mode 100644
index 000000000..2e6c1b2c9
--- /dev/null
+++ b/metric/metrics_test.go
@@ -0,0 +1,15 @@
+package metric
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestNewMetrics(t *testing.T) {
+ m := NewMetrics()
+ assert.Equal(t, 0, m.GetQueueUsage())
+
+ m = NewMetrics(func() int { return 1 })
+ assert.Equal(t, 1, m.GetQueueUsage())
+}
diff --git a/netlify.toml b/netlify.toml
index d5e45397b..7eaa48c5a 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -3,6 +3,7 @@
functions = "release/linux/lambda"
[build.environment]
+ GO_VERSION = "1.16"
GO_IMPORT_PATH = "github.com/appleboy/gorush"
GO111MODULE = "on"
diff --git a/gorush/feedback.go b/notify/feedback.go
similarity index 81%
rename from gorush/feedback.go
rename to notify/feedback.go
index 0eb2557e5..c4f873e35 100644
--- a/gorush/feedback.go
+++ b/notify/feedback.go
@@ -1,18 +1,19 @@
-package gorush
+package notify
import (
"bytes"
- "encoding/json"
"errors"
"net"
"net/http"
"time"
+
+ "github.com/appleboy/gorush/logx"
)
// DispatchFeedback sends a feedback to the configured gateway.
-func DispatchFeedback(log LogPushEntry, url string, timeout int64) error {
+func DispatchFeedback(log logx.LogPushEntry, url string, timeout int64) error {
if url == "" {
- return errors.New("The url can't be empty")
+ return errors.New("url can't be empty")
}
payload, err := json.Marshal(log)
diff --git a/gorush/feedback_test.go b/notify/feedback_test.go
similarity index 63%
rename from gorush/feedback_test.go
rename to notify/feedback_test.go
index 4a3ebd8de..ec20b502e 100644
--- a/gorush/feedback_test.go
+++ b/notify/feedback_test.go
@@ -1,4 +1,4 @@
-package gorush
+package notify
import (
"log"
@@ -7,13 +7,14 @@ import (
"testing"
"github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/logx"
"github.com/stretchr/testify/assert"
)
func TestEmptyFeedbackURL(t *testing.T) {
- // PushConf, _ = config.LoadConf("")
- logEntry := LogPushEntry{
+ cfg, _ := config.LoadConf()
+ logEntry := logx.LogPushEntry{
ID: "",
Type: "",
Platform: "",
@@ -22,14 +23,14 @@ func TestEmptyFeedbackURL(t *testing.T) {
Error: "",
}
- err := DispatchFeedback(logEntry, PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
+ err := DispatchFeedback(logEntry, cfg.Core.FeedbackURL, cfg.Core.FeedbackTimeout)
assert.NotNil(t, err)
}
func TestHTTPErrorInFeedbackCall(t *testing.T) {
- config, _ := config.LoadConf("")
- config.Core.FeedbackURL = "http://test.example.com/api/"
- logEntry := LogPushEntry{
+ cfg, _ := config.LoadConf()
+ cfg.Core.FeedbackURL = "http://test.example.com/api/"
+ logEntry := logx.LogPushEntry{
ID: "",
Type: "",
Platform: "",
@@ -38,7 +39,7 @@ func TestHTTPErrorInFeedbackCall(t *testing.T) {
Error: "",
}
- err := DispatchFeedback(logEntry, config.Core.FeedbackURL, config.Core.FeedbackTimeout)
+ err := DispatchFeedback(logEntry, cfg.Core.FeedbackURL, cfg.Core.FeedbackTimeout)
assert.NotNil(t, err)
}
@@ -58,9 +59,9 @@ func TestSuccessfulFeedbackCall(t *testing.T) {
)
defer httpMock.Close()
- config, _ := config.LoadConf("")
- config.Core.FeedbackURL = httpMock.URL
- logEntry := LogPushEntry{
+ cfg, _ := config.LoadConf()
+ cfg.Core.FeedbackURL = httpMock.URL
+ logEntry := logx.LogPushEntry{
ID: "",
Type: "",
Platform: "",
@@ -69,6 +70,6 @@ func TestSuccessfulFeedbackCall(t *testing.T) {
Error: "",
}
- err := DispatchFeedback(logEntry, config.Core.FeedbackURL, config.Core.FeedbackTimeout)
+ err := DispatchFeedback(logEntry, cfg.Core.FeedbackURL, cfg.Core.FeedbackTimeout)
assert.Nil(t, err)
}
diff --git a/notify/global.go b/notify/global.go
new file mode 100644
index 000000000..7433be6b5
--- /dev/null
+++ b/notify/global.go
@@ -0,0 +1,18 @@
+package notify
+
+import (
+ "github.com/appleboy/go-fcm"
+ "github.com/msalihkarakasli/go-hms-push/push/core"
+ "github.com/sideshow/apns2"
+)
+
+var (
+ // ApnsClient is apns client
+ ApnsClient *apns2.Client
+ // FCMClient is apns client
+ FCMClient *fcm.Client
+ // HMSClient is Huawei push client
+ HMSClient *core.HMSClient
+ // MaxConcurrentIOSPushes pool to limit the number of concurrent iOS pushes
+ MaxConcurrentIOSPushes chan struct{}
+)
diff --git a/notify/main_test.go b/notify/main_test.go
new file mode 100644
index 000000000..899ef0b55
--- /dev/null
+++ b/notify/main_test.go
@@ -0,0 +1,19 @@
+package notify
+
+import (
+ "log"
+ "os"
+ "testing"
+
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/status"
+)
+
+func TestMain(m *testing.M) {
+ cfg, _ := config.LoadConf()
+ if err := status.InitAppStatus(cfg); err != nil {
+ log.Fatal(err)
+ }
+
+ os.Exit(m.Run())
+}
diff --git a/gorush/notification.go b/notify/notification.go
similarity index 70%
rename from gorush/notification.go
rename to notify/notification.go
index 87ec42c31..a5367d9d7 100644
--- a/gorush/notification.go
+++ b/notify/notification.go
@@ -1,17 +1,25 @@
-package gorush
+package notify
import (
+ "context"
"errors"
"net/http"
"net/url"
"os"
"strings"
- "sync"
+
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/core"
+ "github.com/appleboy/gorush/logx"
"github.com/appleboy/go-fcm"
+ "github.com/golang-queue/queue"
+ jsoniter "github.com/json-iterator/go"
"github.com/msalihkarakasli/go-hms-push/push/model"
)
+var json = jsoniter.ConfigCompatibleWithStandardLibrary
+
// D provide string array
type D map[string]interface{}
@@ -50,11 +58,13 @@ type RequestPush struct {
Notifications []PushNotification `json:"notifications" binding:"required"`
}
+// ResponsePush response of notification request.
+type ResponsePush struct {
+ Logs []logx.LogPushEntry `json:"logs"`
+}
+
// PushNotification is single notification request
type PushNotification struct {
- wg *sync.WaitGroup
- log *[]LogPushEntry
-
// Common
ID string `json:"notif_id,omitempty"`
Tokens []string `json:"tokens" binding:"required"`
@@ -108,35 +118,23 @@ type PushNotification struct {
Apns D `json:"apns,omitempty"`
}
-// WaitDone decrements the WaitGroup counter.
-func (p *PushNotification) WaitDone() {
- if p.wg != nil {
- p.wg.Done()
- }
-}
-
-// AddWaitCount increments the WaitGroup counter.
-func (p *PushNotification) AddWaitCount() {
- if p.wg != nil {
- p.wg.Add(1)
- }
-}
-
-// AddLog record fail log of notification
-func (p *PushNotification) AddLog(log LogPushEntry) {
- if p.log != nil {
- *p.log = append(*p.log, log)
+// Bytes for queue message
+func (p *PushNotification) Bytes() []byte {
+ b, err := json.Marshal(p)
+ if err != nil {
+ panic(err)
}
+ return b
}
// IsTopic check if message format is topic for FCM
// ref: https://firebase.google.com/docs/cloud-messaging/send-message#topic-http-post-request
func (p *PushNotification) IsTopic() bool {
- if p.Platform == PlatFormAndroid {
+ if p.Platform == core.PlatFormAndroid {
return p.To != "" && strings.HasPrefix(p.To, "/topics/") || p.Condition != ""
}
- if p.Platform == PlatFormHuawei {
+ if p.Platform == core.PlatFormHuawei {
return p.Topic != "" || p.Condition != ""
}
@@ -144,39 +142,39 @@ func (p *PushNotification) IsTopic() bool {
}
// CheckMessage for check request message
-func CheckMessage(req PushNotification) error {
+func CheckMessage(req *PushNotification) error {
var msg string
// ignore send topic mesaage from FCM
if !req.IsTopic() && len(req.Tokens) == 0 && req.To == "" {
msg = "the message must specify at least one registration ID"
- LogAccess.Debug(msg)
+ logx.LogAccess.Debug(msg)
return errors.New(msg)
}
- if len(req.Tokens) == PlatFormIos && req.Tokens[0] == "" {
+ if len(req.Tokens) == core.PlatFormIos && req.Tokens[0] == "" {
msg = "the token must not be empty"
- LogAccess.Debug(msg)
+ logx.LogAccess.Debug(msg)
return errors.New(msg)
}
- if req.Platform == PlatFormAndroid && len(req.Tokens) > 1000 {
+ if req.Platform == core.PlatFormAndroid && len(req.Tokens) > 1000 {
msg = "the message may specify at most 1000 registration IDs"
- LogAccess.Debug(msg)
+ logx.LogAccess.Debug(msg)
return errors.New(msg)
}
- if req.Platform == PlatFormHuawei && len(req.Tokens) > 500 {
+ if req.Platform == core.PlatFormHuawei && len(req.Tokens) > 500 {
msg = "the message may specify at most 500 registration IDs for Huawei"
- LogAccess.Debug(msg)
+ logx.LogAccess.Debug(msg)
return errors.New(msg)
}
// ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref
- if req.Platform == PlatFormAndroid && req.TimeToLive != nil && *req.TimeToLive > uint(2419200) {
+ if req.Platform == core.PlatFormAndroid && req.TimeToLive != nil && *req.TimeToLive > uint(2419200) {
msg = "the message's TimeToLive field must be an integer " +
"between 0 and 2419200 (4 weeks)"
- LogAccess.Debug(msg)
+ logx.LogAccess.Debug(msg)
return errors.New(msg)
}
@@ -191,45 +189,83 @@ func SetProxy(proxy string) error {
}
http.DefaultTransport = &http.Transport{Proxy: http.ProxyURL(proxyURL)}
- LogAccess.Debug("Set http proxy as " + proxy)
+ logx.LogAccess.Debug("Set http proxy as " + proxy)
return nil
}
// CheckPushConf provide check your yml config.
-func CheckPushConf() error {
- if !PushConf.Ios.Enabled && !PushConf.Android.Enabled && !PushConf.Huawei.Enabled {
- return errors.New("Please enable iOS, Android or Huawei config in yml config")
+func CheckPushConf(cfg *config.ConfYaml) error {
+ if !cfg.Ios.Enabled && !cfg.Android.Enabled && !cfg.Huawei.Enabled {
+ return errors.New("please enable iOS, Android or Huawei config in yml config")
}
- if PushConf.Ios.Enabled {
- if PushConf.Ios.KeyPath == "" && PushConf.Ios.KeyBase64 == "" {
- return errors.New("Missing iOS certificate key")
+ if cfg.Ios.Enabled {
+ if cfg.Ios.KeyPath == "" && cfg.Ios.KeyBase64 == "" {
+ return errors.New("missing iOS certificate key")
}
// check certificate file exist
- if PushConf.Ios.KeyPath != "" {
- if _, err := os.Stat(PushConf.Ios.KeyPath); os.IsNotExist(err) {
+ if cfg.Ios.KeyPath != "" {
+ if _, err := os.Stat(cfg.Ios.KeyPath); os.IsNotExist(err) {
return errors.New("certificate file does not exist")
}
}
}
- if PushConf.Android.Enabled {
- if PushConf.Android.APIKey == "" {
+ if cfg.Android.Enabled {
+ if cfg.Android.APIKey == "" {
return errors.New("Missing Android API Key")
}
}
- if PushConf.Huawei.Enabled {
- if PushConf.Huawei.AppSecret == "" {
+ if cfg.Huawei.Enabled {
+ if cfg.Huawei.AppSecret == "" {
return errors.New("Missing Huawei App Secret")
}
- if PushConf.Huawei.AppID == "" {
+ if cfg.Huawei.AppID == "" {
return errors.New("Missing Huawei App ID")
}
}
return nil
}
+
+// SendNotification send notification
+func SendNotification(req queue.QueuedMessage, cfg *config.ConfYaml) (resp *ResponsePush, err error) {
+ v, ok := req.(*PushNotification)
+ if !ok {
+ if err = json.Unmarshal(req.Bytes(), &v); err != nil {
+ return
+ }
+ }
+
+ switch v.Platform {
+ case core.PlatFormIos:
+ resp, err = PushToIOS(v, cfg)
+ case core.PlatFormAndroid:
+ resp, err = PushToAndroid(v, cfg)
+ case core.PlatFormHuawei:
+ resp, err = PushToHuawei(v, cfg)
+ }
+
+ if cfg.Core.FeedbackURL != "" {
+ for _, l := range resp.Logs {
+ err := DispatchFeedback(l, cfg.Core.FeedbackURL, cfg.Core.FeedbackTimeout)
+ if err != nil {
+ logx.LogError.Error(err)
+ }
+ }
+ }
+
+ return
+}
+
+// Run send notification
+var Run = func(cfg *config.ConfYaml) func(ctx context.Context, msg queue.QueuedMessage) error {
+ return func(ctx context.Context, msg queue.QueuedMessage) error {
+ _, err := SendNotification(msg, cfg)
+ return err
+ }
+}
diff --git a/gorush/notification_apns.go b/notify/notification_apns.go
similarity index 72%
rename from gorush/notification_apns.go
rename to notify/notification_apns.go
index f7f057d13..143cb4f0c 100644
--- a/gorush/notification_apns.go
+++ b/notify/notification_apns.go
@@ -1,9 +1,10 @@
-package gorush
+package notify
import (
"crypto/ecdsa"
"crypto/tls"
"encoding/base64"
+ "encoding/json"
"errors"
"net"
"net/http"
@@ -11,12 +12,16 @@ import (
"sync"
"time"
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/core"
+ "github.com/appleboy/gorush/logx"
+ "github.com/appleboy/gorush/status"
+
"github.com/mitchellh/mapstructure"
"github.com/sideshow/apns2"
"github.com/sideshow/apns2/certificate"
"github.com/sideshow/apns2/payload"
"github.com/sideshow/apns2/token"
- "github.com/sirupsen/logrus"
"golang.org/x/net/http2"
)
@@ -26,6 +31,8 @@ var (
tcpKeepAlive = 60 * time.Second
)
+var doOnce sync.Once
+
// DialTLS is the default dial function for creating TLS connections for
// non-proxied HTTPS requests.
var DialTLS = func(cfg *tls.Config) func(network, addr string) (net.Conn, error) {
@@ -46,45 +53,45 @@ type Sound struct {
}
// InitAPNSClient use for initialize APNs Client.
-func InitAPNSClient() error {
- if PushConf.Ios.Enabled {
+func InitAPNSClient(cfg *config.ConfYaml) error {
+ if cfg.Ios.Enabled {
var err error
var authKey *ecdsa.PrivateKey
var certificateKey tls.Certificate
var ext string
- if PushConf.Ios.KeyPath != "" {
- ext = filepath.Ext(PushConf.Ios.KeyPath)
+ if cfg.Ios.KeyPath != "" {
+ ext = filepath.Ext(cfg.Ios.KeyPath)
switch ext {
case ".p12":
- certificateKey, err = certificate.FromP12File(PushConf.Ios.KeyPath, PushConf.Ios.Password)
+ certificateKey, err = certificate.FromP12File(cfg.Ios.KeyPath, cfg.Ios.Password)
case ".pem":
- certificateKey, err = certificate.FromPemFile(PushConf.Ios.KeyPath, PushConf.Ios.Password)
+ certificateKey, err = certificate.FromPemFile(cfg.Ios.KeyPath, cfg.Ios.Password)
case ".p8":
- authKey, err = token.AuthKeyFromFile(PushConf.Ios.KeyPath)
+ authKey, err = token.AuthKeyFromFile(cfg.Ios.KeyPath)
default:
err = errors.New("wrong certificate key extension")
}
if err != nil {
- LogError.Error("Cert Error:", err.Error())
+ logx.LogError.Error("Cert Error:", err.Error())
return err
}
- } else if PushConf.Ios.KeyBase64 != "" {
- ext = "." + PushConf.Ios.KeyType
- key, err := base64.StdEncoding.DecodeString(PushConf.Ios.KeyBase64)
+ } else if cfg.Ios.KeyBase64 != "" {
+ ext = "." + cfg.Ios.KeyType
+ key, err := base64.StdEncoding.DecodeString(cfg.Ios.KeyBase64)
if err != nil {
- LogError.Error("base64 decode error:", err.Error())
+ logx.LogError.Error("base64 decode error:", err.Error())
return err
}
switch ext {
case ".p12":
- certificateKey, err = certificate.FromP12Bytes(key, PushConf.Ios.Password)
+ certificateKey, err = certificate.FromP12Bytes(key, cfg.Ios.Password)
case ".pem":
- certificateKey, err = certificate.FromPemBytes(key, PushConf.Ios.Password)
+ certificateKey, err = certificate.FromPemBytes(key, cfg.Ios.Password)
case ".p8":
authKey, err = token.AuthKeyFromBytes(key)
default:
@@ -92,29 +99,29 @@ func InitAPNSClient() error {
}
if err != nil {
- LogError.Error("Cert Error:", err.Error())
+ logx.LogError.Error("Cert Error:", err.Error())
return err
}
}
if ext == ".p8" {
- if PushConf.Ios.KeyID == "" || PushConf.Ios.TeamID == "" {
+ if cfg.Ios.KeyID == "" || cfg.Ios.TeamID == "" {
msg := "You should provide ios.KeyID and ios.TeamID for P8 token"
- LogError.Error(msg)
+ logx.LogError.Error(msg)
return errors.New(msg)
}
token := &token.Token{
AuthKey: authKey,
// KeyID from developer account (Certificates, Identifiers & Profiles -> Keys)
- KeyID: PushConf.Ios.KeyID,
+ KeyID: cfg.Ios.KeyID,
// TeamID from developer account (View Account -> Membership)
- TeamID: PushConf.Ios.TeamID,
+ TeamID: cfg.Ios.TeamID,
}
- ApnsClient, err = newApnsTokenClient(token)
+ ApnsClient, err = newApnsTokenClient(cfg, token)
} else {
- ApnsClient, err = newApnsClient(certificateKey)
+ ApnsClient, err = newApnsClient(cfg, certificateKey)
}
if h2Transport, ok := ApnsClient.HTTPClient.Transport.(*http2.Transport); ok {
@@ -122,25 +129,29 @@ func InitAPNSClient() error {
}
if err != nil {
- LogError.Error("Transport Error:", err.Error())
+ logx.LogError.Error("Transport Error:", err.Error())
return err
}
+
+ doOnce.Do(func() {
+ MaxConcurrentIOSPushes = make(chan struct{}, cfg.Ios.MaxConcurrentPushes)
+ })
}
return nil
}
-func newApnsClient(certificate tls.Certificate) (*apns2.Client, error) {
+func newApnsClient(cfg *config.ConfYaml, certificate tls.Certificate) (*apns2.Client, error) {
var client *apns2.Client
- if PushConf.Ios.Production {
+ if cfg.Ios.Production {
client = apns2.NewClient(certificate).Production()
} else {
client = apns2.NewClient(certificate).Development()
}
- if PushConf.Core.HTTPProxy == "" {
+ if cfg.Core.HTTPProxy == "" {
return client, nil
}
@@ -171,16 +182,16 @@ func newApnsClient(certificate tls.Certificate) (*apns2.Client, error) {
return client, nil
}
-func newApnsTokenClient(token *token.Token) (*apns2.Client, error) {
+func newApnsTokenClient(cfg *config.ConfYaml, token *token.Token) (*apns2.Client, error) {
var client *apns2.Client
- if PushConf.Ios.Production {
+ if cfg.Ios.Production {
client = apns2.NewTokenClient(token).Production()
} else {
client = apns2.NewTokenClient(token).Development()
}
- if PushConf.Core.HTTPProxy == "" {
+ if cfg.Core.HTTPProxy == "" {
return client, nil
}
@@ -207,7 +218,7 @@ func configureHTTP2ConnHealthCheck(h2Transport *http2.Transport) {
h2Transport.PingTimeout = 1 * time.Second
}
-func iosAlertDictionary(payload *payload.Payload, req PushNotification) *payload.Payload {
+func iosAlertDictionary(payload *payload.Payload, req *PushNotification) *payload.Payload {
// Alert dictionary
if len(req.Title) > 0 {
@@ -276,9 +287,9 @@ func iosAlertDictionary(payload *payload.Payload, req PushNotification) *payload
}
// GetIOSNotification use for define iOS notification.
-// The iOS Notification Payload
-// ref: https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html#//apple_ref/doc/uid/TP40008194-CH17-SW1
-func GetIOSNotification(req PushNotification) *apns2.Notification {
+// The iOS Notification Payload (Payload Key Reference)
+// Ref: https://apple.co/2VtH6Iu
+func GetIOSNotification(req *PushNotification) (*apns2.Notification, error) {
notification := &apns2.Notification{
ApnsID: req.ApnsID,
Topic: req.Topic,
@@ -358,42 +369,54 @@ func GetIOSNotification(req PushNotification) *apns2.Notification {
notification.Payload = payload
- return notification
+ jsonMarshall, err := json.Marshal(notification)
+ if err != nil {
+ LogError.Error("Failed to marshal the default message! Error is " + err.Error())
+ return nil, err
+ }
+
+ LogAccess.Debugf("Default message is %s", string(jsonMarshall))
+
+ return notification, nil
}
-func getApnsClient(req PushNotification) (client *apns2.Client) {
- if req.Production {
+func getApnsClient(cfg *config.ConfYaml, req *PushNotification) (client *apns2.Client) {
+ switch {
+ case req.Production:
client = ApnsClient.Production()
- } else if req.Development {
+ case req.Development:
client = ApnsClient.Development()
- } else {
- if PushConf.Ios.Production {
+ default:
+ if cfg.Ios.Production {
client = ApnsClient.Production()
} else {
client = ApnsClient.Development()
}
}
+
return
}
// PushToIOS provide send notification to APNs server.
-func PushToIOS(req PushNotification) {
- LogAccess.Debug("Start push notification for iOS")
+func PushToIOS(req *PushNotification, cfg *config.ConfYaml) (resp *ResponsePush, err error) {
+ logx.LogAccess.Debug("Start push notification for iOS")
var (
retryCount = 0
- maxRetry = PushConf.Ios.MaxRetry
+ maxRetry = cfg.Ios.MaxRetry
)
if req.Retry > 0 && req.Retry < maxRetry {
maxRetry = req.Retry
}
+ resp = &ResponsePush{}
+
Retry:
var newTokens []string
- notification := GetIOSNotification(req)
- client := getApnsClient(req)
+ notification, _ := GetIOSNotification(req)
+ client := getApnsClient(cfg, req)
var wg sync.WaitGroup
for _, token := range req.Tokens {
@@ -411,37 +434,30 @@ Retry:
// ref: https://github.com/sideshow/apns2/blob/master/response.go#L14-L65
err = errors.New(res.Reason)
}
+
// apns server error
- LogPush(FailedPush, token, req, err)
-
- if PushConf.Core.Sync {
- req.AddLog(getLogPushEntry(FailedPush, token, req, err))
- } else if PushConf.Core.FeedbackURL != "" {
- go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) {
- err := DispatchFeedback(log, url, timeout)
- if err != nil {
- logger.Error(err)
- }
- }(LogError, getLogPushEntry(FailedPush, token, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
- }
+ errLog := logPush(cfg, core.FailedPush, token, req, err)
+ resp.Logs = append(resp.Logs, errLog)
- StatStorage.AddIosError(1)
+ status.StatStorage.AddIosError(1)
// We should retry only "retryable" statuses. More info about response:
- // https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/handling_notification_responses_from_apns
+ // See https://apple.co/3AdNane (Handling Notification Responses from APNs)
if res != nil && res.StatusCode >= http.StatusInternalServerError {
newTokens = append(newTokens, token)
}
}
if res != nil && res.Sent() {
- LogPush(SucceededPush, token, req, nil)
- StatStorage.AddIosSuccess(1)
+ logPush(cfg, core.SucceededPush, token, req, nil)
+ status.StatStorage.AddIosSuccess(1)
}
+
// free push slot
<-MaxConcurrentIOSPushes
wg.Done()
}(*notification, token)
}
+
wg.Wait()
if len(newTokens) > 0 && retryCount < maxRetry {
@@ -451,4 +467,6 @@ Retry:
req.Tokens = newTokens
goto Retry
}
+
+ return resp, nil
}
diff --git a/gorush/notification_apns_test.go b/notify/notification_apns_test.go
similarity index 52%
rename from gorush/notification_apns_test.go
rename to notify/notification_apns_test.go
index e000133e2..28dc318fe 100644
--- a/gorush/notification_apns_test.go
+++ b/notify/notification_apns_test.go
@@ -1,53 +1,54 @@
-package gorush
+package notify
import (
- "context"
- "encoding/json"
"log"
"net/http"
"net/url"
- "os"
"testing"
"time"
"github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/status"
"github.com/buger/jsonparser"
"github.com/sideshow/apns2"
"github.com/stretchr/testify/assert"
)
-const certificateValidP12 = `MIIKlgIBAzCCClwGCSqGSIb3DQEHAaCCCk0EggpJMIIKRTCCBMcGCSqGSIb3DQEHBqCCBLgwggS0AgEAMIIErQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQID/GJtcRhjvwCAggAgIIEgE5ralQoQBDgHgdp5+EwBaMjcZEJUXmYRdVCttIwfN2OxlIs54tob3/wpUyWGqJ+UXy9X+4EsWpDPUfTN/w88GMgj0kftpTqG0+3Hu/9pkZO4pdLCiyMGOJnXCOdhHFirtTXAR3QvnKKIpXIKrmZ4rcr/24Uvd/u669Tz8VDgcGOQazKeyvtdW7TJBxMFRv+IsQi/qCj5PkQ0jBbZ1LAc4C8mCMwOcH+gi/e471mzPWihQmynH2yJlZ4jb+taxQ/b8Dhlni2vcIMn+HknRk3Cyo8jfFvvO0BjvVvEAPxPJt7X96VFFS2KlyXjY3zt0siGrzQpczgPB/1vTqhQUvoOBw6kcXWgOjwt+gR8Mmo2DELnQqGhbYuWu52doLgVvD+zGr5vLYXHz6gAXnI6FVyHb+oABeBet3cer3EzGR7r+VoLmWSBm8SyRHwi0mxE63S7oD1j22jaTo7jnQBFZaY+cPaATcFjqW67x4j8kXh9NRPoINSgodLJrgmet2D1iOKuLTkCWf0UTi2HUkn9Zf0y+IIViZaVE4mWaGb9xTBClfa4KwM5gSz3jybksFKbtnzzPFuzClu+2mdthJs/58Ao40eyaykNmzSPhDv1F8Mai8bfaAqSdcBl5ZB2PF33xhuNSS4j2uIh1ICGv9DueyN507iEMQO2yCcaQTMKejV7/52h9LReS5/QPXDJhWMVpTb5FGCP7EmO0lZTeBNO5MlDzDQfz5xcFqHqfoby2sfAMU8HNB8wzdcwHtacgKGLBjLkapxyTsqYE5Kry6UxclvF4soR8TZoQ69E7WsKZLmTaw2+msmnDJubpY0NqkRqkVk7umtVC0D+w6AIKDrY58HMlm80/ImgGXwybA1kuZMxqMzaH/xFiAHOSIGuVPtGgGFYNEdGbfOryuhFo9l1nSECWm8MN9hYwB1Rn9p6rkd+zrvbU1zv13drtrZ/vL0NlT02tlkS8NdWLGJkZhWgc2c89GyRb7mjuHRHu/BWGED3y7vjHo/lnkPsLJXw0ovIlqhtW0BtN/xSpGg0phDbn0Et5jb7Xmc+fWimgbtIUHcnJOV5QSYFzlR+kbzx0oKRARU4B3CWkdPeaXkrmw0IriS6vOdZcM8YBJ6BtXEDLsrSH7tHxeknYHLEl0uy9Oc1+Huyrz8j7Zxo8SQj9H+RX0HeMl8YB3HUBLHYcqCEBjm7mHI4rP8ULVkC5oCA5w3tJfMyvS/jZRiwMUyr0tiWhrh/AM3wPPX54cqozefojWKrqGtK9I+n0cfwW9rU3FsUcpMTo9uQ27O7NejKP2X/LLMZkQvWUEabZNjNrWsbp6d51/frfIR7kRlZAmmt2yS23h6w6RvKTAVUrNatEyzokfNAIDml6lYLweNJATZU08BznhPpuvh3bKOSos5uaJBYpsOYexoMGnAig428qypw0cmv6sCjO/xdIL86COVNQp/UtjcXJ9/E0bnVmzfpgA3WCy+29YXPx7DZ1U+bQ9jOO/P9pwqLwTH+gpcZiVm3ru1Tmiq6iZ8cG7tMLfTBNXljvtlDzCCBXYGCSqGSIb3DQEHAaCCBWcEggVjMIIFXzCCBVsGCyqGSIb3DQEMCgECoIIE7jCCBOowHAYKKoZIhvcNAQwBAzAOBAgCvAo2HCM89AICCAAEggTIOcfaF6qWYXlo+BNBjYIllg0VwQSJXZmcqj2vXlDPIPrTuQ+QDmGnhYR6hVbcMrk3o7eQhH3ThyHM+KEzkYx1IAYCOdEQXYcFguoDG1CxHrgE1Y0H8yndc/yPw2tqkx6X9ZemdYp3welXZjYgUi9MKvGbN6lZ0cFTU+2+0+H/IyKQ3OUjDNymhOxypOPBaK2eQsJ7XumgJ6nLvNZDRx/f277J+LD/z0pOhzUOljhvA3dkBMpEvomX4erZihErunqP1jbH9O3eIYq9J7czGS2xuckolW19KqWOyWh8KRI/LnAqiEh2e0hZ7lpltj79PenO66VGPbn2f85A6b6PD4kipgoMB2IRibkoodyn/oo3WizO386fqtEfUlbFmxI4y4utobWe7nZ2VuBLgA/mgyyxqAJK1erM98NDWB/Njo1CPsaMl9ubXKPOyIZG0fOLUa23DfkJUEiCb839yKc2oEJkI0wtrvbeh1TAPv4vL4TxiXdiJ/6YrSa0/FQh6nqk1jiK+p22MzvEIkDOyPqk/GsAlc/k2kQ/M86tF50wtc08wnXv8+G8k6qTZ7VCluffzAUt64La47qj8XIfh7tKleznzQSbyjlNX8DsFVzGbCg9G4PKxrLAVnKEgIK1kOopSF1UUMqSKE0D3s5AURQhX8/Cf9h+WtNsWK+y7EMOntsBc2op0M7fQ9Jm73NF7CCYeqb0W7sziJSzqJsJgNp0+ArAcZQExeltxAb6kye3Z5JtP/oaB+jmcHKy9l/nhzKA3MzJwCZ5Q3oviPlNqJvFVBmGEEvC6iULLuv6VSxNdB2uH3Tsfa1TMOOHOadBTcyWatjscYS9ynkXuw1+8+FvEu3EV0UwopZmlSaYfMKQ2jshT4Cgg1zy15uKjomojtAaaF+D/U6KZVQk/7rzdaDmvkJvNtc5n9BW96tmrOhI6L+/WihS570qaitQUsHBBTOetlHXYEPiOkH8BhjzNHXLH9YpC8OEQOhO+1jEninDKNdbU7SCqV0+YE6kfR5Bfkw2MxoIQLtUnHjK6GR/q3fxo1TirbTe8c8dp907wgcXkT/rONX/iG1JTjxV2ixR1oM68LYI3eJzY801/xBSnmOjdzOPUHXCNHDTf9kPjkOtZWkGbZugf4ckRH/L8dK2Vo4QpFUN8AZjomanzLxjQZ+DVFNoPDT2K+0pezsMiwSJlyBGoIQHN0/2zVNVLo/KfARIOac1iC8+duj5S/1c52+PvP7FkMe72QUV0KUQ7AJHXUvQtFZx4Ny579/B/3c4D72CFSydhw3/+nL9+Nz956UafZ6G7HZ96frMTgajMcXQe1uXwgN2iTnnNtLdcC/ARHS1RkjgXHohO+VGuQxOo23PPABVaxex2SGGXX7Fc4MI2Xr4uaimZIzcUkuHUnhZQGkcFlVekZ/wJXookq0Fv8DuPuv7mGCx6BKERU9I+NMU6xLNe6VsfkS8t5uVq1EIINnddGl9VGpqOPN8EgU47gh6CcDkP8sxXsT8pZ1vQyJrUlWGYp68/okoQ+7lqnd06wzVDIwAE/+pq9PUxLdNvYE0sNe4JrEcKO0xp/zxCqLjHLT+rB896v2OsU0BA5tPQA7xkKp4PuQr6qO8fTVyfhImVmoFX6b9VgtLHIlJMVowIwYJKoZIhvcNAQkVMRYEFIwanwBmvSRCuV0e6/5ei8oEPXODMDMGCSqGSIb3DQEJFDEmHiQAQQBQAE4AUwAvADIAIABQAHIAaQB2AGEAdABlACAASwBlAHkwMTAhMAkGBSsOAwIaBQAEFK7XWCbKGSKmxNqE2E8dmCfwhaQxBAjPcbkv12ro6gICCAA=`
-
-const certificateValidPEM = `QmFnIEF0dHJpYnV0ZXMKICAgIGxvY2FsS2V5SUQ6IDhDIDFBIDlGIDAwIDY2IEJEIDI0IDQyIEI5IDVEIDFFIEVCIEZFIDVFIDhCIENBIDA0IDNEIDczIDgzIAogICAgZnJpZW5kbHlOYW1lOiBBUE5TLzIgUHJpdmF0ZSBLZXkKc3ViamVjdD0vQz1OWi9TVD1XZWxsaW5ndG9uL0w9V2VsbGluZ3Rvbi9PPUludGVybmV0IFdpZGdpdHMgUHR5IEx0ZC9PVT05WkVINjJLUlZWL0NOPUFQTlMvMiBEZXZlbG9wbWVudCBJT1MgUHVzaCBTZXJ2aWNlczogY29tLnNpZGVzaG93LkFwbnMyCmlzc3Vlcj0vQz1OWi9TVD1XZWxsaW5ndG9uL0w9V2VsbGluZ3Rvbi9PPUFQTlMvMiBJbmMuL09VPUFQTlMvMiBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9ucy9DTj1BUE5TLzIgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ2ekNDQXRNQ0FRSXdEUVlKS29aSWh2Y05BUUVMQlFBd2djTXhDekFKQmdOVkJBWVRBazVhTVJNd0VRWUQKVlFRSUV3cFhaV3hzYVc1bmRHOXVNUk13RVFZRFZRUUhFd3BYWld4c2FXNW5kRzl1TVJRd0VnWURWUVFLRXd0QgpVRTVUTHpJZ1NXNWpMakV0TUNzR0ExVUVDeE1rUVZCT1V5OHlJRmR2Y214a2QybGtaU0JFWlhabGJHOXdaWElnClVtVnNZWFJwYjI1ek1VVXdRd1lEVlFRREV6eEJVRTVUTHpJZ1YyOXliR1IzYVdSbElFUmxkbVZzYjNCbGNpQlMKWld4aGRHbHZibk1nUTJWeWRHbG1hV05oZEdsdmJpQkJkWFJvYjNKcGRIa3dIaGNOTVRZd01UQTRNRGd6TkRNdwpXaGNOTWpZd01UQTFNRGd6TkRNd1dqQ0JzakVMTUFrR0ExVUVCaE1DVGxveEV6QVJCZ05WQkFnVENsZGxiR3hwCmJtZDBiMjR4RXpBUkJnTlZCQWNUQ2xkbGJHeHBibWQwYjI0eElUQWZCZ05WQkFvVEdFbHVkR1Z5Ym1WMElGZHAKWkdkcGRITWdVSFI1SUV4MFpERVRNQkVHQTFVRUN4TUtPVnBGU0RZeVMxSldWakZCTUQ4R0ExVUVBeE00UVZCTwpVeTh5SUVSbGRtVnNiM0J0Wlc1MElFbFBVeUJRZFhOb0lGTmxjblpwWTJWek9pQmpiMjB1YzJsa1pYTm9iM2N1ClFYQnVjekl3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRFkwYzFUS0I1b1pQd1EKN3QxQ3dNSXJ2cUI2R0lVM3RQeTZSaGNrWlhUa09COFllQldKN1VLZkN6OEhHSEZWb21CUDBUNU9VYmVxUXpxVwpZSmJRelo4YTZaTXN6YkwwbE80WDkrKzNPaTUvVHRBd09VT0s4ck9GTjI1bTJLZnNheUhRWi80dldTdEsyRndtCjVhSmJHTGxwSC9iLzd6MUQ0dmhtTWdvQnVUMUl1eWhHaXlGeGxaOUV0VGxvRnZzcU0xRTVmWVpPU1pBQ3lYVGEKSzR2ZGdiUU1nVVZzSTcxNEZBZ0xUbEswVWVpUmttS20zcGRidGZWYnJ0aHpJK0lIWEtJdFVJeStGbjIwUFJNaApkU25henRTejd0Z0JXQ0l4MjJxdmNZb2dIV2lPZ1VZSU03NzJ6RTJ5OFVWT3I4RHNpUmxzT0hTQTdFSTRNSmNRCkcyRlVxMlovQWdNQkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBR3lmeU8ySE1nY2RlQmN6M2J0NUJJTFgKZjdSQTIvVW1WSXdjS1IxcW90VHNGK1BuQm1jSUxleU9RZ0RlOXRHVTVjUmM3OWtEdDNKUm1NWVJPRklNZ0ZSZgpXZjIydU9LdGhvN0dRUWFLdkcrYmtnTVZkWUZSbEJIbkYrS2VxS0g4MXFiOXArQ1Q0SXcwR2VoSUwxRGlqRkxSClZJQUlCWXB6NG9CUENJRTFJU1ZUK0ZnYWYzSkFoNTlrYlBiTnc5QUlEeGFCdFA4RXV6U1ROd2ZieG9HYkNvYlMKV2kxVThJc0N3UUZ0OHRNMW00WlhEMUNjWklyR2RyeWVBaFZrdktJSlJpVTVRWVdJMm5xWk4rSnFRdWNtOWFkMAptWU81bUprSW9iVWE0K1pKaENQS0VkbWdwRmJSR2swd1Z1YURNOUN2NlAyc3JzWUFqYU80eTNWUDBHdk5LUkk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KQmFnIEF0dHJpYnV0ZXMKICAgIGxvY2FsS2V5SUQ6IDhDIDFBIDlGIDAwIDY2IEJEIDI0IDQyIEI5IDVEIDFFIEVCIEZFIDVFIDhCIENBIDA0IDNEIDczIDgzIAogICAgZnJpZW5kbHlOYW1lOiBBUE5TLzIgUHJpdmF0ZSBLZXkKS2V5IEF0dHJpYnV0ZXM6IDxObyBBdHRyaWJ1dGVzPgotLS0tLUJFR0lOIFJTQSBQUklWQVRFIEtFWS0tLS0tCk1JSUVvd0lCQUFLQ0FRRUEyTkhOVXlnZWFHVDhFTzdkUXNEQ0s3NmdlaGlGTjdUOHVrWVhKR1YwNURnZkdIZ1YKaWUxQ253cy9CeGh4VmFKZ1Q5RStUbEczcWtNNmxtQ1cwTTJmR3VtVExNMnk5SlR1Ri9mdnR6b3VmMDdRTURsRAppdkt6aFRkdVp0aW43R3NoMEdmK0wxa3JTdGhjSnVXaVd4aTVhUi8yLys4OVErTDRaaklLQWJrOVNMc29Sb3NoCmNaV2ZSTFU1YUJiN0tqTlJPWDJHVGttUUFzbDAyaXVMM1lHMERJRkZiQ085ZUJRSUMwNVN0Rkhva1pKaXB0NlgKVzdYMVc2N1ljeVBpQjF5aUxWQ012aFo5dEQwVElYVXAyczdVcys3WUFWZ2lNZHRxcjNHS0lCMW9qb0ZHQ0RPKwo5c3hOc3ZGRlRxL0E3SWtaYkRoMGdPeENPRENYRUJ0aFZLdG1md0lEQVFBQkFvSUJBUUNXOFpDSStPQWFlMXRFCmlwWjlGMmJXUDNMSExYVG84RllWZENBK1ZXZUlUazNQb2lJVWtKbVYwYVdDVWhEc3RndG81ZG9EZWo1c0NUdXIKWHZqL3luYWVyTWVxSkZZV2tld2p3WmNnTHlBWnZ3dU8xdjdmcDlFMHgvOVRHRGZuampuUE5lYXVuZHhXMGNOdAp6T1kzbDBIVkhzeTlKcGUzUURjQUpvdnk0VHY1K2hGWTRrRHhVQkdzeWp2aFNjVmdLZzV0TGtKY2xtM3NPdS9MCkd5THFwd05JM09KQWRNSXVWRDROMkJaMWFPRWFwNm1wMnk4SWUwL1I0WVdjYVo1QTRQdzd4VVBsNlNYYzl1dWEKLzc4UVRFUnRQQzZlanlDQmlFMDVhOG0zUTNpdWQzWHRubHl3czJLd2hnQkFmRTZNNHpSL2YzT1FCN1pJWE1oeQpacG1aWnc1eEFvR0JBUFluODRJcmxJUWV0V1FmdlBkTTdLemdoNlVESEN1Z25sQ0RnaHdZcFJKR2k4aE1mdVpWCnhOSXJZQUp6TFlEUTAxbEZKUkpnV1hUY2JxejlOQnoxbmhnK2NOT3oxL0tZKzM4ZXVkZWU2RE5ZbXp0UDdqRFAKMmpuYVMrZHRqQzhoQVhPYm5GcUcrTmlsTURMTHU2YVJtckphSW1ialNyZnlMaUU2bXZKN3U4MW5Bb0dCQU9GOQpnOTN3WjBtTDFyazJzNVd3SEdUTlUvSGFPdG1XUzR6N2tBN2Y0UWFSdWIrTXdwcFptbURaUEhwaVpYN0JQY1p6CmlPUFFoK3huN0lxUkdvUVdCTHlrQlZ0OHpaRm9MWkpvQ1IzbjYzbGV4NUE0cC8wUHAxZ0ZaclIreFg4UFlWb3MKM3llZWlXeVBLc1hYTmMwczVRd0haY1g2V2I4RUhUaFRYR0NCZXRjcEFvR0FNZVFKQzlJUGFQUGNhZTJ3M0NMQQpPWTNNa0ZwZ0JFdXFxc0RzeHdzTHNmZVFiMGxwMHYrQlErTzhzdUpyVDVlRHJxMUFCVWgzK1NLUVlBbDEzWVMrCnhVVXFrdzM1YjljbjZpenRGOUhDV0YzV0lLQmpzNHI5UFFxTXBkeGpORTRwUUNoQytXb3YxNkVyY3JBdVdXVmIKaUZpU2JtNFUvOUZiSGlzRnFxMy9jM01DZ1lCK3Z6U3VQZ0Z3MzcrMG9FRFZ0UVpneXVHU29wNU56Q052ZmIvOQovRzNhYVhORmJuTzhtdjBoenpvbGVNV2dPRExuSis0Y1VBejNIM3RnY0N1OWJ6citaaHYwenZRbDlhOFlDbzZGClZ1V1BkVzByYmcxUE84dE91TXFBVG5ubzc5WkMvOUgzelM5bDdCdVkxVjJTbE5leXFUM1Z5T0ZGYzZTUkVwcHMKVEp1bDhRS0JnQXhuUUI4TUE3elBVTHUxY2x5YUpMZHRFZFJQa0tXTjdsS1lwdGMwZS9WSGZTc0t4c2VXa2ZxaQp6Z1haNTFrUVRyVDZaYjZIWVJmd0MxbU1YSFdSS1J5WWpBbkN4VmltNllRZCtLVlQ0OWlSRERBaUlGb01HQTRpCnZ2Y0lsbmVxT1paUERJb0tKNjBJak8vRFpIV2t3NW1MamFJclQrcVEzWEFHZEpBMTNoY20KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K`
-
-const authkeyInvalidP8 = `TUlHSEFnRUFNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQkcwd2F3SUJBUVFnRWJWemZQblpQeGZBeXhxRQpaVjA1bGFBb0pBbCsvNlh0Mk80bU9CNjExc09oUkFOQ0FBU2dGVEtqd0pBQVU5NWcrKy92ektXSGt6QVZtTk1JCnRCNXZUalpPT0l3bkViNzBNc1daRkl5VUZEMVA5R3dzdHo0K2FrSFg3dkk4Qkg2aEhtQm1mWlpaCg==`
-
-const authkeyValidP8 = `LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ0ViVnpmUG5aUHhmQXl4cUUKWlYwNWxhQW9KQWwrLzZYdDJPNG1PQjYxMXNPaFJBTkNBQVNnRlRLandKQUFVOTVnKysvdnpLV0hrekFWbU5NSQp0QjV2VGpaT09Jd25FYjcwTXNXWkZJeVVGRDFQOUd3c3R6NCtha0hYN3ZJOEJINmhIbUJtZmVRbAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==`
+const (
+ // nolint
+ certificateValidP12 = `MIIKlgIBAzCCClwGCSqGSIb3DQEHAaCCCk0EggpJMIIKRTCCBMcGCSqGSIb3DQEHBqCCBLgwggS0AgEAMIIErQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQID/GJtcRhjvwCAggAgIIEgE5ralQoQBDgHgdp5+EwBaMjcZEJUXmYRdVCttIwfN2OxlIs54tob3/wpUyWGqJ+UXy9X+4EsWpDPUfTN/w88GMgj0kftpTqG0+3Hu/9pkZO4pdLCiyMGOJnXCOdhHFirtTXAR3QvnKKIpXIKrmZ4rcr/24Uvd/u669Tz8VDgcGOQazKeyvtdW7TJBxMFRv+IsQi/qCj5PkQ0jBbZ1LAc4C8mCMwOcH+gi/e471mzPWihQmynH2yJlZ4jb+taxQ/b8Dhlni2vcIMn+HknRk3Cyo8jfFvvO0BjvVvEAPxPJt7X96VFFS2KlyXjY3zt0siGrzQpczgPB/1vTqhQUvoOBw6kcXWgOjwt+gR8Mmo2DELnQqGhbYuWu52doLgVvD+zGr5vLYXHz6gAXnI6FVyHb+oABeBet3cer3EzGR7r+VoLmWSBm8SyRHwi0mxE63S7oD1j22jaTo7jnQBFZaY+cPaATcFjqW67x4j8kXh9NRPoINSgodLJrgmet2D1iOKuLTkCWf0UTi2HUkn9Zf0y+IIViZaVE4mWaGb9xTBClfa4KwM5gSz3jybksFKbtnzzPFuzClu+2mdthJs/58Ao40eyaykNmzSPhDv1F8Mai8bfaAqSdcBl5ZB2PF33xhuNSS4j2uIh1ICGv9DueyN507iEMQO2yCcaQTMKejV7/52h9LReS5/QPXDJhWMVpTb5FGCP7EmO0lZTeBNO5MlDzDQfz5xcFqHqfoby2sfAMU8HNB8wzdcwHtacgKGLBjLkapxyTsqYE5Kry6UxclvF4soR8TZoQ69E7WsKZLmTaw2+msmnDJubpY0NqkRqkVk7umtVC0D+w6AIKDrY58HMlm80/ImgGXwybA1kuZMxqMzaH/xFiAHOSIGuVPtGgGFYNEdGbfOryuhFo9l1nSECWm8MN9hYwB1Rn9p6rkd+zrvbU1zv13drtrZ/vL0NlT02tlkS8NdWLGJkZhWgc2c89GyRb7mjuHRHu/BWGED3y7vjHo/lnkPsLJXw0ovIlqhtW0BtN/xSpGg0phDbn0Et5jb7Xmc+fWimgbtIUHcnJOV5QSYFzlR+kbzx0oKRARU4B3CWkdPeaXkrmw0IriS6vOdZcM8YBJ6BtXEDLsrSH7tHxeknYHLEl0uy9Oc1+Huyrz8j7Zxo8SQj9H+RX0HeMl8YB3HUBLHYcqCEBjm7mHI4rP8ULVkC5oCA5w3tJfMyvS/jZRiwMUyr0tiWhrh/AM3wPPX54cqozefojWKrqGtK9I+n0cfwW9rU3FsUcpMTo9uQ27O7NejKP2X/LLMZkQvWUEabZNjNrWsbp6d51/frfIR7kRlZAmmt2yS23h6w6RvKTAVUrNatEyzokfNAIDml6lYLweNJATZU08BznhPpuvh3bKOSos5uaJBYpsOYexoMGnAig428qypw0cmv6sCjO/xdIL86COVNQp/UtjcXJ9/E0bnVmzfpgA3WCy+29YXPx7DZ1U+bQ9jOO/P9pwqLwTH+gpcZiVm3ru1Tmiq6iZ8cG7tMLfTBNXljvtlDzCCBXYGCSqGSIb3DQEHAaCCBWcEggVjMIIFXzCCBVsGCyqGSIb3DQEMCgECoIIE7jCCBOowHAYKKoZIhvcNAQwBAzAOBAgCvAo2HCM89AICCAAEggTIOcfaF6qWYXlo+BNBjYIllg0VwQSJXZmcqj2vXlDPIPrTuQ+QDmGnhYR6hVbcMrk3o7eQhH3ThyHM+KEzkYx1IAYCOdEQXYcFguoDG1CxHrgE1Y0H8yndc/yPw2tqkx6X9ZemdYp3welXZjYgUi9MKvGbN6lZ0cFTU+2+0+H/IyKQ3OUjDNymhOxypOPBaK2eQsJ7XumgJ6nLvNZDRx/f277J+LD/z0pOhzUOljhvA3dkBMpEvomX4erZihErunqP1jbH9O3eIYq9J7czGS2xuckolW19KqWOyWh8KRI/LnAqiEh2e0hZ7lpltj79PenO66VGPbn2f85A6b6PD4kipgoMB2IRibkoodyn/oo3WizO386fqtEfUlbFmxI4y4utobWe7nZ2VuBLgA/mgyyxqAJK1erM98NDWB/Njo1CPsaMl9ubXKPOyIZG0fOLUa23DfkJUEiCb839yKc2oEJkI0wtrvbeh1TAPv4vL4TxiXdiJ/6YrSa0/FQh6nqk1jiK+p22MzvEIkDOyPqk/GsAlc/k2kQ/M86tF50wtc08wnXv8+G8k6qTZ7VCluffzAUt64La47qj8XIfh7tKleznzQSbyjlNX8DsFVzGbCg9G4PKxrLAVnKEgIK1kOopSF1UUMqSKE0D3s5AURQhX8/Cf9h+WtNsWK+y7EMOntsBc2op0M7fQ9Jm73NF7CCYeqb0W7sziJSzqJsJgNp0+ArAcZQExeltxAb6kye3Z5JtP/oaB+jmcHKy9l/nhzKA3MzJwCZ5Q3oviPlNqJvFVBmGEEvC6iULLuv6VSxNdB2uH3Tsfa1TMOOHOadBTcyWatjscYS9ynkXuw1+8+FvEu3EV0UwopZmlSaYfMKQ2jshT4Cgg1zy15uKjomojtAaaF+D/U6KZVQk/7rzdaDmvkJvNtc5n9BW96tmrOhI6L+/WihS570qaitQUsHBBTOetlHXYEPiOkH8BhjzNHXLH9YpC8OEQOhO+1jEninDKNdbU7SCqV0+YE6kfR5Bfkw2MxoIQLtUnHjK6GR/q3fxo1TirbTe8c8dp907wgcXkT/rONX/iG1JTjxV2ixR1oM68LYI3eJzY801/xBSnmOjdzOPUHXCNHDTf9kPjkOtZWkGbZugf4ckRH/L8dK2Vo4QpFUN8AZjomanzLxjQZ+DVFNoPDT2K+0pezsMiwSJlyBGoIQHN0/2zVNVLo/KfARIOac1iC8+duj5S/1c52+PvP7FkMe72QUV0KUQ7AJHXUvQtFZx4Ny579/B/3c4D72CFSydhw3/+nL9+Nz956UafZ6G7HZ96frMTgajMcXQe1uXwgN2iTnnNtLdcC/ARHS1RkjgXHohO+VGuQxOo23PPABVaxex2SGGXX7Fc4MI2Xr4uaimZIzcUkuHUnhZQGkcFlVekZ/wJXookq0Fv8DuPuv7mGCx6BKERU9I+NMU6xLNe6VsfkS8t5uVq1EIINnddGl9VGpqOPN8EgU47gh6CcDkP8sxXsT8pZ1vQyJrUlWGYp68/okoQ+7lqnd06wzVDIwAE/+pq9PUxLdNvYE0sNe4JrEcKO0xp/zxCqLjHLT+rB896v2OsU0BA5tPQA7xkKp4PuQr6qO8fTVyfhImVmoFX6b9VgtLHIlJMVowIwYJKoZIhvcNAQkVMRYEFIwanwBmvSRCuV0e6/5ei8oEPXODMDMGCSqGSIb3DQEJFDEmHiQAQQBQAE4AUwAvADIAIABQAHIAaQB2AGEAdABlACAASwBlAHkwMTAhMAkGBSsOAwIaBQAEFK7XWCbKGSKmxNqE2E8dmCfwhaQxBAjPcbkv12ro6gICCAA=`
+ // nolint
+ certificateValidPEM = `QmFnIEF0dHJpYnV0ZXMKICAgIGxvY2FsS2V5SUQ6IDhDIDFBIDlGIDAwIDY2IEJEIDI0IDQyIEI5IDVEIDFFIEVCIEZFIDVFIDhCIENBIDA0IDNEIDczIDgzIAogICAgZnJpZW5kbHlOYW1lOiBBUE5TLzIgUHJpdmF0ZSBLZXkKc3ViamVjdD0vQz1OWi9TVD1XZWxsaW5ndG9uL0w9V2VsbGluZ3Rvbi9PPUludGVybmV0IFdpZGdpdHMgUHR5IEx0ZC9PVT05WkVINjJLUlZWL0NOPUFQTlMvMiBEZXZlbG9wbWVudCBJT1MgUHVzaCBTZXJ2aWNlczogY29tLnNpZGVzaG93LkFwbnMyCmlzc3Vlcj0vQz1OWi9TVD1XZWxsaW5ndG9uL0w9V2VsbGluZ3Rvbi9PPUFQTlMvMiBJbmMuL09VPUFQTlMvMiBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9ucy9DTj1BUE5TLzIgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ2ekNDQXRNQ0FRSXdEUVlKS29aSWh2Y05BUUVMQlFBd2djTXhDekFKQmdOVkJBWVRBazVhTVJNd0VRWUQKVlFRSUV3cFhaV3hzYVc1bmRHOXVNUk13RVFZRFZRUUhFd3BYWld4c2FXNW5kRzl1TVJRd0VnWURWUVFLRXd0QgpVRTVUTHpJZ1NXNWpMakV0TUNzR0ExVUVDeE1rUVZCT1V5OHlJRmR2Y214a2QybGtaU0JFWlhabGJHOXdaWElnClVtVnNZWFJwYjI1ek1VVXdRd1lEVlFRREV6eEJVRTVUTHpJZ1YyOXliR1IzYVdSbElFUmxkbVZzYjNCbGNpQlMKWld4aGRHbHZibk1nUTJWeWRHbG1hV05oZEdsdmJpQkJkWFJvYjNKcGRIa3dIaGNOTVRZd01UQTRNRGd6TkRNdwpXaGNOTWpZd01UQTFNRGd6TkRNd1dqQ0JzakVMTUFrR0ExVUVCaE1DVGxveEV6QVJCZ05WQkFnVENsZGxiR3hwCmJtZDBiMjR4RXpBUkJnTlZCQWNUQ2xkbGJHeHBibWQwYjI0eElUQWZCZ05WQkFvVEdFbHVkR1Z5Ym1WMElGZHAKWkdkcGRITWdVSFI1SUV4MFpERVRNQkVHQTFVRUN4TUtPVnBGU0RZeVMxSldWakZCTUQ4R0ExVUVBeE00UVZCTwpVeTh5SUVSbGRtVnNiM0J0Wlc1MElFbFBVeUJRZFhOb0lGTmxjblpwWTJWek9pQmpiMjB1YzJsa1pYTm9iM2N1ClFYQnVjekl3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRFkwYzFUS0I1b1pQd1EKN3QxQ3dNSXJ2cUI2R0lVM3RQeTZSaGNrWlhUa09COFllQldKN1VLZkN6OEhHSEZWb21CUDBUNU9VYmVxUXpxVwpZSmJRelo4YTZaTXN6YkwwbE80WDkrKzNPaTUvVHRBd09VT0s4ck9GTjI1bTJLZnNheUhRWi80dldTdEsyRndtCjVhSmJHTGxwSC9iLzd6MUQ0dmhtTWdvQnVUMUl1eWhHaXlGeGxaOUV0VGxvRnZzcU0xRTVmWVpPU1pBQ3lYVGEKSzR2ZGdiUU1nVVZzSTcxNEZBZ0xUbEswVWVpUmttS20zcGRidGZWYnJ0aHpJK0lIWEtJdFVJeStGbjIwUFJNaApkU25henRTejd0Z0JXQ0l4MjJxdmNZb2dIV2lPZ1VZSU03NzJ6RTJ5OFVWT3I4RHNpUmxzT0hTQTdFSTRNSmNRCkcyRlVxMlovQWdNQkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBR3lmeU8ySE1nY2RlQmN6M2J0NUJJTFgKZjdSQTIvVW1WSXdjS1IxcW90VHNGK1BuQm1jSUxleU9RZ0RlOXRHVTVjUmM3OWtEdDNKUm1NWVJPRklNZ0ZSZgpXZjIydU9LdGhvN0dRUWFLdkcrYmtnTVZkWUZSbEJIbkYrS2VxS0g4MXFiOXArQ1Q0SXcwR2VoSUwxRGlqRkxSClZJQUlCWXB6NG9CUENJRTFJU1ZUK0ZnYWYzSkFoNTlrYlBiTnc5QUlEeGFCdFA4RXV6U1ROd2ZieG9HYkNvYlMKV2kxVThJc0N3UUZ0OHRNMW00WlhEMUNjWklyR2RyeWVBaFZrdktJSlJpVTVRWVdJMm5xWk4rSnFRdWNtOWFkMAptWU81bUprSW9iVWE0K1pKaENQS0VkbWdwRmJSR2swd1Z1YURNOUN2NlAyc3JzWUFqYU80eTNWUDBHdk5LUkk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KQmFnIEF0dHJpYnV0ZXMKICAgIGxvY2FsS2V5SUQ6IDhDIDFBIDlGIDAwIDY2IEJEIDI0IDQyIEI5IDVEIDFFIEVCIEZFIDVFIDhCIENBIDA0IDNEIDczIDgzIAogICAgZnJpZW5kbHlOYW1lOiBBUE5TLzIgUHJpdmF0ZSBLZXkKS2V5IEF0dHJpYnV0ZXM6IDxObyBBdHRyaWJ1dGVzPgotLS0tLUJFR0lOIFJTQSBQUklWQVRFIEtFWS0tLS0tCk1JSUVvd0lCQUFLQ0FRRUEyTkhOVXlnZWFHVDhFTzdkUXNEQ0s3NmdlaGlGTjdUOHVrWVhKR1YwNURnZkdIZ1YKaWUxQ253cy9CeGh4VmFKZ1Q5RStUbEczcWtNNmxtQ1cwTTJmR3VtVExNMnk5SlR1Ri9mdnR6b3VmMDdRTURsRAppdkt6aFRkdVp0aW43R3NoMEdmK0wxa3JTdGhjSnVXaVd4aTVhUi8yLys4OVErTDRaaklLQWJrOVNMc29Sb3NoCmNaV2ZSTFU1YUJiN0tqTlJPWDJHVGttUUFzbDAyaXVMM1lHMERJRkZiQ085ZUJRSUMwNVN0Rkhva1pKaXB0NlgKVzdYMVc2N1ljeVBpQjF5aUxWQ012aFo5dEQwVElYVXAyczdVcys3WUFWZ2lNZHRxcjNHS0lCMW9qb0ZHQ0RPKwo5c3hOc3ZGRlRxL0E3SWtaYkRoMGdPeENPRENYRUJ0aFZLdG1md0lEQVFBQkFvSUJBUUNXOFpDSStPQWFlMXRFCmlwWjlGMmJXUDNMSExYVG84RllWZENBK1ZXZUlUazNQb2lJVWtKbVYwYVdDVWhEc3RndG81ZG9EZWo1c0NUdXIKWHZqL3luYWVyTWVxSkZZV2tld2p3WmNnTHlBWnZ3dU8xdjdmcDlFMHgvOVRHRGZuampuUE5lYXVuZHhXMGNOdAp6T1kzbDBIVkhzeTlKcGUzUURjQUpvdnk0VHY1K2hGWTRrRHhVQkdzeWp2aFNjVmdLZzV0TGtKY2xtM3NPdS9MCkd5THFwd05JM09KQWRNSXVWRDROMkJaMWFPRWFwNm1wMnk4SWUwL1I0WVdjYVo1QTRQdzd4VVBsNlNYYzl1dWEKLzc4UVRFUnRQQzZlanlDQmlFMDVhOG0zUTNpdWQzWHRubHl3czJLd2hnQkFmRTZNNHpSL2YzT1FCN1pJWE1oeQpacG1aWnc1eEFvR0JBUFluODRJcmxJUWV0V1FmdlBkTTdLemdoNlVESEN1Z25sQ0RnaHdZcFJKR2k4aE1mdVpWCnhOSXJZQUp6TFlEUTAxbEZKUkpnV1hUY2JxejlOQnoxbmhnK2NOT3oxL0tZKzM4ZXVkZWU2RE5ZbXp0UDdqRFAKMmpuYVMrZHRqQzhoQVhPYm5GcUcrTmlsTURMTHU2YVJtckphSW1ialNyZnlMaUU2bXZKN3U4MW5Bb0dCQU9GOQpnOTN3WjBtTDFyazJzNVd3SEdUTlUvSGFPdG1XUzR6N2tBN2Y0UWFSdWIrTXdwcFptbURaUEhwaVpYN0JQY1p6CmlPUFFoK3huN0lxUkdvUVdCTHlrQlZ0OHpaRm9MWkpvQ1IzbjYzbGV4NUE0cC8wUHAxZ0ZaclIreFg4UFlWb3MKM3llZWlXeVBLc1hYTmMwczVRd0haY1g2V2I4RUhUaFRYR0NCZXRjcEFvR0FNZVFKQzlJUGFQUGNhZTJ3M0NMQQpPWTNNa0ZwZ0JFdXFxc0RzeHdzTHNmZVFiMGxwMHYrQlErTzhzdUpyVDVlRHJxMUFCVWgzK1NLUVlBbDEzWVMrCnhVVXFrdzM1YjljbjZpenRGOUhDV0YzV0lLQmpzNHI5UFFxTXBkeGpORTRwUUNoQytXb3YxNkVyY3JBdVdXVmIKaUZpU2JtNFUvOUZiSGlzRnFxMy9jM01DZ1lCK3Z6U3VQZ0Z3MzcrMG9FRFZ0UVpneXVHU29wNU56Q052ZmIvOQovRzNhYVhORmJuTzhtdjBoenpvbGVNV2dPRExuSis0Y1VBejNIM3RnY0N1OWJ6citaaHYwenZRbDlhOFlDbzZGClZ1V1BkVzByYmcxUE84dE91TXFBVG5ubzc5WkMvOUgzelM5bDdCdVkxVjJTbE5leXFUM1Z5T0ZGYzZTUkVwcHMKVEp1bDhRS0JnQXhuUUI4TUE3elBVTHUxY2x5YUpMZHRFZFJQa0tXTjdsS1lwdGMwZS9WSGZTc0t4c2VXa2ZxaQp6Z1haNTFrUVRyVDZaYjZIWVJmd0MxbU1YSFdSS1J5WWpBbkN4VmltNllRZCtLVlQ0OWlSRERBaUlGb01HQTRpCnZ2Y0lsbmVxT1paUERJb0tKNjBJak8vRFpIV2t3NW1MamFJclQrcVEzWEFHZEpBMTNoY20KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K`
+ // nolint
+ authkeyInvalidP8 = `TUlHSEFnRUFNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQkcwd2F3SUJBUVFnRWJWemZQblpQeGZBeXhxRQpaVjA1bGFBb0pBbCsvNlh0Mk80bU9CNjExc09oUkFOQ0FBU2dGVEtqd0pBQVU5NWcrKy92ektXSGt6QVZtTk1JCnRCNXZUalpPT0l3bkViNzBNc1daRkl5VUZEMVA5R3dzdHo0K2FrSFg3dkk4Qkg2aEhtQm1mWlpaCg==`
+ // nolint
+ authkeyValidP8 = `LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ0ViVnpmUG5aUHhmQXl4cUUKWlYwNWxhQW9KQWwrLzZYdDJPNG1PQjYxMXNPaFJBTkNBQVNnRlRLandKQUFVOTVnKysvdnpLV0hrekFWbU5NSQp0QjV2VGpaT09Jd25FYjcwTXNXWkZJeVVGRDFQOUd3c3R6NCtha0hYN3ZJOEJINmhIbUJtZmVRbAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==`
+)
func TestDisabledAndroidIosConf(t *testing.T) {
- PushConf, _ = config.LoadConf("")
- PushConf.Android.Enabled = false
- PushConf.Huawei.Enabled = false
+ cfg, _ := config.LoadConf()
+ cfg.Android.Enabled = false
+ cfg.Huawei.Enabled = false
- err := CheckPushConf()
+ err := CheckPushConf(cfg)
assert.Error(t, err)
- assert.Equal(t, "Please enable iOS, Android or Huawei config in yml config", err.Error())
+ assert.Equal(t, "please enable iOS, Android or Huawei config in yml config", err.Error())
}
func TestMissingIOSCertificate(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = ""
- PushConf.Ios.KeyBase64 = ""
- err := CheckPushConf()
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = ""
+ cfg.Ios.KeyBase64 = ""
+ err := CheckPushConf(cfg)
assert.Error(t, err)
- assert.Equal(t, "Missing iOS certificate key", err.Error())
+ assert.Equal(t, "missing iOS certificate key", err.Error())
- PushConf.Ios.KeyPath = "test.pem"
- err = CheckPushConf()
+ cfg.Ios.KeyPath = "test.pem"
+ err = CheckPushConf(cfg)
assert.Error(t, err)
assert.Equal(t, "certificate file does not exist", err.Error())
@@ -60,8 +61,8 @@ func TestIOSNotificationStructure(t *testing.T) {
test := "test"
expectBadge := 0
message := "Welcome notification Server"
- expiration := int64(time.Now().Unix())
- req := PushNotification{
+ expiration := time.Now().Unix()
+ req := &PushNotification{
ApnsID: test,
Topic: test,
Expiration: &expiration,
@@ -82,7 +83,7 @@ func TestIOSNotificationStructure(t *testing.T) {
URLArgs: []string{"a", "b"},
}
- notification := GetIOSNotification(req)
+ notification, _ := GetIOSNotification(req)
dump, _ := json.Marshal(notification.Payload)
data := []byte(string(dump))
@@ -98,8 +99,8 @@ func TestIOSNotificationStructure(t *testing.T) {
soundVolume, _ := jsonparser.GetFloat(data, "aps", "sound", "volume")
contentAvailable, _ := jsonparser.GetInt(data, "aps", "content-available")
category, _ := jsonparser.GetString(data, "aps", "category")
- key1 := dat["key1"].(interface{})
- key2 := dat["key2"].(interface{})
+ key1 := dat["key1"]
+ key2 := dat["key2"]
aps := dat["aps"].(map[string]interface{})
urlArgs := aps["url-args"].([]interface{})
@@ -126,7 +127,7 @@ func TestIOSSoundAndVolume(t *testing.T) {
test := "test"
message := "Welcome notification Server"
- req := PushNotification{
+ req := &PushNotification{
ApnsID: test,
Topic: test,
Priority: "normal",
@@ -138,7 +139,7 @@ func TestIOSSoundAndVolume(t *testing.T) {
},
}
- notification := GetIOSNotification(req)
+ notification, _ := GetIOSNotification(req)
dump, _ := json.Marshal(notification.Payload)
data := []byte(string(dump))
@@ -162,7 +163,7 @@ func TestIOSSoundAndVolume(t *testing.T) {
req.SoundName = "foobar"
req.SoundVolume = 5.5
- notification = GetIOSNotification(req)
+ notification, _ = GetIOSNotification(req)
dump, _ = json.Marshal(notification.Payload)
data = []byte(string(dump))
@@ -177,7 +178,7 @@ func TestIOSSoundAndVolume(t *testing.T) {
assert.Equal(t, int64(1), soundCritical)
assert.Equal(t, "foobar", soundName)
- req = PushNotification{
+ req = &PushNotification{
ApnsID: test,
Topic: test,
Priority: "normal",
@@ -189,7 +190,7 @@ func TestIOSSoundAndVolume(t *testing.T) {
},
}
- notification = GetIOSNotification(req)
+ notification, _ = GetIOSNotification(req)
dump, _ = json.Marshal(notification.Payload)
data = []byte(string(dump))
@@ -204,7 +205,7 @@ func TestIOSSoundAndVolume(t *testing.T) {
assert.Equal(t, int64(3), soundCritical)
assert.Equal(t, "test", soundName)
- req = PushNotification{
+ req = &PushNotification{
ApnsID: test,
Topic: test,
Priority: "normal",
@@ -212,7 +213,7 @@ func TestIOSSoundAndVolume(t *testing.T) {
Sound: "default",
}
- notification = GetIOSNotification(req)
+ notification, _ = GetIOSNotification(req)
dump, _ = json.Marshal(notification.Payload)
data = []byte(string(dump))
@@ -229,7 +230,7 @@ func TestIOSSummaryArg(t *testing.T) {
test := "test"
message := "Welcome notification Server"
- req := PushNotification{
+ req := &PushNotification{
ApnsID: test,
Topic: test,
Priority: "normal",
@@ -240,7 +241,7 @@ func TestIOSSummaryArg(t *testing.T) {
},
}
- notification := GetIOSNotification(req)
+ notification, _ := GetIOSNotification(req)
dump, _ := json.Marshal(notification.Payload)
data := []byte(string(dump))
@@ -263,7 +264,7 @@ func TestSendZeroValueForBadgeKey(t *testing.T) {
test := "test"
message := "Welcome notification Server"
- req := PushNotification{
+ req := &PushNotification{
ApnsID: test,
Topic: test,
Priority: "normal",
@@ -274,7 +275,7 @@ func TestSendZeroValueForBadgeKey(t *testing.T) {
ThreadID: test,
}
- notification := GetIOSNotification(req)
+ notification, _ := GetIOSNotification(req)
dump, _ := json.Marshal(notification.Payload)
data := []byte(string(dump))
@@ -309,7 +310,7 @@ func TestSendZeroValueForBadgeKey(t *testing.T) {
expectBadge := 10
req.Badge = &expectBadge
- notification = GetIOSNotification(req)
+ notification, _ = GetIOSNotification(req)
dump, _ = json.Marshal(notification.Payload)
data = []byte(string(dump))
@@ -336,7 +337,7 @@ func TestCheckSilentNotification(t *testing.T) {
var dat map[string]interface{}
test := "test"
- req := PushNotification{
+ req := &PushNotification{
ApnsID: test,
Topic: test,
CollapseID: test,
@@ -344,7 +345,7 @@ func TestCheckSilentNotification(t *testing.T) {
ContentAvailable: true,
}
- notification := GetIOSNotification(req)
+ notification, _ := GetIOSNotification(req)
dump, _ := json.Marshal(notification.Payload)
data := []byte(string(dump))
@@ -383,7 +384,7 @@ func TestAlertStringExample2ForIos(t *testing.T) {
title := "Game Request"
body := "Bob wants to play poker"
actionLocKey := "PLAY"
- req := PushNotification{
+ req := &PushNotification{
ApnsID: test,
Topic: test,
Priority: "normal",
@@ -394,7 +395,7 @@ func TestAlertStringExample2ForIos(t *testing.T) {
},
}
- notification := GetIOSNotification(req)
+ notification, _ := GetIOSNotification(req)
dump, _ := json.Marshal(notification.Payload)
data := []byte(string(dump))
@@ -426,7 +427,7 @@ func TestAlertStringExample3ForIos(t *testing.T) {
test := "test"
badge := 9
sound := "bingbong.aiff"
- req := PushNotification{
+ req := &PushNotification{
ApnsID: test,
Topic: test,
Priority: "normal",
@@ -436,7 +437,7 @@ func TestAlertStringExample3ForIos(t *testing.T) {
Sound: sound,
}
- notification := GetIOSNotification(req)
+ notification, _ := GetIOSNotification(req)
dump, _ := json.Marshal(notification.Payload)
data := []byte(string(dump))
@@ -457,7 +458,7 @@ func TestMessageAndTitle(t *testing.T) {
test := "test"
message := "Welcome notification Server"
title := "Welcome notification Server title"
- req := PushNotification{
+ req := &PushNotification{
ApnsID: test,
Topic: test,
Priority: "normal",
@@ -466,7 +467,7 @@ func TestMessageAndTitle(t *testing.T) {
ContentAvailable: true,
}
- notification := GetIOSNotification(req)
+ notification, _ := GetIOSNotification(req)
dump, _ := json.Marshal(notification.Payload)
data := []byte(string(dump))
@@ -490,7 +491,7 @@ func TestMessageAndTitle(t *testing.T) {
messageOverride := "Welcome notification Server overridden"
req.Alert.Body = messageOverride
- notification = GetIOSNotification(req)
+ notification, _ = GetIOSNotification(req)
dump, _ = json.Marshal(notification.Payload)
data = []byte(string(dump))
@@ -511,7 +512,7 @@ func TestIOSAlertNotificationStructure(t *testing.T) {
var dat map[string]interface{}
test := "test"
- req := PushNotification{
+ req := &PushNotification{
Message: "Welcome",
Title: test,
Alert: Alert{
@@ -527,7 +528,7 @@ func TestIOSAlertNotificationStructure(t *testing.T) {
},
}
- notification := GetIOSNotification(req)
+ notification, _ := GetIOSNotification(req)
dump, _ := json.Marshal(notification.Payload)
data := []byte(string(dump))
@@ -564,166 +565,130 @@ func TestIOSAlertNotificationStructure(t *testing.T) {
assert.Contains(t, locArgs, "b")
}
-func TestDisabledIosNotifications(t *testing.T) {
- ctx := context.Background()
- PushConf, _ = config.LoadConf("")
-
- PushConf.Ios.Enabled = false
- PushConf.Ios.KeyPath = "../certificate/certificate-valid.pem"
- err := InitAPNSClient()
- assert.Nil(t, err)
-
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
-
- androidToken := os.Getenv("ANDROID_TEST_TOKEN")
-
- req := RequestPush{
- Notifications: []PushNotification{
- // ios
- {
- Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
- Platform: PlatFormIos,
- Message: "Welcome",
- },
- // android
- {
- Tokens: []string{androidToken, androidToken + "_"},
- Platform: PlatFormAndroid,
- Message: "Welcome",
- },
- },
- }
-
- count, logs := queueNotification(ctx, req)
- assert.Equal(t, 2, count)
- assert.Equal(t, 0, len(logs))
-}
-
func TestWrongIosCertificateExt(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "test"
- err := InitAPNSClient()
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "test"
+ err := InitAPNSClient(cfg)
assert.Error(t, err)
assert.Equal(t, "wrong certificate key extension", err.Error())
- PushConf.Ios.KeyPath = ""
- PushConf.Ios.KeyBase64 = "abcd"
- PushConf.Ios.KeyType = "abcd"
- err = InitAPNSClient()
+ cfg.Ios.KeyPath = ""
+ cfg.Ios.KeyBase64 = "abcd"
+ cfg.Ios.KeyType = "abcd"
+ err = InitAPNSClient(cfg)
assert.Error(t, err)
assert.Equal(t, "wrong certificate key type", err.Error())
}
func TestAPNSClientDevHost(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "../certificate/certificate-valid.p12"
- err := InitAPNSClient()
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "../certificate/certificate-valid.p12"
+ err := InitAPNSClient(cfg)
assert.Nil(t, err)
assert.Equal(t, apns2.HostDevelopment, ApnsClient.Host)
- PushConf.Ios.KeyPath = ""
- PushConf.Ios.KeyBase64 = certificateValidP12
- PushConf.Ios.KeyType = "p12"
- err = InitAPNSClient()
+ cfg.Ios.KeyPath = ""
+ cfg.Ios.KeyBase64 = certificateValidP12
+ cfg.Ios.KeyType = "p12"
+ err = InitAPNSClient(cfg)
assert.Nil(t, err)
assert.Equal(t, apns2.HostDevelopment, ApnsClient.Host)
}
func TestAPNSClientProdHost(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Ios.Enabled = true
- PushConf.Ios.Production = true
- PushConf.Ios.KeyPath = "../certificate/certificate-valid.pem"
- err := InitAPNSClient()
+ cfg.Ios.Enabled = true
+ cfg.Ios.Production = true
+ cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
+ err := InitAPNSClient(cfg)
assert.Nil(t, err)
assert.Equal(t, apns2.HostProduction, ApnsClient.Host)
- PushConf.Ios.KeyPath = ""
- PushConf.Ios.KeyBase64 = certificateValidPEM
- PushConf.Ios.KeyType = "pem"
- err = InitAPNSClient()
+ cfg.Ios.KeyPath = ""
+ cfg.Ios.KeyBase64 = certificateValidPEM
+ cfg.Ios.KeyType = "pem"
+ err = InitAPNSClient(cfg)
assert.Nil(t, err)
assert.Equal(t, apns2.HostProduction, ApnsClient.Host)
}
func TestAPNSClientInvaildToken(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "../certificate/authkey-invalid.p8"
- err := InitAPNSClient()
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "../certificate/authkey-invalid.p8"
+ err := InitAPNSClient(cfg)
assert.Error(t, err)
- PushConf.Ios.KeyPath = ""
- PushConf.Ios.KeyBase64 = authkeyInvalidP8
- PushConf.Ios.KeyType = "p8"
- err = InitAPNSClient()
+ cfg.Ios.KeyPath = ""
+ cfg.Ios.KeyBase64 = authkeyInvalidP8
+ cfg.Ios.KeyType = "p8"
+ err = InitAPNSClient(cfg)
assert.Error(t, err)
// empty key-id or team-id
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "../certificate/authkey-valid.p8"
- err = InitAPNSClient()
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "../certificate/authkey-valid.p8"
+ err = InitAPNSClient(cfg)
assert.Error(t, err)
- PushConf.Ios.KeyID = "key-id"
- PushConf.Ios.TeamID = ""
- err = InitAPNSClient()
+ cfg.Ios.KeyID = "key-id"
+ cfg.Ios.TeamID = ""
+ err = InitAPNSClient(cfg)
assert.Error(t, err)
- PushConf.Ios.KeyID = ""
- PushConf.Ios.TeamID = "team-id"
- err = InitAPNSClient()
+ cfg.Ios.KeyID = ""
+ cfg.Ios.TeamID = "team-id"
+ err = InitAPNSClient(cfg)
assert.Error(t, err)
}
func TestAPNSClientVaildToken(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "../certificate/authkey-valid.p8"
- PushConf.Ios.KeyID = "key-id"
- PushConf.Ios.TeamID = "team-id"
- err := InitAPNSClient()
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "../certificate/authkey-valid.p8"
+ cfg.Ios.KeyID = "key-id"
+ cfg.Ios.TeamID = "team-id"
+ err := InitAPNSClient(cfg)
assert.NoError(t, err)
assert.Equal(t, apns2.HostDevelopment, ApnsClient.Host)
- PushConf.Ios.Production = true
- err = InitAPNSClient()
+ cfg.Ios.Production = true
+ err = InitAPNSClient(cfg)
assert.NoError(t, err)
assert.Equal(t, apns2.HostProduction, ApnsClient.Host)
// test base64
- PushConf.Ios.Production = false
- PushConf.Ios.KeyPath = ""
- PushConf.Ios.KeyBase64 = authkeyValidP8
- PushConf.Ios.KeyType = "p8"
- err = InitAPNSClient()
+ cfg.Ios.Production = false
+ cfg.Ios.KeyPath = ""
+ cfg.Ios.KeyBase64 = authkeyValidP8
+ cfg.Ios.KeyType = "p8"
+ err = InitAPNSClient(cfg)
assert.NoError(t, err)
assert.Equal(t, apns2.HostDevelopment, ApnsClient.Host)
- PushConf.Ios.Production = true
- err = InitAPNSClient()
+ cfg.Ios.Production = true
+ err = InitAPNSClient(cfg)
assert.NoError(t, err)
assert.Equal(t, apns2.HostProduction, ApnsClient.Host)
}
func TestAPNSClientUseProxy(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "../certificate/certificate-valid.p12"
- PushConf.Core.HTTPProxy = "http://127.0.0.1:8080"
- _ = SetProxy(PushConf.Core.HTTPProxy)
- err := InitAPNSClient()
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "../certificate/certificate-valid.p12"
+ cfg.Core.HTTPProxy = "http://127.0.0.1:8080"
+ _ = SetProxy(cfg.Core.HTTPProxy)
+ err := InitAPNSClient(cfg)
assert.Nil(t, err)
assert.Equal(t, apns2.HostDevelopment, ApnsClient.Host)
@@ -731,13 +696,13 @@ func TestAPNSClientUseProxy(t *testing.T) {
actualProxyURL, err := ApnsClient.HTTPClient.Transport.(*http.Transport).Proxy(req)
assert.Nil(t, err)
- expectedProxyURL, _ := url.ParseRequestURI(PushConf.Core.HTTPProxy)
+ expectedProxyURL, _ := url.ParseRequestURI(cfg.Core.HTTPProxy)
assert.Equal(t, expectedProxyURL, actualProxyURL)
- PushConf.Ios.KeyPath = "../certificate/authkey-valid.p8"
- PushConf.Ios.TeamID = "example.team"
- PushConf.Ios.KeyID = "example.key"
- err = InitAPNSClient()
+ cfg.Ios.KeyPath = "../certificate/authkey-valid.p8"
+ cfg.Ios.TeamID = "example.team"
+ cfg.Ios.KeyID = "example.key"
+ err = InitAPNSClient(cfg)
assert.Nil(t, err)
assert.Equal(t, apns2.HostDevelopment, ApnsClient.Host)
assert.NotNil(t, ApnsClient.Token)
@@ -746,61 +711,64 @@ func TestAPNSClientUseProxy(t *testing.T) {
actualProxyURL, err = ApnsClient.HTTPClient.Transport.(*http.Transport).Proxy(req)
assert.Nil(t, err)
- expectedProxyURL, _ = url.ParseRequestURI(PushConf.Core.HTTPProxy)
+ expectedProxyURL, _ = url.ParseRequestURI(cfg.Core.HTTPProxy)
assert.Equal(t, expectedProxyURL, actualProxyURL)
http.DefaultTransport.(*http.Transport).Proxy = nil
}
func TestPushToIOS(t *testing.T) {
- PushConf, _ = config.LoadConf("")
- MaxConcurrentIOSPushes = make(chan struct{}, PushConf.Ios.MaxConcurrentPushes)
+ cfg, _ := config.LoadConf()
+ MaxConcurrentIOSPushes = make(chan struct{}, cfg.Ios.MaxConcurrentPushes)
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "../certificate/certificate-valid.pem"
- err := InitAPNSClient()
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
+ err := InitAPNSClient(cfg)
assert.Nil(t, err)
- err = InitAppStatus()
+ err = status.InitAppStatus(cfg)
assert.Nil(t, err)
- req := PushNotification{
+ req := &PushNotification{
+ // nolint
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7", "11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef1"},
Platform: 1,
Message: "Welcome",
}
// send fail
- PushToIOS(req)
+ resp, err := PushToIOS(req, cfg)
+ assert.Nil(t, err)
+ assert.Len(t, resp.Logs, 2)
}
func TestApnsHostFromRequest(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Ios.Enabled = true
- PushConf.Ios.KeyPath = "../certificate/certificate-valid.pem"
- err := InitAPNSClient()
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
+ err := InitAPNSClient(cfg)
assert.Nil(t, err)
- err = InitAppStatus()
+ err = status.InitAppStatus(cfg)
assert.Nil(t, err)
- req := PushNotification{
+ req := &PushNotification{
Production: true,
}
- client := getApnsClient(req)
+ client := getApnsClient(cfg, req)
assert.Equal(t, apns2.HostProduction, client.Host)
- req = PushNotification{
+ req = &PushNotification{
Development: true,
}
- client = getApnsClient(req)
+ client = getApnsClient(cfg, req)
assert.Equal(t, apns2.HostDevelopment, client.Host)
- req = PushNotification{}
- PushConf.Ios.Production = true
- client = getApnsClient(req)
+ req = &PushNotification{}
+ cfg.Ios.Production = true
+ client = getApnsClient(cfg, req)
assert.Equal(t, apns2.HostProduction, client.Host)
- PushConf.Ios.Production = false
- client = getApnsClient(req)
+ cfg.Ios.Production = false
+ client = getApnsClient(cfg, req)
assert.Equal(t, apns2.HostDevelopment, client.Host)
}
diff --git a/gorush/notification_fcm.go b/notify/notification_fcm.go
similarity index 53%
rename from gorush/notification_fcm.go
rename to notify/notification_fcm.go
index de1129c46..2c906d9a7 100644
--- a/gorush/notification_fcm.go
+++ b/notify/notification_fcm.go
@@ -1,27 +1,32 @@
-package gorush
+package notify
import (
+ "encoding/json"
"errors"
"fmt"
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/core"
+ "github.com/appleboy/gorush/logx"
+ "github.com/appleboy/gorush/status"
+
"github.com/appleboy/go-fcm"
- "github.com/sirupsen/logrus"
)
// InitFCMClient use for initialize FCM Client.
-func InitFCMClient(key string) (*fcm.Client, error) {
+func InitFCMClient(cfg *config.ConfYaml, key string) (*fcm.Client, error) {
var err error
- if key == "" {
+ if key == "" && cfg.Android.APIKey == "" {
return nil, errors.New("Missing Android API Key")
}
- if key != PushConf.Android.APIKey {
+ if key != "" && key != cfg.Android.APIKey {
return fcm.NewClient(key)
}
if FCMClient == nil {
- FCMClient, err = fcm.NewClient(key)
+ FCMClient, err = fcm.NewClient(cfg.Android.APIKey)
return FCMClient, err
}
@@ -31,7 +36,7 @@ func InitFCMClient(key string) (*fcm.Client, error) {
// GetAndroidNotification use for define Android notification.
// HTTP Connection Server Reference for Android
// https://firebase.google.com/docs/cloud-messaging/http-server-ref
-func GetAndroidNotification(req PushNotification) *fcm.Message {
+func GetAndroidNotification(req PushNotification) (*fcm.Message, error) {
notification := &fcm.Message{
To: req.To,
Condition: req.Condition,
@@ -97,17 +102,25 @@ func GetAndroidNotification(req PushNotification) *fcm.Message {
notification.Apns = req.Apns
}
- return notification
+ jsonMarshall, err := json.Marshal(notification)
+ if err != nil {
+ LogError.Error("Failed to marshal the default message! Error is " + err.Error())
+ return nil, err
+ }
+
+ LogAccess.Debugf("Default message is %s", string(jsonMarshall))
+
+ return notification, nil
}
// PushToAndroid provide send notification to Android server.
-func PushToAndroid(req PushNotification) {
- LogAccess.Debug("Start push notification for Android")
+func PushToAndroid(req *PushNotification, cfg *config.ConfYaml) (resp *ResponsePush, err error) {
+ logx.LogAccess.Debug("Start push notification for Android")
var (
client *fcm.Client
retryCount = 0
- maxRetry = PushConf.Android.MaxRetry
+ maxRetry = cfg.Android.MaxRetry
)
if req.Retry > 0 && req.Retry < maxRetry {
@@ -115,68 +128,54 @@ func PushToAndroid(req PushNotification) {
}
// check message
- err := CheckMessage(req)
+ err = CheckMessage(req)
if err != nil {
- LogError.Error("request error: " + err.Error())
+ logx.LogError.Error("request error: " + err.Error())
return
}
+ resp = &ResponsePush{}
+
Retry:
- notification := GetAndroidNotification(req)
+ notification, _ := GetAndroidNotification(req)
if req.APIKey != "" {
- client, err = InitFCMClient(req.APIKey)
+ client, err = InitFCMClient(cfg, req.APIKey)
} else {
- client, err = InitFCMClient(PushConf.Android.APIKey)
+ client, err = InitFCMClient(cfg, cfg.Android.APIKey)
}
if err != nil {
// FCM server error
- LogError.Error("FCM server error: " + err.Error())
+ logx.LogError.Error("FCM server error: " + err.Error())
return
}
res, err := client.Send(notification)
if err != nil {
// Send Message error
- LogError.Error("FCM server send message error: " + err.Error())
+ logx.LogError.Error("FCM server send message error: " + err.Error())
if req.IsTopic() {
- if PushConf.Core.Sync {
- req.AddLog(getLogPushEntry(FailedPush, req.To, req, err))
- } else if PushConf.Core.FeedbackURL != "" {
- go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) {
- err := DispatchFeedback(log, url, timeout)
- if err != nil {
- logger.Error(err)
- }
- }(LogError, getLogPushEntry(FailedPush, req.To, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
- }
- StatStorage.AddAndroidError(1)
+ errLog := logPush(cfg, core.FailedPush, req.To, req, err)
+ resp.Logs = append(resp.Logs, errLog)
+ status.StatStorage.AddAndroidError(1)
} else {
for _, token := range req.Tokens {
- if PushConf.Core.Sync {
- req.AddLog(getLogPushEntry(FailedPush, token, req, err))
- } else if PushConf.Core.FeedbackURL != "" {
- go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) {
- err := DispatchFeedback(log, url, timeout)
- if err != nil {
- logger.Error(err)
- }
- }(LogError, getLogPushEntry(FailedPush, token, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
- }
+ errLog := logPush(cfg, core.FailedPush, token, req, err)
+ resp.Logs = append(resp.Logs, errLog)
}
- StatStorage.AddAndroidError(int64(len(req.Tokens)))
+ status.StatStorage.AddAndroidError(int64(len(req.Tokens)))
}
return
}
if !req.IsTopic() {
- LogAccess.Debug(fmt.Sprintf("Android Success count: %d, Failure count: %d", res.Success, res.Failure))
+ logx.LogAccess.Debug(fmt.Sprintf("Android Success count: %d, Failure count: %d", res.Success, res.Failure))
}
- StatStorage.AddAndroidSuccess(int64(res.Success))
- StatStorage.AddAndroidError(int64(res.Failure))
+ status.StatStorage.AddAndroidSuccess(int64(res.Success))
+ status.StatStorage.AddAndroidError(int64(res.Failure))
var newTokens []string
// result from Send messages to specific devices
@@ -195,21 +194,12 @@ Retry:
newTokens = append(newTokens, to)
}
- LogPush(FailedPush, to, req, result.Error)
- if PushConf.Core.Sync {
- req.AddLog(getLogPushEntry(FailedPush, to, req, result.Error))
- } else if PushConf.Core.FeedbackURL != "" {
- go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) {
- err := DispatchFeedback(log, url, timeout)
- if err != nil {
- logger.Error(err)
- }
- }(LogError, getLogPushEntry(FailedPush, to, req, result.Error), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
- }
+ errLog := logPush(cfg, core.FailedPush, to, req, result.Error)
+ resp.Logs = append(resp.Logs, errLog)
continue
}
- LogPush(SucceededPush, to, req, nil)
+ logPush(cfg, core.SucceededPush, to, req, nil)
}
// result from Send messages to topics
@@ -220,16 +210,14 @@ Retry:
} else {
to = req.Condition
}
- LogAccess.Debug("Send Topic Message: ", to)
+ logx.LogAccess.Debug("Send Topic Message: ", to)
// Success
if res.MessageID != 0 {
- LogPush(SucceededPush, to, req, nil)
+ logPush(cfg, core.SucceededPush, to, req, nil)
} else {
// failure
- LogPush(FailedPush, to, req, res.Error)
- if PushConf.Core.Sync {
- req.AddLog(getLogPushEntry(FailedPush, to, req, res.Error))
- }
+ errLog := logPush(cfg, core.FailedPush, to, req, res.Error)
+ resp.Logs = append(resp.Logs, errLog)
}
}
@@ -237,10 +225,9 @@ Retry:
if len(res.FailedRegistrationIDs) > 0 {
newTokens = append(newTokens, res.FailedRegistrationIDs...)
- LogPush(FailedPush, notification.To, req, errors.New("device group: partial success or all fails"))
- if PushConf.Core.Sync {
- req.AddLog(getLogPushEntry(FailedPush, notification.To, req, errors.New("device group: partial success or all fails")))
- }
+ // nolint
+ errLog := logPush(cfg, core.FailedPush, notification.To, req, errors.New("device group: partial success or all fails"))
+ resp.Logs = append(resp.Logs, errLog)
}
if len(newTokens) > 0 && retryCount < maxRetry {
@@ -250,4 +237,19 @@ Retry:
req.Tokens = newTokens
goto Retry
}
+
+ return resp, nil
+}
+
+func logPush(cfg *config.ConfYaml, status, token string, req *PushNotification, err error) logx.LogPushEntry {
+ return logx.LogPush(&logx.InputLog{
+ ID: req.ID,
+ Status: status,
+ Token: token,
+ Message: req.Message,
+ Platform: req.Platform,
+ Error: err,
+ HideToken: cfg.Log.HideToken,
+ Format: cfg.Log.Format,
+ })
}
diff --git a/gorush/notification_fcm_test.go b/notify/notification_fcm_test.go
similarity index 66%
rename from gorush/notification_fcm_test.go
rename to notify/notification_fcm_test.go
index b9106e85f..8623bb051 100644
--- a/gorush/notification_fcm_test.go
+++ b/notify/notification_fcm_test.go
@@ -1,47 +1,32 @@
-package gorush
+package notify
import (
- "context"
- "log"
"os"
- "sync"
"testing"
- "github.com/appleboy/go-fcm"
"github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/core"
+
+ "github.com/appleboy/go-fcm"
"github.com/stretchr/testify/assert"
)
-func init() {
- PushConf, _ = config.LoadConf("")
- if err := InitLog(); err != nil {
- log.Fatal(err)
- }
-
- ctx := context.Background()
- wg := &sync.WaitGroup{}
- wg.Add(int(PushConf.Core.WorkerNum))
- InitWorkers(ctx, wg, PushConf.Core.WorkerNum, PushConf.Core.QueueNum)
-
- if err := InitAppStatus(); err != nil {
- log.Fatal(err)
- }
-}
-
func TestMissingAndroidAPIKey(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = ""
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = ""
- err := CheckPushConf()
+ err := CheckPushConf(cfg)
assert.Error(t, err)
assert.Equal(t, "Missing Android API Key", err.Error())
}
func TestMissingKeyForInitFCMClient(t *testing.T) {
- client, err := InitFCMClient("")
+ cfg, _ := config.LoadConf()
+ cfg.Android.APIKey = ""
+ client, err := InitFCMClient(cfg, "")
assert.Nil(t, client)
assert.Error(t, err)
@@ -49,88 +34,92 @@ func TestMissingKeyForInitFCMClient(t *testing.T) {
}
func TestPushToAndroidWrongToken(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
- req := PushNotification{
+ req := &PushNotification{
Tokens: []string{"aaaaaa", "bbbbb"},
- Platform: PlatFormAndroid,
+ Platform: core.PlatFormAndroid,
Message: "Welcome",
}
// Android Success count: 0, Failure count: 2
- PushToAndroid(req)
+ resp, err := PushToAndroid(req, cfg)
+ assert.Nil(t, err)
+ assert.Len(t, resp.Logs, 2)
}
func TestPushToAndroidRightTokenForJSONLog(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
// log for json
- PushConf.Log.Format = "json"
+ cfg.Log.Format = "json"
androidToken := os.Getenv("ANDROID_TEST_TOKEN")
- req := PushNotification{
+ req := &PushNotification{
Tokens: []string{androidToken},
- Platform: PlatFormAndroid,
+ Platform: core.PlatFormAndroid,
Message: "Welcome",
}
- PushToAndroid(req)
+ resp, err := PushToAndroid(req, cfg)
+ assert.Nil(t, err)
+ assert.Len(t, resp.Logs, 0)
}
func TestPushToAndroidRightTokenForStringLog(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
androidToken := os.Getenv("ANDROID_TEST_TOKEN")
- req := PushNotification{
+ req := &PushNotification{
Tokens: []string{androidToken},
- Platform: PlatFormAndroid,
+ Platform: core.PlatFormAndroid,
Message: "Welcome",
}
- PushToAndroid(req)
+ resp, err := PushToAndroid(req, cfg)
+ assert.Nil(t, err)
+ assert.Len(t, resp.Logs, 0)
}
func TestOverwriteAndroidAPIKey(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Core.Sync = true
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+ cfg.Core.Sync = true
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
androidToken := os.Getenv("ANDROID_TEST_TOKEN")
- req := PushNotification{
+ req := &PushNotification{
Tokens: []string{androidToken, "bbbbb"},
- Platform: PlatFormAndroid,
+ Platform: core.PlatFormAndroid,
Message: "Welcome",
// overwrite android api key
APIKey: "1234",
-
- log: &[]LogPushEntry{},
}
// FCM server error: 401 error: 401 Unauthorized (Wrong API Key)
- PushToAndroid(req)
+ resp, err := PushToAndroid(req, cfg)
- assert.Len(t, *req.log, 2)
+ assert.Error(t, err)
+ assert.Len(t, resp.Logs, 2)
}
func TestFCMMessage(t *testing.T) {
- var req PushNotification
var err error
// the message must specify at least one registration ID
- req = PushNotification{
+ req := &PushNotification{
Message: "Test",
Tokens: []string{},
}
@@ -139,7 +128,7 @@ func TestFCMMessage(t *testing.T) {
assert.Error(t, err)
// the token must not be empty
- req = PushNotification{
+ req = &PushNotification{
Message: "Test",
Tokens: []string{""},
}
@@ -148,9 +137,9 @@ func TestFCMMessage(t *testing.T) {
assert.Error(t, err)
// ignore check token length if send topic message
- req = PushNotification{
+ req = &PushNotification{
Message: "Test",
- Platform: PlatFormAndroid,
+ Platform: core.PlatFormAndroid,
To: "/topics/foo-bar",
}
@@ -158,9 +147,9 @@ func TestFCMMessage(t *testing.T) {
assert.NoError(t, err)
// "condition": "'dogs' in topics || 'cats' in topics",
- req = PushNotification{
+ req = &PushNotification{
Message: "Test",
- Platform: PlatFormAndroid,
+ Platform: core.PlatFormAndroid,
Condition: "'dogs' in topics || 'cats' in topics",
}
@@ -168,9 +157,9 @@ func TestFCMMessage(t *testing.T) {
assert.NoError(t, err)
// the message may specify at most 1000 registration IDs
- req = PushNotification{
+ req = &PushNotification{
Message: "Test",
- Platform: PlatFormAndroid,
+ Platform: core.PlatFormAndroid,
Tokens: make([]string, 1001),
}
@@ -180,9 +169,9 @@ func TestFCMMessage(t *testing.T) {
// the message's TimeToLive field must be an integer
// between 0 and 2419200 (4 weeks)
timeToLive := uint(2419201)
- req = PushNotification{
+ req = &PushNotification{
Message: "Test",
- Platform: PlatFormAndroid,
+ Platform: core.PlatFormAndroid,
Tokens: []string{"XXXXXXXXX"},
TimeToLive: &timeToLive,
}
@@ -192,9 +181,9 @@ func TestFCMMessage(t *testing.T) {
// Pass
timeToLive = uint(86400)
- req = PushNotification{
+ req = &PushNotification{
Message: "Test",
- Platform: PlatFormAndroid,
+ Platform: core.PlatFormAndroid,
Tokens: []string{"XXXXXXXXX"},
TimeToLive: &timeToLive,
}
@@ -204,26 +193,29 @@ func TestFCMMessage(t *testing.T) {
}
func TestCheckAndroidMessage(t *testing.T) {
- PushConf, _ = config.LoadConf("")
+ cfg, _ := config.LoadConf()
- PushConf.Android.Enabled = true
- PushConf.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
timeToLive := uint(2419201)
- req := PushNotification{
+ req := &PushNotification{
Tokens: []string{"aaaaaa", "bbbbb"},
- Platform: PlatFormAndroid,
+ Platform: core.PlatFormAndroid,
Message: "Welcome",
TimeToLive: &timeToLive,
}
- PushToAndroid(req)
+ // the message's TimeToLive field must be an integer between 0 and 2419200 (4 weeks)
+ resp, err := PushToAndroid(req, cfg)
+ assert.NotNil(t, err)
+ assert.Nil(t, resp)
}
func TestAndroidNotificationStructure(t *testing.T) {
test := "test"
timeToLive := uint(100)
- req := PushNotification{
+ req := &PushNotification{
Tokens: []string{"a", "b"},
Message: "Welcome",
To: test,
@@ -247,7 +239,7 @@ func TestAndroidNotificationStructure(t *testing.T) {
},
}
- notification := GetAndroidNotification(req)
+ notification, _ := GetAndroidNotification(req)
assert.Equal(t, test, notification.To)
assert.Equal(t, "high", notification.Priority)
@@ -266,14 +258,14 @@ func TestAndroidNotificationStructure(t *testing.T) {
assert.Equal(t, 2, notification.Data["b"])
// test empty body
- req = PushNotification{
+ req = &PushNotification{
Tokens: []string{"a", "b"},
To: test,
Notification: &fcm.Notification{
Body: "",
},
}
- notification = GetAndroidNotification(req)
+ notification, _ = GetAndroidNotification(req)
assert.Equal(t, test, notification.To)
assert.Equal(t, "", notification.Notification.Body)
diff --git a/gorush/notification_hms.go b/notify/notification_hms.go
similarity index 67%
rename from gorush/notification_hms.go
rename to notify/notification_hms.go
index 6d373fe36..12cf80afc 100644
--- a/gorush/notification_hms.go
+++ b/notify/notification_hms.go
@@ -1,26 +1,30 @@
-package gorush
+package notify
import (
"context"
- "encoding/json"
"errors"
"sync"
- "github.com/msalihkarakasli/go-hms-push/push/config"
- "github.com/msalihkarakasli/go-hms-push/push/core"
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/core"
+ "github.com/appleboy/gorush/logx"
+ "github.com/appleboy/gorush/status"
+
+ c "github.com/msalihkarakasli/go-hms-push/push/config"
+ client "github.com/msalihkarakasli/go-hms-push/push/core"
"github.com/msalihkarakasli/go-hms-push/push/model"
)
var (
pushError error
- pushClient *core.HMSClient
+ pushClient *client.HMSClient
once sync.Once
)
// GetPushClient use for create HMS Push
-func GetPushClient(conf *config.Config) (*core.HMSClient, error) {
+func GetPushClient(conf *c.Config) (*client.HMSClient, error) {
once.Do(func() {
- client, err := core.NewHttpClient(conf)
+ client, err := client.NewHttpClient(conf)
if err != nil {
panic(err)
}
@@ -32,7 +36,7 @@ func GetPushClient(conf *config.Config) (*core.HMSClient, error) {
}
// InitHMSClient use for initialize HMS Client.
-func InitHMSClient(appSecret, appID string) (*core.HMSClient, error) {
+func InitHMSClient(cfg *config.ConfYaml, appSecret, appID string) (*client.HMSClient, error) {
if appSecret == "" {
return nil, errors.New("Missing Huawei App Secret")
}
@@ -41,14 +45,14 @@ func InitHMSClient(appSecret, appID string) (*core.HMSClient, error) {
return nil, errors.New("Missing Huawei App ID")
}
- conf := &config.Config{
+ conf := &c.Config{
AppId: appID,
AppSecret: appSecret,
AuthUrl: "https://oauth-login.cloud.huawei.com/oauth2/v3/token",
PushUrl: "https://push-api.cloud.huawei.com",
}
- if appSecret != PushConf.Huawei.AppSecret || appID != PushConf.Huawei.AppID {
+ if appSecret != cfg.Huawei.AppSecret || appID != cfg.Huawei.AppID {
return GetPushClient(conf)
}
@@ -62,7 +66,7 @@ func InitHMSClient(appSecret, appID string) (*core.HMSClient, error) {
// GetHuaweiNotification use for define HMS notification.
// HTTP Connection Server Reference for HMS
// https://developer.huawei.com/consumer/en/doc/development/HMS-References/push-sendapi
-func GetHuaweiNotification(req PushNotification) (*model.MessageRequest, error) {
+func GetHuaweiNotification(req *PushNotification) (*model.MessageRequest, error) {
msgRequest := model.NewNotificationMsgRequest()
msgRequest.Message.Android = model.GetDefaultAndroid()
@@ -153,22 +157,22 @@ func GetHuaweiNotification(req PushNotification) (*model.MessageRequest, error)
b, err := json.Marshal(msgRequest)
if err != nil {
- LogError.Error("Failed to marshal the default message! Error is " + err.Error())
+ logx.LogError.Error("Failed to marshal the default message! Error is " + err.Error())
return nil, err
}
- LogAccess.Debugf("Default message is %s", string(b))
+ logx.LogAccess.Debugf("Default message is %s", string(b))
return msgRequest, nil
}
// PushToHuawei provide send notification to Android server.
-func PushToHuawei(req PushNotification) bool {
- LogAccess.Debug("Start push notification for Huawei")
+func PushToHuawei(req *PushNotification, cfg *config.ConfYaml) (resp *ResponsePush, err error) {
+ logx.LogAccess.Debug("Start push notification for Huawei")
var (
- client *core.HMSClient
+ client *client.HMSClient
retryCount = 0
- maxRetry = PushConf.Huawei.MaxRetry
+ maxRetry = cfg.Huawei.MaxRetry
)
if req.Retry > 0 && req.Retry < maxRetry {
@@ -176,40 +180,44 @@ func PushToHuawei(req PushNotification) bool {
}
// check message
- err := CheckMessage(req)
+ err = CheckMessage(req)
if err != nil {
- LogError.Error("request error: " + err.Error())
- return false
+ logx.LogError.Error("request error: " + err.Error())
+ return
}
-Retry:
- isError := false
-
- notification, _ := GetHuaweiNotification(req)
-
- client, err = InitHMSClient(PushConf.Huawei.AppSecret, PushConf.Huawei.AppID)
+ client, err = InitHMSClient(cfg, cfg.Huawei.AppSecret, cfg.Huawei.AppID)
if err != nil {
// HMS server error
- LogError.Error("HMS server error: " + err.Error())
- return false
+ logx.LogError.Error("HMS server error: " + err.Error())
+ return
}
+ resp = &ResponsePush{}
+
+Retry:
+ isError := false
+
+ notification, _ := GetHuaweiNotification(req)
+
res, err := client.SendMessage(context.Background(), notification)
if err != nil {
// Send Message error
- LogError.Error("HMS server send message error: " + err.Error())
- return false
+ errLog := logPush(cfg, core.FailedPush, req.To, req, err)
+ resp.Logs = append(resp.Logs, errLog)
+ logx.LogError.Error("HMS server send message error: " + err.Error())
+ return
}
// Huawei Push Send API does not support exact results for each token
if res.Code == "80000000" {
- StatStorage.AddHuaweiSuccess(int64(1))
- LogAccess.Debug("Huwaei Send Notification is completed successfully!")
+ status.StatStorage.AddHuaweiSuccess(int64(1))
+ logx.LogAccess.Debug("Huwaei Send Notification is completed successfully!")
} else {
isError = true
- StatStorage.AddHuaweiError(int64(1))
- LogAccess.Debug("Huawei Send Notification is failed! Code: " + res.Code)
+ status.StatStorage.AddHuaweiError(int64(1))
+ logx.LogAccess.Debug("Huawei Send Notification is failed! Code: " + res.Code)
}
if isError && retryCount < maxRetry {
@@ -219,5 +227,5 @@ Retry:
goto Retry
}
- return isError
+ return resp, nil
}
diff --git a/notify/notification_hms_test.go b/notify/notification_hms_test.go
new file mode 100644
index 000000000..27e1d8490
--- /dev/null
+++ b/notify/notification_hms_test.go
@@ -0,0 +1,50 @@
+package notify
+
+import (
+ "testing"
+
+ "github.com/appleboy/gorush/config"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestMissingHuaweiAppSecret(t *testing.T) {
+ cfg, _ := config.LoadConf()
+
+ cfg.Huawei.Enabled = true
+ cfg.Huawei.AppSecret = ""
+
+ err := CheckPushConf(cfg)
+
+ assert.Error(t, err)
+ assert.Equal(t, "Missing Huawei App Secret", err.Error())
+}
+
+func TestMissingHuaweiAppID(t *testing.T) {
+ cfg, _ := config.LoadConf()
+
+ cfg.Huawei.Enabled = true
+ cfg.Huawei.AppID = ""
+
+ err := CheckPushConf(cfg)
+
+ assert.Error(t, err)
+ assert.Equal(t, "Missing Huawei App ID", err.Error())
+}
+
+func TestMissingAppSecretForInitHMSClient(t *testing.T) {
+ cfg, _ := config.LoadConf()
+ client, err := InitHMSClient(cfg, "", "APP_SECRET")
+
+ assert.Nil(t, client)
+ assert.Error(t, err)
+ assert.Equal(t, "Missing Huawei App Secret", err.Error())
+}
+
+func TestMissingAppIDForInitHMSClient(t *testing.T) {
+ cfg, _ := config.LoadConf()
+ client, err := InitHMSClient(cfg, "APP_ID", "")
+
+ assert.Nil(t, client)
+ assert.Error(t, err)
+ assert.Equal(t, "Missing Huawei App ID", err.Error())
+}
diff --git a/notify/notification_test.go b/notify/notification_test.go
new file mode 100644
index 000000000..559a5bb95
--- /dev/null
+++ b/notify/notification_test.go
@@ -0,0 +1,34 @@
+package notify
+
+import (
+ "testing"
+
+ "github.com/appleboy/gorush/config"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestCorrectConf(t *testing.T) {
+ cfg, _ := config.LoadConf()
+
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = "xxxxx"
+
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
+
+ err := CheckPushConf(cfg)
+
+ assert.NoError(t, err)
+}
+
+func TestSetProxyURL(t *testing.T) {
+ err := SetProxy("87.236.233.92:8080")
+ assert.Error(t, err)
+ assert.Equal(t, "parse \"87.236.233.92:8080\": invalid URI for request", err.Error())
+
+ err = SetProxy("a.html")
+ assert.Error(t, err)
+
+ err = SetProxy("http://87.236.233.92:8080")
+ assert.NoError(t, err)
+}
diff --git a/pipeline.libsonnet b/pipeline.libsonnet
index 2fc599750..0f8b5de7e 100644
--- a/pipeline.libsonnet
+++ b/pipeline.libsonnet
@@ -7,40 +7,12 @@
arch: 'amd64',
},
steps: [
- {
- name: 'vet',
- image: 'golang:1.16',
- pull: 'always',
- commands: [
- 'make vet',
- ],
- volumes: [
- {
- name: 'gopath',
- path: '/go',
- },
- ],
- },
{
name: 'lint',
- image: 'golang:1.16',
- pull: 'always',
- commands: [
- 'make lint',
- ],
- volumes: [
- {
- name: 'gopath',
- path: '/go',
- },
- ],
- },
- {
- name: 'misspell',
- image: 'golang:1.16',
+ image: 'golangci/golangci-lint:v1.41.1',
pull: 'always',
commands: [
- 'make misspell-check',
+ 'golangci-lint run -v',
],
volumes: [
{
@@ -118,6 +90,13 @@
name: 'redis',
image: 'redis',
},
+ {
+ name: 'nsq',
+ image: 'nsqio/nsq',
+ commands: [
+ "/nsqd",
+ ],
+ },
],
},
@@ -183,22 +162,6 @@
'./release/' + os + '/' + arch + '/' + name + ' --help',
],
},
- {
- name: 'dryrun',
- image: 'plugins/docker:' + os + '-' + arch,
- pull: 'always',
- settings: {
- daemon_off: false,
- dry_run: true,
- tags: os + '-' + arch,
- dockerfile: 'docker/Dockerfile.' + os + '.' + arch,
- repo: 'appleboy/' + name,
- cache_from: 'appleboy/' + name,
- },
- when: {
- event: [ 'pull_request' ],
- },
- },
{
name: 'publish',
image: 'plugins/docker:' + os + '-' + arch,
diff --git a/router/server.go b/router/server.go
new file mode 100644
index 000000000..7dd738e5f
--- /dev/null
+++ b/router/server.go
@@ -0,0 +1,317 @@
+package router
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "net/http"
+ "os"
+ "sync"
+
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/core"
+ "github.com/appleboy/gorush/logx"
+ "github.com/appleboy/gorush/metric"
+ "github.com/appleboy/gorush/notify"
+ "github.com/appleboy/gorush/status"
+
+ api "github.com/appleboy/gin-status-api"
+ "github.com/gin-contrib/logger"
+ "github.com/gin-gonic/gin"
+ "github.com/gin-gonic/gin/binding"
+ "github.com/golang-queue/queue"
+ "github.com/mattn/go-isatty"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+ "github.com/thoas/stats"
+ "golang.org/x/crypto/acme/autocert"
+)
+
+var doOnce sync.Once
+
+func abortWithError(c *gin.Context, code int, message string) {
+ c.AbortWithStatusJSON(code, gin.H{
+ "code": code,
+ "message": message,
+ })
+}
+
+func rootHandler(c *gin.Context) {
+ c.JSON(http.StatusOK, gin.H{
+ "text": "Welcome to notification server.",
+ })
+}
+
+func heartbeatHandler(c *gin.Context) {
+ c.AbortWithStatus(http.StatusOK)
+}
+
+func versionHandler(c *gin.Context) {
+ c.JSON(http.StatusOK, gin.H{
+ "source": "https://github.com/appleboy/gorush",
+ "version": GetVersion(),
+ })
+}
+
+func pushHandler(cfg *config.ConfYaml, q *queue.Queue) gin.HandlerFunc {
+ return func(c *gin.Context) {
+ var form notify.RequestPush
+ var msg string
+
+ if err := c.ShouldBindWith(&form, binding.JSON); err != nil {
+ msg = "Missing notifications field."
+ logx.LogAccess.Debug(err)
+ abortWithError(c, http.StatusBadRequest, msg)
+ return
+ }
+
+ if len(form.Notifications) == 0 {
+ msg = "Notifications field is empty."
+ logx.LogAccess.Debug(msg)
+ abortWithError(c, http.StatusBadRequest, msg)
+ return
+ }
+
+ if int64(len(form.Notifications)) > cfg.Core.MaxNotification {
+ msg = fmt.Sprintf("Number of notifications(%d) over limit(%d)", len(form.Notifications), cfg.Core.MaxNotification)
+ logx.LogAccess.Debug(msg)
+ abortWithError(c, http.StatusBadRequest, msg)
+ return
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ // Deprecated: the CloseNotifier interface predates Go's context package.
+ // New code should use Request.Context instead.
+ // Change to context package
+ <-c.Request.Context().Done()
+ // Don't send notification after client timeout or disconnected.
+ // See the following issue for detail information.
+ // https://github.com/appleboy/gorush/issues/422
+ if cfg.Core.Sync {
+ cancel()
+ }
+ }()
+
+ counts, logs := handleNotification(ctx, cfg, form, q)
+
+ c.JSON(http.StatusOK, gin.H{
+ "success": "ok",
+ "counts": counts,
+ "logs": logs,
+ })
+ }
+}
+
+func configHandler(cfg *config.ConfYaml) gin.HandlerFunc {
+ return func(c *gin.Context) {
+ c.YAML(http.StatusCreated, cfg)
+ }
+}
+
+func metricsHandler(c *gin.Context) {
+ promhttp.Handler().ServeHTTP(c.Writer, c.Request)
+}
+
+func appStatusHandler(q *queue.Queue) gin.HandlerFunc {
+ return func(c *gin.Context) {
+ result := status.App{}
+
+ result.Version = GetVersion()
+ result.QueueMax = q.Capacity()
+ result.QueueUsage = q.Usage()
+ result.TotalCount = status.StatStorage.GetTotalCount()
+ result.Ios.PushSuccess = status.StatStorage.GetIosSuccess()
+ result.Ios.PushError = status.StatStorage.GetIosError()
+ result.Android.PushSuccess = status.StatStorage.GetAndroidSuccess()
+ result.Android.PushError = status.StatStorage.GetAndroidError()
+ result.Huawei.PushSuccess = status.StatStorage.GetHuaweiSuccess()
+ result.Huawei.PushError = status.StatStorage.GetHuaweiError()
+
+ c.JSON(http.StatusOK, result)
+ }
+}
+
+func sysStatsHandler() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ c.JSON(http.StatusOK, status.Stats.Data())
+ }
+}
+
+// StatMiddleware response time, status code count, etc.
+func StatMiddleware() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ beginning, recorder := status.Stats.Begin(c.Writer)
+ c.Next()
+ status.Stats.End(beginning, stats.WithRecorder(recorder))
+ }
+}
+
+func autoTLSServer(cfg *config.ConfYaml, q *queue.Queue) *http.Server {
+ m := autocert.Manager{
+ Prompt: autocert.AcceptTOS,
+ HostPolicy: autocert.HostWhitelist(cfg.Core.AutoTLS.Host),
+ Cache: autocert.DirCache(cfg.Core.AutoTLS.Folder),
+ }
+
+ return &http.Server{
+ Addr: ":https",
+ TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
+ Handler: routerEngine(cfg, q),
+ }
+}
+
+func routerEngine(cfg *config.ConfYaml, q *queue.Queue) *gin.Engine {
+ zerolog.SetGlobalLevel(zerolog.InfoLevel)
+ if cfg.Core.Mode == "debug" {
+ zerolog.SetGlobalLevel(zerolog.DebugLevel)
+ }
+
+ log.Logger = zerolog.New(os.Stdout).With().Timestamp().Logger()
+
+ isTerm := isatty.IsTerminal(os.Stdout.Fd())
+ if isTerm {
+ log.Logger = log.Output(
+ zerolog.ConsoleWriter{
+ Out: os.Stdout,
+ NoColor: false,
+ },
+ )
+ }
+
+ // Support metrics
+ doOnce.Do(func() {
+ m := metric.NewMetrics(func() int {
+ return q.Usage()
+ })
+ prometheus.MustRegister(m)
+ })
+
+ // set server mode
+ gin.SetMode(cfg.Core.Mode)
+
+ r := gin.New()
+
+ // Global middleware
+ r.Use(logger.SetLogger(
+ logger.WithUTC(true),
+ logger.WithSkipPath([]string{
+ cfg.API.HealthURI,
+ cfg.API.MetricURI,
+ }),
+ ))
+ r.Use(gin.Recovery())
+ r.Use(VersionMiddleware())
+ r.Use(StatMiddleware())
+
+ r.GET(cfg.API.StatGoURI, api.GinHandler)
+ r.GET(cfg.API.StatAppURI, appStatusHandler(q))
+ r.GET(cfg.API.ConfigURI, configHandler(cfg))
+ r.GET(cfg.API.SysStatURI, sysStatsHandler())
+ r.POST(cfg.API.PushURI, pushHandler(cfg, q))
+ r.GET(cfg.API.MetricURI, metricsHandler)
+ r.GET(cfg.API.HealthURI, heartbeatHandler)
+ r.HEAD(cfg.API.HealthURI, heartbeatHandler)
+ r.GET("/version", versionHandler)
+ r.GET("/", rootHandler)
+
+ return r
+}
+
+// markFailedNotification adds failure logs for all tokens in push notification
+func markFailedNotification(cfg *config.ConfYaml, notification *notify.PushNotification, reason string) []logx.LogPushEntry {
+ logx.LogError.Error(reason)
+ logs := make([]logx.LogPushEntry, 0)
+ for _, token := range notification.Tokens {
+ logs = append(logs, logx.GetLogPushEntry(&logx.InputLog{
+ ID: notification.ID,
+ Status: core.FailedPush,
+ Token: token,
+ Message: notification.Message,
+ Platform: notification.Platform,
+ Error: errors.New(reason),
+ HideToken: cfg.Log.HideToken,
+ Format: cfg.Log.Format,
+ }))
+ }
+
+ return logs
+}
+
+// HandleNotification add notification to queue list.
+func handleNotification(ctx context.Context, cfg *config.ConfYaml, req notify.RequestPush, q *queue.Queue) (int, []logx.LogPushEntry) {
+ var count int
+ wg := sync.WaitGroup{}
+ newNotification := []*notify.PushNotification{}
+
+ if cfg.Core.Sync && !core.IsLocalQueue(core.Queue(cfg.Queue.Engine)) {
+ cfg.Core.Sync = false
+ }
+
+ for i := range req.Notifications {
+ notification := &req.Notifications[i]
+ switch notification.Platform {
+ case core.PlatFormIos:
+ if !cfg.Ios.Enabled {
+ continue
+ }
+ case core.PlatFormAndroid:
+ if !cfg.Android.Enabled {
+ continue
+ }
+ case core.PlatFormHuawei:
+ if !cfg.Huawei.Enabled {
+ continue
+ }
+ }
+ newNotification = append(newNotification, notification)
+ }
+
+ logs := make([]logx.LogPushEntry, 0, count)
+ for _, notification := range newNotification {
+ if cfg.Core.Sync {
+ wg.Add(1)
+ }
+
+ if core.IsLocalQueue(core.Queue(cfg.Queue.Engine)) && cfg.Core.Sync {
+ func(msg *notify.PushNotification, cfg *config.ConfYaml) {
+ if err := q.QueueTask(func(ctx context.Context) error {
+ defer wg.Done()
+ resp, err := notify.SendNotification(msg, cfg)
+ if err != nil {
+ return err
+ }
+
+ // add log
+ logs = append(logs, resp.Logs...)
+
+ return nil
+ }); err != nil {
+ logx.LogError.Error(err)
+ }
+ }(notification, cfg)
+ } else if err := q.Queue(notification); err != nil {
+ resp := markFailedNotification(cfg, notification, "max capacity reached")
+ // add log
+ logs = append(logs, resp...)
+ wg.Done()
+ }
+
+ count += len(notification.Tokens)
+ // Count topic message
+ if notification.To != "" {
+ count++
+ }
+ }
+
+ if cfg.Core.Sync {
+ wg.Wait()
+ }
+
+ status.StatStorage.AddTotalCount(int64(count))
+
+ return count, logs
+}
diff --git a/router/server_lambda.go b/router/server_lambda.go
new file mode 100644
index 000000000..0a186da7d
--- /dev/null
+++ b/router/server_lambda.go
@@ -0,0 +1,26 @@
+// +build lambda
+
+package router
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/logx"
+
+ "github.com/apex/gateway"
+ "github.com/golang-queue/queue"
+)
+
+// RunHTTPServer provide run http or https protocol.
+func RunHTTPServer(ctx context.Context, cfg *config.ConfYaml, q *queue.Queue, s ...*http.Server) (err error) {
+ if !cfg.Core.Enabled {
+ logx.LogAccess.Debug("httpd server is disabled.")
+ return nil
+ }
+
+ logx.LogAccess.Info("HTTPD server is running on " + cfg.Core.Port + " port.")
+
+ return gateway.ListenAndServe(cfg.Core.Address+":"+cfg.Core.Port, routerEngine(cfg, q))
+}
diff --git a/router/server_normal.go b/router/server_normal.go
new file mode 100644
index 000000000..3f52e89d0
--- /dev/null
+++ b/router/server_normal.go
@@ -0,0 +1,124 @@
+// +build !lambda
+
+package router
+
+import (
+ "context"
+ "crypto/tls"
+ "encoding/base64"
+ "errors"
+ "net/http"
+ "time"
+
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/logx"
+
+ "github.com/golang-queue/queue"
+ "golang.org/x/sync/errgroup"
+)
+
+// RunHTTPServer provide run http or https protocol.
+func RunHTTPServer(ctx context.Context, cfg *config.ConfYaml, q *queue.Queue, s ...*http.Server) (err error) {
+ var server *http.Server
+
+ if !cfg.Core.Enabled {
+ logx.LogAccess.Info("httpd server is disabled.")
+ return nil
+ }
+
+ if len(s) == 0 {
+ server = &http.Server{
+ Addr: cfg.Core.Address + ":" + cfg.Core.Port,
+ Handler: routerEngine(cfg, q),
+ }
+ } else {
+ server = s[0]
+ }
+
+ logx.LogAccess.Info("HTTPD server is running on " + cfg.Core.Port + " port.")
+ if cfg.Core.AutoTLS.Enabled {
+ return startServer(ctx, autoTLSServer(cfg, q), cfg)
+ } else if cfg.Core.SSL {
+ config := &tls.Config{
+ MinVersion: tls.VersionTLS10,
+ }
+
+ if config.NextProtos == nil {
+ config.NextProtos = []string{"http/1.1"}
+ }
+
+ config.Certificates = make([]tls.Certificate, 1)
+ if cfg.Core.CertPath != "" && cfg.Core.KeyPath != "" {
+ config.Certificates[0], err = tls.LoadX509KeyPair(cfg.Core.CertPath, cfg.Core.KeyPath)
+ if err != nil {
+ logx.LogError.Error("Failed to load https cert file: ", err)
+ return err
+ }
+ } else if cfg.Core.CertBase64 != "" && cfg.Core.KeyBase64 != "" {
+ cert, err := base64.StdEncoding.DecodeString(cfg.Core.CertBase64)
+ if err != nil {
+ logx.LogError.Error("base64 decode error:", err.Error())
+ return err
+ }
+ key, err := base64.StdEncoding.DecodeString(cfg.Core.KeyBase64)
+ if err != nil {
+ logx.LogError.Error("base64 decode error:", err.Error())
+ return err
+ }
+ if config.Certificates[0], err = tls.X509KeyPair(cert, key); err != nil {
+ logx.LogError.Error("tls key pair error:", err.Error())
+ return err
+ }
+ } else {
+ return errors.New("missing https cert config")
+ }
+
+ server.TLSConfig = config
+ }
+
+ return startServer(ctx, server, cfg)
+}
+
+func listenAndServe(ctx context.Context, s *http.Server, cfg *config.ConfYaml) error {
+ var g errgroup.Group
+ g.Go(func() error {
+ <-ctx.Done()
+ timeout := time.Duration(cfg.Core.ShutdownTimeout) * time.Second
+ ctx, cancel := context.WithTimeout(context.Background(), timeout)
+ defer cancel()
+ return s.Shutdown(ctx)
+ })
+ g.Go(func() error {
+ if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+ return err
+ }
+ return nil
+ })
+ return g.Wait()
+}
+
+func listenAndServeTLS(ctx context.Context, s *http.Server, cfg *config.ConfYaml) error {
+ var g errgroup.Group
+ g.Go(func() error {
+ <-ctx.Done()
+ timeout := time.Duration(cfg.Core.ShutdownTimeout) * time.Second
+ ctx, cancel := context.WithTimeout(context.Background(), timeout)
+ defer cancel()
+ return s.Shutdown(ctx)
+ })
+ g.Go(func() error {
+ if err := s.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
+ return err
+ }
+ return nil
+ })
+ return g.Wait()
+}
+
+func startServer(ctx context.Context, s *http.Server, cfg *config.ConfYaml) error {
+ if s.TLSConfig == nil {
+ return listenAndServe(ctx, s, cfg)
+ }
+
+ return listenAndServeTLS(ctx, s, cfg)
+}
diff --git a/router/server_test.go b/router/server_test.go
new file mode 100644
index 000000000..0d988e891
--- /dev/null
+++ b/router/server_test.go
@@ -0,0 +1,679 @@
+package router
+
+import (
+ "context"
+ "crypto/tls"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "runtime"
+ "testing"
+ "time"
+
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/core"
+ "github.com/appleboy/gorush/logx"
+ "github.com/appleboy/gorush/notify"
+ "github.com/appleboy/gorush/status"
+
+ "github.com/appleboy/gofight/v2"
+ "github.com/buger/jsonparser"
+ "github.com/gin-gonic/gin"
+ "github.com/golang-queue/queue"
+ "github.com/stretchr/testify/assert"
+)
+
+var (
+ goVersion = runtime.Version()
+ q *queue.Queue
+)
+
+func TestMain(m *testing.M) {
+ cfg := initTest()
+ if err := status.InitAppStatus(cfg); err != nil {
+ log.Fatal(err)
+ }
+
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+
+ if _, err := notify.InitFCMClient(cfg, ""); err != nil {
+ log.Fatal(err)
+ }
+
+ q = queue.NewPool(
+ int(cfg.Core.WorkerNum),
+ queue.WithFn(func(ctx context.Context, msg queue.QueuedMessage) error {
+ _, err := notify.SendNotification(msg, cfg)
+ return err
+ }),
+ queue.WithLogger(logx.QueueLogger()),
+ )
+
+ code := m.Run()
+ defer func() {
+ q.Release()
+ os.Exit(code)
+ }()
+}
+
+func initTest() *config.ConfYaml {
+ cfg, _ := config.LoadConf()
+ cfg.Core.Mode = "test"
+ return cfg
+}
+
+// testRequest is testing url string if server is running
+func testRequest(t *testing.T, url string) {
+ tr := &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ }
+ client := &http.Client{
+ Timeout: time.Second * 10,
+ Transport: tr,
+ }
+
+ resp, err := client.Get(url)
+ defer func() {
+ if err := resp.Body.Close(); err != nil {
+ log.Println("close body err:", err)
+ }
+ }()
+
+ assert.NoError(t, err)
+
+ _, ioerr := ioutil.ReadAll(resp.Body)
+ assert.NoError(t, ioerr)
+ assert.Equal(t, "200 OK", resp.Status, "should get a 200")
+}
+
+func TestPrintGoRushVersion(t *testing.T) {
+ SetVersion("3.0.0")
+ ver := GetVersion()
+ PrintGoRushVersion()
+
+ assert.Equal(t, "3.0.0", ver)
+}
+
+func TestRunNormalServer(t *testing.T) {
+ cfg := initTest()
+
+ gin.SetMode(gin.TestMode)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ assert.NoError(t, RunHTTPServer(ctx, cfg, q))
+ }()
+
+ defer func() {
+ // close the server
+ cancel()
+ }()
+ // have to wait for the goroutine to start and run the server
+ // otherwise the main thread will complete
+ time.Sleep(5 * time.Millisecond)
+
+ testRequest(t, "http://localhost:8088/api/stat/go")
+}
+
+func TestRunTLSServer(t *testing.T) {
+ cfg := initTest()
+
+ cfg.Core.SSL = true
+ cfg.Core.Port = "8087"
+ cfg.Core.CertPath = "../certificate/localhost.cert"
+ cfg.Core.KeyPath = "../certificate/localhost.key"
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ assert.NoError(t, RunHTTPServer(ctx, cfg, q))
+ }()
+
+ defer func() {
+ // close the server
+ cancel()
+ }()
+ // have to wait for the goroutine to start and run the server
+ // otherwise the main thread will complete
+ time.Sleep(5 * time.Millisecond)
+
+ testRequest(t, "https://localhost:8087/api/stat/go")
+}
+
+func TestRunTLSBase64Server(t *testing.T) {
+ // nolint
+ cert := `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMrekNDQWVPZ0F3SUJBZ0lKQUxiWkVEdlVRckZLTUEwR0NTcUdTSWIzRFFFQkJRVUFNQlF4RWpBUUJnTlYKQkFNTUNXeHZZMkZzYUc5emREQWVGdzB4TmpBek1qZ3dNek13TkRGYUZ3MHlOakF6TWpZd016TXdOREZhTUJReApFakFRQmdOVkJBTU1DV3h2WTJGc2FHOXpkRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DCmdnRUJBTWoxK3hnNGpWTHpWbkI1ajduMXVsMzBXRUU0QkN6Y05GeGc1QU9CNUg1cSt3amUwWVlpVkZnNlBReXYKR0NpcHFJUlhWUmRWUTFoSFNldW5ZR0tlOGxxM1NiMVg4UFVKMTJ2OXVSYnBTOURLMU93cWs4cnNQRHU2c1ZUTApxS0tnSDFaOHlhenphUzBBYlh1QTVlOWdPL1J6aWpibnBFUCtxdU00ZHVlaU1QVkVKeUxxK0VvSVFZK01NOE1QCjhkWnpMNFhabDd3TDRVc0NON3JQY082VzN0bG5UMGlPM2g5Yy9ZbTJoRmh6K0tOSjlLUlJDdnRQR1pFU2lndEsKYkhzWEgwOTlXRG84di9XcDUvZXZCdy8rSkQwb3B4bUNmSElCQUxIdDl2NTNSdnZzRFoxdDMzUnB1NUM4em5FWQpZMkF5N05neGhxanFvV0pxQTQ4bEplQTBjbHNDQXdFQUFhTlFNRTR3SFFZRFZSME9CQllFRkMwYlRVMVhvZmVoCk5LSWVsYXNoSXNxS2lkRFlNQjhHQTFVZEl3UVlNQmFBRkMwYlRVMVhvZmVoTktJZWxhc2hJc3FLaWREWU1Bd0cKQTFVZEV3UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ2dFQkFBaUpMOElNVHdOWDlYcVFXWURGZ2tHNApBbnJWd1FocmVBcUM5clN4RENqcXFuTUhQSEd6Y0NlRE1MQU1vaDBrT3kyMG5vd1VHTnRDWjB1QnZuWDJxMWJOCmcxanQrR0JjTEpEUjNMTDRDcE5PbG0zWWhPeWN1TmZXTXhUQTdCWGttblNyWkQvN0toQXJzQkVZOGF1bHh3S0oKSFJnTmxJd2Uxb0ZEMVlkWDFCUzVwcDR0MjVCNlZxNEEzRk1NVWtWb1dFNjg4bkUxNjhodlFnd2pySGtnSGh3ZQplTjhsR0UyRGhGcmFYbldtRE1kd2FIRDNIUkZHaHlwcElGTitmN0JxYldYOWdNK1QyWVJUZk9iSVhMV2JxSkxECjNNay9Oa3hxVmNnNGVZNTR3SjF1ZkNVR0FZQUlhWTZmUXFpTlV6OG5od0szdDQ1TkJWVDl5L3VKWHFuVEx5WT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=`
+ // nolint
+ key := `LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBeVBYN0dEaU5Vdk5XY0htUHVmVzZYZlJZUVRnRUxOdzBYR0RrQTRIa2ZtcjdDTjdSCmhpSlVXRG85REs4WUtLbW9oRmRWRjFWRFdFZEo2NmRnWXA3eVdyZEp2VmZ3OVFuWGEvMjVGdWxMME1yVTdDcVQKeXV3OE83cXhWTXVvb3FBZlZuekpyUE5wTFFCdGU0RGw3MkE3OUhPS051ZWtRLzZxNHpoMjU2SXc5VVFuSXVyNApTZ2hCajR3end3L3gxbk12aGRtWHZBdmhTd0kzdXM5dzdwYmUyV2RQU0k3ZUgxejlpYmFFV0hQNG8wbjBwRkVLCiswOFprUktLQzBwc2V4Y2ZUMzFZT2p5Lzlhbm45NjhIRC80a1BTaW5HWUo4Y2dFQXNlMzIvbmRHKyt3Tm5XM2YKZEdtN2tMek9jUmhqWURMczJER0dxT3FoWW1vRGp5VWw0RFJ5V3dJREFRQUJBb0lCQUdUS3FzTjlLYlNmQTQycQpDcUkwVXVMb3VKTU5hMXFzbno1dUFpNllLV2dXZEE0QTQ0bXBFakNtRlJTVmhVSnZ4V3VLK2N5WUlRelh4SVdECkQxNm5aZHFGNzJBZUNXWjlKeVNzdnZaMDBHZktNM3kzNWlSeTA4c0pXZ096bWNMbkdKQ2lTZXlLc1FlM0hUSkMKZGhEWGJYcXZzSFRWUFpnMDFMVGVEeFVpVGZmVThOTUtxUjJBZWNRMnNURHdYRWhBblR5QXRuemwvWGFCZ0Z6dQpVNkc3RnpHTTV5OWJ4a2ZRVmt2eStERUprSEdOT2p6d2NWZkJ5eVZsNjEwaXhtRzF2bXhWajlQYldtSVBzVVY4CnlTbWpodkRRYk9mb3hXMGg5dlRsVHFHdFFjQnc5NjJvc25ERE1XRkNkTTdsek8wVDdSUm5QVkdJUnBDSk9LaHEKa2VxSEt3RUNnWUVBOHd3SS9pWnVnaG9UWFRORzlMblFRL1dBdHNxTzgwRWpNVFVoZW81STFrT3ptVXowOXB5aAppQXNVRG9OMC8yNnRaNVdOamxueVp1N2R2VGMveDNkVFpwbU5ub284Z2NWYlFORUNEUnpxZnVROVBQWG0xU041CjZwZUJxQXZCdjc4aGpWMDVhWHpQRy9WQmJlaWc3bDI5OUVhckVBK2Evb0gzS3JnRG9xVnFFMEVDZ1lFQTA2dkEKWUptZ2c0ZlpSdWNBWW9hWXNMejlaOXJDRmpUZTFQQlRtVUprYk9SOHZGSUhIVFRFV2kvU3V4WEwwd0RTZW9FMgo3QlFtODZnQ0M3L0tnUmRyem9CcVo1cVM5TXYyZHNMZ1k2MzVWU2dqamZaa1ZMaUgxVlJScFNRT2JZbmZveXNnCmdhdGNIU0tNRXhkNFNMUUJ5QXVJbVhQK0w1YXlEQmNFSmZicVNwc0NnWUI3OElzMWIwdXpOTERqT2g3WTlWaHIKRDJxUHpFT1JjSW9Oc2RaY3RPb1h1WGFBbW1uZ3lJYm01UjlaTjFnV1djNDdvRndMVjNyeFdxWGdzNmZtZzhjWAo3djMwOXZGY0M5UTQvVnhhYTRCNUxOSzluM2dUQUlCUFRPdGxVbmwrMm15MXRmQnRCcVJtMFc2SUtiVEhXUzVnCnZ4akVtL0NpRUl5R1VFZ3FUTWdIQVFLQmdCS3VYZFFvdXRuZzYzUXVmd0l6RHRiS1Z6TUxRNFhpTktobWJYcGgKT2F2Q25wK2dQYkIrTDdZbDhsdEFtVFNPSmdWWjBoY1QwRHhBMzYxWngrMk11NThHQmw0T2JsbmNobXdFMXZqMQpLY1F5UHJFUXhkb1VUeWlzd0dmcXZyczhKOWltdmIrejkvVTZUMUtBQjhXaTNXVmlYelByNE1zaWFhUlhnNjQyCkZJZHhBb0dBWjcvNzM1ZGtoSmN5T2ZzK0xLc0xyNjhKU3N0b29yWE9ZdmRNdTErSkdhOWlMdWhuSEVjTVZXQzgKSXVpaHpQZmxvWnRNYkdZa1pKbjhsM0JlR2Q4aG1mRnRnVGdaR1BvVlJldGZ0MkxERkxuUHhwMnNFSDVPRkxzUQpSK0sva0FPdWw4ZVN0V3VNWE9GQTlwTXpHa0dFZ0lGSk1KT3lhSk9OM2tlZFFJOGRlQ009Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==`
+ cfg := initTest()
+
+ cfg.Core.SSL = true
+ cfg.Core.Port = "8089"
+ cfg.Core.CertPath = ""
+ cfg.Core.KeyPath = ""
+ cfg.Core.CertBase64 = cert
+ cfg.Core.KeyBase64 = key
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ assert.NoError(t, RunHTTPServer(ctx, cfg, q))
+ }()
+
+ defer func() {
+ // close the server
+ cancel()
+ }()
+ // have to wait for the goroutine to start and run the server
+ // otherwise the main thread will complete
+ time.Sleep(5 * time.Millisecond)
+
+ testRequest(t, "https://localhost:8089/api/stat/go")
+}
+
+func TestRunAutoTLSServer(t *testing.T) {
+ cfg := initTest()
+ cfg.Core.AutoTLS.Enabled = true
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ assert.NoError(t, RunHTTPServer(ctx, cfg, q))
+ }()
+
+ defer func() {
+ // close the server
+ cancel()
+ }()
+ // have to wait for the goroutine to start and run the server
+ // otherwise the main thread will complete
+ time.Sleep(5 * time.Millisecond)
+}
+
+func TestLoadTLSCertError(t *testing.T) {
+ cfg := initTest()
+
+ cfg.Core.SSL = true
+ cfg.Core.Port = "8087"
+ cfg.Core.CertPath = "../config/config.yml"
+ cfg.Core.KeyPath = "../config/config.yml"
+
+ assert.Error(t, RunHTTPServer(context.Background(), cfg, q))
+}
+
+func TestMissingTLSCertcfgg(t *testing.T) {
+ cfg := initTest()
+
+ cfg.Core.SSL = true
+ cfg.Core.Port = "8087"
+ cfg.Core.CertPath = ""
+ cfg.Core.KeyPath = ""
+ cfg.Core.CertBase64 = ""
+ cfg.Core.KeyBase64 = ""
+
+ err := RunHTTPServer(context.Background(), cfg, q)
+ assert.Error(t, RunHTTPServer(context.Background(), cfg, q))
+ assert.Equal(t, "missing https cert config", err.Error())
+}
+
+func TestRootHandler(t *testing.T) {
+ cfg := initTest()
+
+ r := gofight.New()
+
+ // log for json
+ cfg.Log.Format = "json"
+
+ r.GET("/").
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ data := r.Body.Bytes()
+
+ value, _ := jsonparser.GetString(data, "text")
+
+ assert.Equal(t, "Welcome to notification server.", value)
+ assert.Equal(t, http.StatusOK, r.Code)
+ })
+}
+
+func TestAPIStatusGoHandler(t *testing.T) {
+ cfg := initTest()
+
+ r := gofight.New()
+
+ r.GET("/api/stat/go").
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ data := r.Body.Bytes()
+
+ value, _ := jsonparser.GetString(data, "go_version")
+
+ assert.Equal(t, goVersion, value)
+ assert.Equal(t, http.StatusOK, r.Code)
+ })
+}
+
+func TestAPIStatusAppHandler(t *testing.T) {
+ cfg := initTest()
+
+ r := gofight.New()
+
+ appVersion := "v1.0.0"
+ SetVersion(appVersion)
+
+ r.GET("/api/stat/app").
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ data := r.Body.Bytes()
+
+ value, _ := jsonparser.GetString(data, "version")
+
+ assert.Equal(t, appVersion, value)
+ assert.Equal(t, http.StatusOK, r.Code)
+ })
+}
+
+func TestAPIConfigHandler(t *testing.T) {
+ cfg := initTest()
+
+ r := gofight.New()
+
+ r.GET("/api/config").
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ assert.Equal(t, http.StatusCreated, r.Code)
+ })
+}
+
+func TestMissingNotificationsParameter(t *testing.T) {
+ cfg := initTest()
+
+ r := gofight.New()
+
+ // missing notifications parameter.
+ r.POST("/api/push").
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ assert.Equal(t, http.StatusBadRequest, r.Code)
+ })
+}
+
+func TestEmptyNotifications(t *testing.T) {
+ cfg := initTest()
+
+ r := gofight.New()
+
+ // notifications is empty.
+ r.POST("/api/push").
+ SetJSON(gofight.D{
+ "notifications": []notify.PushNotification{},
+ }).
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ assert.Equal(t, http.StatusBadRequest, r.Code)
+ })
+}
+
+func TestMutableContent(t *testing.T) {
+ cfg := initTest()
+
+ r := gofight.New()
+
+ // notifications is empty.
+ r.POST("/api/push").
+ SetJSON(gofight.D{
+ "notifications": []gofight.D{
+ {
+ "tokens": []string{"aaaaa", "bbbbb"},
+ "platform": core.PlatFormAndroid,
+ "message": "Welcome From API",
+ "mutable_content": 1,
+ "topic": "test",
+ "badge": 1,
+ "alert": gofight.D{
+ "title": "title",
+ "body": "body",
+ },
+ },
+ },
+ }).
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ // json: cannot unmarshal number into Go struct field notify.PushNotification.mutable_content of type bool
+ assert.Equal(t, http.StatusBadRequest, r.Code)
+ })
+}
+
+func TestOutOfRangeMaxNotifications(t *testing.T) {
+ cfg := initTest()
+
+ cfg.Core.MaxNotification = int64(1)
+
+ r := gofight.New()
+
+ // notifications is empty.
+ r.POST("/api/push").
+ SetJSON(gofight.D{
+ "notifications": []gofight.D{
+ {
+ "tokens": []string{"aaaaa", "bbbbb"},
+ "platform": core.PlatFormAndroid,
+ "message": "Welcome API From Android",
+ },
+ {
+ "tokens": []string{"aaaaa", "bbbbb"},
+ "platform": core.PlatFormAndroid,
+ "message": "Welcome API From Android",
+ },
+ },
+ }).
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ assert.Equal(t, http.StatusBadRequest, r.Code)
+ })
+}
+
+func TestSuccessPushHandler(t *testing.T) {
+ t.Skip()
+ cfg := initTest()
+
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+
+ androidToken := os.Getenv("ANDROID_TEST_TOKEN")
+
+ r := gofight.New()
+
+ r.POST("/api/push").
+ SetJSON(gofight.D{
+ "notifications": []gofight.D{
+ {
+ "tokens": []string{androidToken, "bbbbb"},
+ "platform": core.PlatFormAndroid,
+ "message": "Welcome Android",
+ },
+ },
+ }).
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ assert.Equal(t, http.StatusOK, r.Code)
+ })
+}
+
+func TestSysStatsHandler(t *testing.T) {
+ cfg := initTest()
+
+ r := gofight.New()
+
+ r.GET("/sys/stats").
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ assert.Equal(t, http.StatusOK, r.Code)
+ })
+}
+
+func TestMetricsHandler(t *testing.T) {
+ cfg := initTest()
+
+ r := gofight.New()
+
+ r.GET("/metrics").
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ assert.Equal(t, http.StatusOK, r.Code)
+ })
+}
+
+func TestGETHeartbeatHandler(t *testing.T) {
+ cfg := initTest()
+
+ r := gofight.New()
+
+ r.GET("/healthz").
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ assert.Equal(t, http.StatusOK, r.Code)
+ })
+}
+
+func TestHEADHeartbeatHandler(t *testing.T) {
+ cfg := initTest()
+
+ r := gofight.New()
+
+ r.HEAD("/healthz").
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ assert.Equal(t, http.StatusOK, r.Code)
+ })
+}
+
+func TestVersionHandler(t *testing.T) {
+ SetVersion("3.0.0")
+ cfg := initTest()
+
+ r := gofight.New()
+
+ r.GET("/version").
+ Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
+ assert.Equal(t, http.StatusOK, r.Code)
+ data := r.Body.Bytes()
+
+ value, _ := jsonparser.GetString(data, "version")
+
+ assert.Equal(t, "3.0.0", value)
+ })
+}
+
+func TestDisabledHTTPServer(t *testing.T) {
+ cfg := initTest()
+ cfg.Core.Enabled = false
+ err := RunHTTPServer(context.Background(), cfg, q)
+ cfg.Core.Enabled = true
+
+ assert.Nil(t, err)
+}
+
+func TestSenMultipleNotifications(t *testing.T) {
+ ctx := context.Background()
+ cfg := initTest()
+
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
+ err := notify.InitAPNSClient(cfg)
+ assert.Nil(t, err)
+
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+
+ androidToken := os.Getenv("ANDROID_TEST_TOKEN")
+
+ req := notify.RequestPush{
+ Notifications: []notify.PushNotification{
+ // ios
+ {
+ Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
+ Platform: core.PlatFormIos,
+ Message: "Welcome iOS",
+ },
+ // android
+ {
+ Tokens: []string{androidToken, "bbbbb"},
+ Platform: core.PlatFormAndroid,
+ Message: "Welcome Android",
+ },
+ },
+ }
+
+ count, logs := handleNotification(ctx, cfg, req, q)
+ assert.Equal(t, 3, count)
+ assert.Equal(t, 0, len(logs))
+}
+
+func TestDisabledAndroidNotifications(t *testing.T) {
+ ctx := context.Background()
+ cfg := initTest()
+
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
+ err := notify.InitAPNSClient(cfg)
+ assert.Nil(t, err)
+
+ cfg.Android.Enabled = false
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+
+ androidToken := os.Getenv("ANDROID_TEST_TOKEN")
+
+ req := notify.RequestPush{
+ Notifications: []notify.PushNotification{
+ // ios
+ {
+ Tokens: []string{"11aa01229f15f0f0c5209d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
+ Platform: core.PlatFormIos,
+ Message: "Welcome iOS",
+ },
+ // android
+ {
+ Tokens: []string{androidToken, "bbbbb"},
+ Platform: core.PlatFormAndroid,
+ Message: "Welcome Android",
+ },
+ },
+ }
+
+ count, logs := handleNotification(ctx, cfg, req, q)
+ assert.Equal(t, 1, count)
+ assert.Equal(t, 0, len(logs))
+}
+
+func TestSyncModeForNotifications(t *testing.T) {
+ ctx := context.Background()
+ cfg := initTest()
+
+ cfg.Ios.Enabled = true
+ cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
+ err := notify.InitAPNSClient(cfg)
+ assert.Nil(t, err)
+
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+
+ // enable sync mode
+ cfg.Core.Sync = true
+
+ androidToken := os.Getenv("ANDROID_TEST_TOKEN")
+
+ req := notify.RequestPush{
+ Notifications: []notify.PushNotification{
+ // ios
+ {
+ Tokens: []string{
+ "11aa01229f15f0f0c12029d8c111d1ae1f2365f14cebc4af26cd6d76b7919ef7",
+ },
+ Platform: core.PlatFormIos,
+ Message: "Welcome iOS Sync",
+ },
+ // android
+ {
+ Tokens: []string{androidToken, "bbbbb"},
+ Platform: core.PlatFormAndroid,
+ Message: "Welcome Android Sync",
+ },
+ },
+ }
+
+ count, logs := handleNotification(ctx, cfg, req, q)
+ assert.Equal(t, 3, count)
+ assert.Equal(t, 2, len(logs))
+}
+
+func TestSyncModeForTopicNotification(t *testing.T) {
+ ctx := context.Background()
+ cfg := initTest()
+
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+ cfg.Log.HideToken = false
+
+ // enable sync mode
+ cfg.Core.Sync = true
+
+ req := notify.RequestPush{
+ Notifications: []notify.PushNotification{
+ // android
+ {
+ // error:InvalidParameters
+ // Check that the provided parameters have the right name and type.
+ To: "/topics/foo-bar@@@##",
+ Platform: core.PlatFormAndroid,
+ Message: "This is a Firebase Cloud Messaging Topic Message!",
+ },
+ // android
+ {
+ // success
+ To: "/topics/foo-bar",
+ Platform: core.PlatFormAndroid,
+ Message: "This is a Firebase Cloud Messaging Topic Message!",
+ },
+ // android
+ {
+ // success
+ Condition: "'dogs' in topics || 'cats' in topics",
+ Platform: core.PlatFormAndroid,
+ Message: "This is a Firebase Cloud Messaging Topic Message!",
+ },
+ },
+ }
+
+ count, logs := handleNotification(ctx, cfg, req, q)
+ assert.Equal(t, 2, count)
+ assert.Equal(t, 1, len(logs))
+}
+
+func TestSyncModeForDeviceGroupNotification(t *testing.T) {
+ ctx := context.Background()
+ cfg := initTest()
+
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+ cfg.Log.HideToken = false
+
+ // enable sync mode
+ cfg.Core.Sync = true
+
+ req := notify.RequestPush{
+ Notifications: []notify.PushNotification{
+ // android
+ {
+ To: "aUniqueKey",
+ Platform: core.PlatFormAndroid,
+ Message: "This is a Firebase Cloud Messaging Device Group Message!",
+ },
+ },
+ }
+
+ count, logs := handleNotification(ctx, cfg, req, q)
+ assert.Equal(t, 1, count)
+ assert.Equal(t, 1, len(logs))
+}
+
+func TestDisabledIosNotifications(t *testing.T) {
+ ctx := context.Background()
+ cfg := initTest()
+
+ cfg.Ios.Enabled = false
+ cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
+ err := notify.InitAPNSClient(cfg)
+ assert.Nil(t, err)
+
+ cfg.Android.Enabled = true
+ cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
+
+ androidToken := os.Getenv("ANDROID_TEST_TOKEN")
+
+ req := notify.RequestPush{
+ Notifications: []notify.PushNotification{
+ // ios
+ {
+ Tokens: []string{"11aa01229f15f0f0c52021d8cf3cd0ae1f2365fe4cebc4af26cd6d76b7919ef7"},
+ Platform: core.PlatFormIos,
+ Message: "Welcome iOS platform",
+ },
+ // android
+ {
+ Tokens: []string{androidToken, androidToken + "_"},
+ Platform: core.PlatFormAndroid,
+ Message: "Welcome Android platform",
+ },
+ },
+ }
+
+ count, logs := handleNotification(ctx, cfg, req, q)
+ assert.Equal(t, 2, count)
+ assert.Equal(t, 0, len(logs))
+}
diff --git a/gorush/version.go b/router/version.go
similarity index 97%
rename from gorush/version.go
rename to router/version.go
index f8cdcdffa..6300ec346 100644
--- a/gorush/version.go
+++ b/router/version.go
@@ -1,4 +1,4 @@
-package gorush
+package router
import (
"fmt"
diff --git a/rpc/client_grpc_health.go b/rpc/client_grpc_health.go
index 98c498056..39fce0281 100644
--- a/rpc/client_grpc_health.go
+++ b/rpc/client_grpc_health.go
@@ -7,6 +7,7 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
)
// generate protobuffs
@@ -41,7 +42,7 @@ func (c *healthClient) Check(ctx context.Context) (bool, error) {
}
return false, nil
}
- switch grpc.Code(err) {
+ switch status.Code(err) {
case
codes.Aborted,
codes.DataLoss,
diff --git a/rpc/example/go/health/main.go b/rpc/example/go/health/main.go
index 323b8a4fd..91d66f2d2 100644
--- a/rpc/example/go/health/main.go
+++ b/rpc/example/go/health/main.go
@@ -8,6 +8,7 @@ import (
"github.com/appleboy/gorush/rpc"
"google.golang.org/grpc"
+ "google.golang.org/grpc/status"
)
const (
@@ -27,7 +28,7 @@ func main() {
for {
ok, err := client.Check(context.Background())
if !ok || err != nil {
- log.Printf("can't connect grpc server: %v, code: %v\n", err, grpc.Code(err))
+ log.Printf("can't connect grpc server: %v, code: %v\n", err, status.Code(err))
} else {
log.Println("connect the grpc server successfully")
}
diff --git a/rpc/example/go/send/main.go b/rpc/example/go/send/main.go
index 9ead8edae..f9b0581bd 100644
--- a/rpc/example/go/send/main.go
+++ b/rpc/example/go/send/main.go
@@ -30,7 +30,7 @@ func main() {
Badge: 1,
Category: "test",
Sound: "test",
- Priority: proto.Priority_High,
+ Priority: proto.NotificationRequest_HIGH,
Alert: &proto.Alert{
Title: "Test Title",
Body: "Test Alert Body",
@@ -50,8 +50,11 @@ func main() {
},
})
if err != nil {
- log.Fatalf("could not greet: %v", err)
+ log.Println("could not greet: ", err)
+ }
+
+ if r != nil {
+ log.Printf("Success: %t\n", r.Success)
+ log.Printf("Count: %d\n", r.Counts)
}
- log.Printf("Success: %t\n", r.Success)
- log.Printf("Count: %d\n", r.Counts)
}
diff --git a/rpc/example/node/gorush_pb.js b/rpc/example/node/gorush_pb.js
index 32aa1b7e4..bf5d084c6 100644
--- a/rpc/example/node/gorush_pb.js
+++ b/rpc/example/node/gorush_pb.js
@@ -7,6 +7,8 @@
* @public
*/
// GENERATED CODE -- DO NOT EDIT!
+/* eslint-disable */
+// @ts-nocheck
var jspb = require('google-protobuf');
var goog = jspb;
@@ -20,7 +22,7 @@ goog.exportSymbol('proto.proto.HealthCheckResponse', null, global);
goog.exportSymbol('proto.proto.HealthCheckResponse.ServingStatus', null, global);
goog.exportSymbol('proto.proto.NotificationReply', null, global);
goog.exportSymbol('proto.proto.NotificationRequest', null, global);
-goog.exportSymbol('proto.proto.Priority', null, global);
+goog.exportSymbol('proto.proto.NotificationRequest.Priority', null, global);
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
@@ -725,7 +727,7 @@ proto.proto.NotificationRequest.deserializeBinaryFromReader = function(msg, read
msg.setImage(value);
break;
case 16:
- var value = /** @type {!proto.proto.Priority} */ (reader.readEnum());
+ var value = /** @type {!proto.proto.NotificationRequest.Priority} */ (reader.readEnum());
msg.setPriority(value);
break;
default:
@@ -874,6 +876,14 @@ proto.proto.NotificationRequest.serializeBinaryToWriter = function(message, writ
};
+/**
+ * @enum {number}
+ */
+proto.proto.NotificationRequest.Priority = {
+ NORMAL: 0,
+ HIGH: 1
+};
+
/**
* repeated string tokens = 1;
* @return {!Array}
@@ -1202,16 +1212,16 @@ proto.proto.NotificationRequest.prototype.setImage = function(value) {
/**
- * optional Priority Priority = 16;
- * @return {!proto.proto.Priority}
+ * optional Priority priority = 16;
+ * @return {!proto.proto.NotificationRequest.Priority}
*/
proto.proto.NotificationRequest.prototype.getPriority = function() {
- return /** @type {!proto.proto.Priority} */ (jspb.Message.getFieldWithDefault(this, 16, 0));
+ return /** @type {!proto.proto.NotificationRequest.Priority} */ (jspb.Message.getFieldWithDefault(this, 16, 0));
};
/**
- * @param {!proto.proto.Priority} value
+ * @param {!proto.proto.NotificationRequest.Priority} value
* @return {!proto.proto.NotificationRequest} returns this
*/
proto.proto.NotificationRequest.prototype.setPriority = function(value) {
@@ -1648,12 +1658,4 @@ proto.proto.HealthCheckResponse.prototype.setStatus = function(value) {
};
-/**
- * @enum {number}
- */
-proto.proto.Priority = {
- NORMAL: 0,
- HIGH: 1
-};
-
goog.object.extend(exports, proto.proto);
diff --git a/rpc/example/node/package-lock.json b/rpc/example/node/package-lock.json
index a13e67077..e7a86febe 100644
--- a/rpc/example/node/package-lock.json
+++ b/rpc/example/node/package-lock.json
@@ -4,37 +4,80 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+ "@mapbox/node-pre-gyp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz",
+ "integrity": "sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==",
+ "requires": {
+ "detect-libc": "^1.0.3",
+ "https-proxy-agent": "^5.0.0",
+ "make-dir": "^3.1.0",
+ "node-fetch": "^2.6.1",
+ "nopt": "^5.0.0",
+ "npmlog": "^4.1.2",
+ "rimraf": "^3.0.2",
+ "semver": "^7.3.4",
+ "tar": "^6.1.0"
+ }
+ },
"@types/bytebuffer": {
- "version": "5.0.40",
- "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.40.tgz",
- "integrity": "sha512-h48dyzZrPMz25K6Q4+NCwWaxwXany2FhQg/ErOcdZS1ZpsaDnDMZg8JYLMTGz7uvXKrcKGJUZJlZObyfgdaN9g==",
+ "version": "5.0.42",
+ "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.42.tgz",
+ "integrity": "sha512-lEgKojWUAc/MG2t649oZS5AfYFP2xRNPoDuwDBlBMjHXd8MaGPgFgtCXUK7inZdBOygmVf10qxc1Us8GXC96aw==",
"requires": {
- "@types/long": "4.0.0",
- "@types/node": "12.11.7"
+ "@types/long": "*",
+ "@types/node": "*"
}
},
"@types/long": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz",
- "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q=="
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz",
+ "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w=="
},
"@types/node": {
- "version": "12.11.7",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.7.tgz",
- "integrity": "sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA=="
+ "version": "15.3.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz",
+ "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ=="
+ },
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+ },
+ "agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "requires": {
+ "debug": "4"
+ }
},
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
+ "aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
"ascli": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz",
"integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=",
"requires": {
- "colour": "0.7.1",
- "optjs": "3.2.2"
+ "colour": "~0.7.1",
+ "optjs": "~3.2.2"
}
},
"async": {
@@ -43,16 +86,16 @@
"integrity": "sha512-4vx/aaY6j/j3Lw3fbCHNWP0pPaTCew3F6F3hYyl/tHs/ndmV1q7NW9T5yuJ2XAGwdQrP+6Wu20x06U4APo/iQQ=="
},
"balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
- "balanced-match": "1.0.0",
+ "balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
@@ -61,7 +104,7 @@
"resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz",
"integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=",
"requires": {
- "long": "3.2.0"
+ "long": "~3"
}
},
"camelcase": {
@@ -69,14 +112,19 @@
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
"integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8="
},
+ "chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
+ },
"cliui": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
"integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
"requires": {
- "string-width": "1.0.2",
- "strip-ansi": "3.0.1",
- "wrap-ansi": "2.1.0"
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wrap-ansi": "^2.0.0"
}
},
"code-point-at": {
@@ -94,32 +142,83 @@
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
+ "console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
},
+ "delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
+ },
"dom-walk": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
"integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg="
},
+ "fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
+ "gauge": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
"glob": {
- "version": "7.1.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz",
- "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==",
+ "version": "7.1.7",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
+ "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
"requires": {
- "fs.realpath": "1.0.0",
- "inflight": "1.0.6",
- "inherits": "2.0.4",
- "minimatch": "3.0.4",
- "once": "1.4.0",
- "path-is-absolute": "1.0.1"
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
}
},
"global": {
@@ -137,487 +236,30 @@
"integrity": "sha512-d0cMO8TJ6xtB/WrVHCv5U81L2ulX+aCD58IljyAN6mHwdHHJ2jbcauX5glvivi3s3hx7EYEo7eUA9WftzamMnw=="
},
"grpc": {
- "version": "1.24.1",
- "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.24.1.tgz",
- "integrity": "sha512-NFIWbt3RXZU4VlDLpiAM/Ca8Yz30QShUdPGMqOPH652PmA+2fau2vuW+tOYWQUkYMfBW2yege/T5p65e5TetVQ==",
- "requires": {
- "@types/bytebuffer": "5.0.40",
- "lodash.camelcase": "4.3.0",
- "lodash.clone": "4.5.0",
- "nan": "2.14.0",
- "node-pre-gyp": "0.13.0",
- "protobufjs": "5.0.3"
- },
- "dependencies": {
- "abbrev": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
- "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
- },
- "ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
- },
- "aproba": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
- "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
- },
- "are-we-there-yet": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
- "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
- "requires": {
- "delegates": "1.0.0",
- "readable-stream": "2.3.6"
- }
- },
- "balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
- },
- "brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "requires": {
- "balanced-match": "1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "chownr": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz",
- "integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A=="
- },
- "code-point-at": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
- },
- "console-control-strings": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
- "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
- },
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
- },
- "debug": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "deep-extend": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
- "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
- },
- "delegates": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
- "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
- },
- "detect-libc": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
- "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
- },
- "fs-minipass": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz",
- "integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==",
- "requires": {
- "minipass": "2.3.5"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
- },
- "gauge": {
- "version": "2.7.4",
- "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
- "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
- "requires": {
- "aproba": "1.2.0",
- "console-control-strings": "1.1.0",
- "has-unicode": "2.0.1",
- "object-assign": "4.1.1",
- "signal-exit": "3.0.2",
- "string-width": "1.0.2",
- "strip-ansi": "3.0.1",
- "wide-align": "1.1.3"
- }
- },
- "glob": {
- "version": "7.1.4",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
- "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
- "requires": {
- "fs.realpath": "1.0.0",
- "inflight": "1.0.6",
- "inherits": "2.0.4",
- "minimatch": "3.0.4",
- "once": "1.4.0",
- "path-is-absolute": "1.0.1"
- }
- },
- "has-unicode": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
- "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
- },
- "iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "requires": {
- "safer-buffer": "2.1.2"
- }
- },
- "ignore-walk": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
- "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
- "requires": {
- "minimatch": "3.0.4"
- }
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "requires": {
- "once": "1.4.0",
- "wrappy": "1.0.2"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "ini": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
- "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "requires": {
- "number-is-nan": "1.0.1"
- }
- },
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
- },
- "minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "requires": {
- "brace-expansion": "1.1.11"
- }
- },
- "minimist": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
- },
- "minipass": {
- "version": "2.3.5",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
- "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
- "requires": {
- "safe-buffer": "5.1.2",
- "yallist": "3.0.3"
- }
- },
- "minizlib": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
- "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
- "requires": {
- "minipass": "2.3.5"
- }
- },
- "mkdirp": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
- "requires": {
- "minimist": "0.0.8"
- },
- "dependencies": {
- "minimist": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
- }
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "needle": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz",
- "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==",
- "requires": {
- "debug": "3.2.6",
- "iconv-lite": "0.4.24",
- "sax": "1.2.4"
- }
- },
- "node-pre-gyp": {
- "version": "0.13.0",
- "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz",
- "integrity": "sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ==",
- "requires": {
- "detect-libc": "1.0.3",
- "mkdirp": "0.5.1",
- "needle": "2.4.0",
- "nopt": "4.0.1",
- "npm-packlist": "1.4.4",
- "npmlog": "4.1.2",
- "rc": "1.2.8",
- "rimraf": "2.7.1",
- "semver": "5.7.1",
- "tar": "4.4.10"
- }
- },
- "nopt": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
- "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
- "requires": {
- "abbrev": "1.1.1",
- "osenv": "0.1.5"
- }
- },
- "npm-bundled": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
- "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g=="
- },
- "npm-packlist": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.4.tgz",
- "integrity": "sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==",
- "requires": {
- "ignore-walk": "3.0.1",
- "npm-bundled": "1.0.6"
- }
- },
- "npmlog": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
- "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
- "requires": {
- "are-we-there-yet": "1.1.5",
- "console-control-strings": "1.1.0",
- "gauge": "2.7.4",
- "set-blocking": "2.0.0"
- }
- },
- "number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "requires": {
- "wrappy": "1.0.2"
- }
- },
- "os-homedir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
- "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
- },
- "os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
- },
- "osenv": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
- "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
- "requires": {
- "os-homedir": "1.0.2",
- "os-tmpdir": "1.0.2"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
- },
- "process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
- },
- "rc": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
- "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
- "requires": {
- "deep-extend": "0.6.0",
- "ini": "1.3.5",
- "minimist": "1.2.0",
- "strip-json-comments": "2.0.1"
- }
- },
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "requires": {
- "core-util-is": "1.0.2",
- "inherits": "2.0.4",
- "isarray": "1.0.0",
- "process-nextick-args": "2.0.1",
- "safe-buffer": "5.1.2",
- "string_decoder": "1.1.1",
- "util-deprecate": "1.0.2"
- }
- },
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "requires": {
- "glob": "7.1.4"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- },
- "safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
- },
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
- },
- "set-blocking": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
- },
- "signal-exit": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
- "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
- },
- "string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "requires": {
- "code-point-at": "1.1.0",
- "is-fullwidth-code-point": "1.0.0",
- "strip-ansi": "3.0.1"
- }
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "requires": {
- "safe-buffer": "5.1.2"
- }
- },
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "requires": {
- "ansi-regex": "2.1.1"
- }
- },
- "strip-json-comments": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
- "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
- },
- "tar": {
- "version": "4.4.10",
- "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz",
- "integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==",
- "requires": {
- "chownr": "1.1.2",
- "fs-minipass": "1.2.6",
- "minipass": "2.3.5",
- "minizlib": "1.2.1",
- "mkdirp": "0.5.1",
- "safe-buffer": "5.1.2",
- "yallist": "3.0.3"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
- },
- "wide-align": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
- "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
- "requires": {
- "string-width": "1.0.2"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
- },
- "yallist": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
- "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
- }
+ "version": "1.24.9",
+ "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.24.9.tgz",
+ "integrity": "sha512-BOq1AJocZJcG/6qyX3LX2KvKy91RIix10GFLhqWg+1L6b73uWIN2w0cq+lSi0q9mXfkjeFaBz83+oau7oJqG3Q==",
+ "requires": {
+ "@mapbox/node-pre-gyp": "^1.0.4",
+ "@types/bytebuffer": "^5.0.40",
+ "lodash.camelcase": "^4.3.0",
+ "lodash.clone": "^4.5.0",
+ "nan": "^2.13.2",
+ "protobufjs": "^5.0.3"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+ },
+ "https-proxy-agent": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
+ "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+ "requires": {
+ "agent-base": "6",
+ "debug": "4"
}
},
"inflight": {
@@ -625,8 +267,8 @@
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
- "once": "1.4.0",
- "wrappy": "1.0.2"
+ "once": "^1.3.0",
+ "wrappy": "1"
}
},
"inherits": {
@@ -644,15 +286,20 @@
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"requires": {
- "number-is-nan": "1.0.1"
+ "number-is-nan": "^1.0.0"
}
},
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
"lcid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
"integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
"requires": {
- "invert-kv": "1.0.0"
+ "invert-kv": "^1.0.0"
}
},
"lodash": {
@@ -675,6 +322,29 @@
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
"integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s="
},
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "requires": {
+ "semver": "^6.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ }
+ }
+ },
"min-document": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
@@ -688,7 +358,7 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
- "brace-expansion": "1.1.11"
+ "brace-expansion": "^1.1.7"
}
},
"minimist": {
@@ -696,22 +366,78 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
+ "minipass": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
+ "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "requires": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ }
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
"nan": {
- "version": "2.14.0",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
- "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
+ "version": "2.14.2",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
+ "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ=="
+ },
+ "node-fetch": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
+ "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
+ },
+ "nopt": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+ "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
},
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
- "wrappy": "1.0.2"
+ "wrappy": "1"
}
},
"optjs": {
@@ -724,7 +450,7 @@
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"requires": {
- "lcid": "1.0.0"
+ "lcid": "^1.0.0"
}
},
"path-is-absolute": {
@@ -737,25 +463,83 @@
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
},
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ },
"protobufjs": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.3.tgz",
"integrity": "sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA==",
"requires": {
- "ascli": "1.0.1",
- "bytebuffer": "5.0.1",
- "glob": "7.1.5",
- "yargs": "3.32.0"
+ "ascli": "~1",
+ "bytebuffer": "~5",
+ "glob": "^7.0.5",
+ "yargs": "^3.10.0"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
}
},
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "semver": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ },
+ "signal-exit": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
+ },
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"requires": {
- "code-point-at": "1.1.0",
- "is-fullwidth-code-point": "1.0.0",
- "strip-ansi": "3.0.1"
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
}
},
"strip-ansi": {
@@ -763,7 +547,33 @@
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
- "ansi-regex": "2.1.1"
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "tar": {
+ "version": "6.1.11",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
+ "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==",
+ "requires": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^3.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+ "requires": {
+ "string-width": "^1.0.2 || 2"
}
},
"window-size": {
@@ -776,8 +586,8 @@
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"requires": {
- "string-width": "1.0.2",
- "strip-ansi": "3.0.1"
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
}
},
"wrappy": {
@@ -786,22 +596,27 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"y18n": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
- "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz",
+ "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ=="
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"yargs": {
"version": "3.32.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz",
"integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=",
"requires": {
- "camelcase": "2.1.1",
- "cliui": "3.2.0",
- "decamelize": "1.2.0",
- "os-locale": "1.4.0",
- "string-width": "1.0.2",
- "window-size": "0.1.4",
- "y18n": "3.2.1"
+ "camelcase": "^2.0.1",
+ "cliui": "^3.0.3",
+ "decamelize": "^1.1.1",
+ "os-locale": "^1.4.0",
+ "string-width": "^1.0.1",
+ "window-size": "^0.1.4",
+ "y18n": "^3.2.0"
}
}
}
diff --git a/rpc/example/node/package.json b/rpc/example/node/package.json
index 839809179..44ff5305c 100644
--- a/rpc/example/node/package.json
+++ b/rpc/example/node/package.json
@@ -5,7 +5,7 @@
"async": "^3.1.0",
"global": "^4.4.0",
"google-protobuf": "^3.10.0",
- "grpc": "^1.24.1",
+ "grpc": "^1.24.9",
"lodash": "^4.17.21",
"minimist": ">=1.2.2"
}
diff --git a/rpc/proto/gorush.pb.go b/rpc/proto/gorush.pb.go
index 24392f1bb..e22570f2a 100644
--- a/rpc/proto/gorush.pb.go
+++ b/rpc/proto/gorush.pb.go
@@ -1,23 +1,18 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.24.0
-// protoc v3.12.3
+// protoc-gen-go v1.25.0-devel
+// protoc v3.14.0
// source: gorush.proto
package proto
import (
- context "context"
reflect "reflect"
sync "sync"
- proto "github.com/golang/protobuf/proto"
- _struct "github.com/golang/protobuf/ptypes/struct"
- grpc "google.golang.org/grpc"
- codes "google.golang.org/grpc/codes"
- status "google.golang.org/grpc/status"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ structpb "google.golang.org/protobuf/types/known/structpb"
)
const (
@@ -27,54 +22,50 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
-type Priority int32
+type NotificationRequest_Priority int32
const (
- Priority_Normal Priority = 0
- Priority_High Priority = 1
+ NotificationRequest_NORMAL NotificationRequest_Priority = 0
+ NotificationRequest_HIGH NotificationRequest_Priority = 1
)
-// Enum value maps for Priority.
+// Enum value maps for NotificationRequest_Priority.
var (
- Priority_name = map[int32]string{
- 0: "Normal",
- 1: "High",
+ NotificationRequest_Priority_name = map[int32]string{
+ 0: "NORMAL",
+ 1: "HIGH",
}
- Priority_value = map[string]int32{
- "Normal": 0,
- "High": 1,
+ NotificationRequest_Priority_value = map[string]int32{
+ "NORMAL": 0,
+ "HIGH": 1,
}
)
-func (x Priority) Enum() *Priority {
- p := new(Priority)
+func (x NotificationRequest_Priority) Enum() *NotificationRequest_Priority {
+ p := new(NotificationRequest_Priority)
*p = x
return p
}
-func (x Priority) String() string {
+func (x NotificationRequest_Priority) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
-func (Priority) Descriptor() protoreflect.EnumDescriptor {
+func (NotificationRequest_Priority) Descriptor() protoreflect.EnumDescriptor {
return file_gorush_proto_enumTypes[0].Descriptor()
}
-func (Priority) Type() protoreflect.EnumType {
+func (NotificationRequest_Priority) Type() protoreflect.EnumType {
return &file_gorush_proto_enumTypes[0]
}
-func (x Priority) Number() protoreflect.EnumNumber {
+func (x NotificationRequest_Priority) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
-// Deprecated: Use Priority.Descriptor instead.
-func (Priority) EnumDescriptor() ([]byte, []int) {
- return file_gorush_proto_rawDescGZIP(), []int{0}
+// Deprecated: Use NotificationRequest_Priority.Descriptor instead.
+func (NotificationRequest_Priority) EnumDescriptor() ([]byte, []int) {
+ return file_gorush_proto_rawDescGZIP(), []int{1, 0}
}
type HealthCheckResponse_ServingStatus int32
@@ -250,22 +241,22 @@ type NotificationRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Tokens []string `protobuf:"bytes,1,rep,name=tokens,proto3" json:"tokens,omitempty"`
- Platform int32 `protobuf:"varint,2,opt,name=platform,proto3" json:"platform,omitempty"`
- Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
- Title string `protobuf:"bytes,4,opt,name=title,proto3" json:"title,omitempty"`
- Topic string `protobuf:"bytes,5,opt,name=topic,proto3" json:"topic,omitempty"`
- Key string `protobuf:"bytes,6,opt,name=key,proto3" json:"key,omitempty"`
- Badge int32 `protobuf:"varint,7,opt,name=badge,proto3" json:"badge,omitempty"`
- Category string `protobuf:"bytes,8,opt,name=category,proto3" json:"category,omitempty"`
- Alert *Alert `protobuf:"bytes,9,opt,name=alert,proto3" json:"alert,omitempty"`
- Sound string `protobuf:"bytes,10,opt,name=sound,proto3" json:"sound,omitempty"`
- ContentAvailable bool `protobuf:"varint,11,opt,name=contentAvailable,proto3" json:"contentAvailable,omitempty"`
- ThreadID string `protobuf:"bytes,12,opt,name=threadID,proto3" json:"threadID,omitempty"`
- MutableContent bool `protobuf:"varint,13,opt,name=mutableContent,proto3" json:"mutableContent,omitempty"`
- Data *_struct.Struct `protobuf:"bytes,14,opt,name=data,proto3" json:"data,omitempty"`
- Image string `protobuf:"bytes,15,opt,name=image,proto3" json:"image,omitempty"`
- Priority Priority `protobuf:"varint,16,opt,name=Priority,proto3,enum=proto.Priority" json:"Priority,omitempty"`
+ Tokens []string `protobuf:"bytes,1,rep,name=tokens,proto3" json:"tokens,omitempty"`
+ Platform int32 `protobuf:"varint,2,opt,name=platform,proto3" json:"platform,omitempty"`
+ Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
+ Title string `protobuf:"bytes,4,opt,name=title,proto3" json:"title,omitempty"`
+ Topic string `protobuf:"bytes,5,opt,name=topic,proto3" json:"topic,omitempty"`
+ Key string `protobuf:"bytes,6,opt,name=key,proto3" json:"key,omitempty"`
+ Badge int32 `protobuf:"varint,7,opt,name=badge,proto3" json:"badge,omitempty"`
+ Category string `protobuf:"bytes,8,opt,name=category,proto3" json:"category,omitempty"`
+ Alert *Alert `protobuf:"bytes,9,opt,name=alert,proto3" json:"alert,omitempty"`
+ Sound string `protobuf:"bytes,10,opt,name=sound,proto3" json:"sound,omitempty"`
+ ContentAvailable bool `protobuf:"varint,11,opt,name=contentAvailable,proto3" json:"contentAvailable,omitempty"`
+ ThreadID string `protobuf:"bytes,12,opt,name=threadID,proto3" json:"threadID,omitempty"`
+ MutableContent bool `protobuf:"varint,13,opt,name=mutableContent,proto3" json:"mutableContent,omitempty"`
+ Data *structpb.Struct `protobuf:"bytes,14,opt,name=data,proto3" json:"data,omitempty"`
+ Image string `protobuf:"bytes,15,opt,name=image,proto3" json:"image,omitempty"`
+ Priority NotificationRequest_Priority `protobuf:"varint,16,opt,name=priority,proto3,enum=proto.NotificationRequest_Priority" json:"priority,omitempty"`
}
func (x *NotificationRequest) Reset() {
@@ -391,7 +382,7 @@ func (x *NotificationRequest) GetMutableContent() bool {
return false
}
-func (x *NotificationRequest) GetData() *_struct.Struct {
+func (x *NotificationRequest) GetData() *structpb.Struct {
if x != nil {
return x.Data
}
@@ -405,11 +396,11 @@ func (x *NotificationRequest) GetImage() string {
return ""
}
-func (x *NotificationRequest) GetPriority() Priority {
+func (x *NotificationRequest) GetPriority() NotificationRequest_Priority {
if x != nil {
return x.Priority
}
- return Priority_Normal
+ return NotificationRequest_NORMAL
}
type NotificationReply struct {
@@ -585,7 +576,7 @@ var file_gorush_proto_rawDesc = []byte{
0x6f, 0x63, 0x41, 0x72, 0x67, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f,
0x63, 0x41, 0x72, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x4c, 0x6f,
0x63, 0x41, 0x72, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x69, 0x74,
- 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x41, 0x72, 0x67, 0x73, 0x22, 0xed, 0x03, 0x0a, 0x13, 0x4e, 0x6f,
+ 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x41, 0x72, 0x67, 0x73, 0x22, 0xa3, 0x04, 0x0a, 0x13, 0x4e, 0x6f,
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
0x09, 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61,
@@ -613,39 +604,40 @@ var file_gorush_proto_rawDesc = []byte{
0x61, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74,
0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18,
- 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x2b, 0x0a, 0x08,
- 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f,
- 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52,
- 0x08, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x45, 0x0a, 0x11, 0x4e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18,
- 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x6e,
- 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73,
- 0x22, 0x2e, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
- 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
- 0x22, 0x93, 0x01, 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
- 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74,
- 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, 0x0a, 0x0d, 0x53, 0x65,
- 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55,
- 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56,
- 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x45, 0x52,
- 0x56, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x2a, 0x20, 0x0a, 0x08, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69,
- 0x74, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x10, 0x00, 0x12, 0x08,
- 0x0a, 0x04, 0x48, 0x69, 0x67, 0x68, 0x10, 0x01, 0x32, 0x48, 0x0a, 0x06, 0x47, 0x6f, 0x72, 0x75,
- 0x73, 0x68, 0x12, 0x3e, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f,
+ 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, 0x08,
+ 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72,
+ 0x69, 0x74, 0x79, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x20, 0x0a,
+ 0x08, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52,
+ 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, 0x10, 0x01, 0x22,
+ 0x45, 0x0a, 0x11, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+ 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x16,
+ 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06,
+ 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x22, 0x2e, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68,
+ 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07,
+ 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c, 0x74,
+ 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40,
+ 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65,
+ 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69,
+ 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
+ 0x22, 0x3a, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75,
+ 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b,
+ 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4e,
+ 0x4f, 0x54, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x32, 0x48, 0x0a, 0x06,
+ 0x47, 0x6f, 0x72, 0x75, 0x73, 0x68, 0x12, 0x3e, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x1a,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e,
- 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79,
- 0x22, 0x00, 0x32, 0x48, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x3e, 0x0a, 0x05,
- 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65,
- 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43,
- 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x62, 0x06, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x33,
+ 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x32, 0x48, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68,
+ 0x12, 0x3e, 0x0a, 0x05, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61,
+ 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -664,21 +656,21 @@ var (
file_gorush_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
file_gorush_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
file_gorush_proto_goTypes = []interface{}{
- (Priority)(0), // 0: proto.Priority
+ (NotificationRequest_Priority)(0), // 0: proto.NotificationRequest.Priority
(HealthCheckResponse_ServingStatus)(0), // 1: proto.HealthCheckResponse.ServingStatus
(*Alert)(nil), // 2: proto.Alert
(*NotificationRequest)(nil), // 3: proto.NotificationRequest
(*NotificationReply)(nil), // 4: proto.NotificationReply
(*HealthCheckRequest)(nil), // 5: proto.HealthCheckRequest
(*HealthCheckResponse)(nil), // 6: proto.HealthCheckResponse
- (*_struct.Struct)(nil), // 7: google.protobuf.Struct
+ (*structpb.Struct)(nil), // 7: google.protobuf.Struct
}
)
var file_gorush_proto_depIdxs = []int32{
2, // 0: proto.NotificationRequest.alert:type_name -> proto.Alert
7, // 1: proto.NotificationRequest.data:type_name -> google.protobuf.Struct
- 0, // 2: proto.NotificationRequest.Priority:type_name -> proto.Priority
+ 0, // 2: proto.NotificationRequest.priority:type_name -> proto.NotificationRequest.Priority
1, // 3: proto.HealthCheckResponse.status:type_name -> proto.HealthCheckResponse.ServingStatus
3, // 4: proto.Gorush.Send:input_type -> proto.NotificationRequest
5, // 5: proto.Health.Check:input_type -> proto.HealthCheckRequest
@@ -778,155 +770,3 @@ func file_gorush_proto_init() {
file_gorush_proto_goTypes = nil
file_gorush_proto_depIdxs = nil
}
-
-// Reference imports to suppress errors if they are not otherwise used.
-var (
- _ context.Context
- _ grpc.ClientConnInterface
-)
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion6
-
-// GorushClient is the client API for Gorush service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
-type GorushClient interface {
- Send(ctx context.Context, in *NotificationRequest, opts ...grpc.CallOption) (*NotificationReply, error)
-}
-
-type gorushClient struct {
- cc grpc.ClientConnInterface
-}
-
-func NewGorushClient(cc grpc.ClientConnInterface) GorushClient {
- return &gorushClient{cc}
-}
-
-func (c *gorushClient) Send(ctx context.Context, in *NotificationRequest, opts ...grpc.CallOption) (*NotificationReply, error) {
- out := new(NotificationReply)
- err := c.cc.Invoke(ctx, "/proto.Gorush/Send", in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// GorushServer is the server API for Gorush service.
-type GorushServer interface {
- Send(context.Context, *NotificationRequest) (*NotificationReply, error)
-}
-
-// UnimplementedGorushServer can be embedded to have forward compatible implementations.
-type UnimplementedGorushServer struct{}
-
-func (*UnimplementedGorushServer) Send(context.Context, *NotificationRequest) (*NotificationReply, error) {
- return nil, status.Errorf(codes.Unimplemented, "method Send not implemented")
-}
-
-func RegisterGorushServer(s *grpc.Server, srv GorushServer) {
- s.RegisterService(&_Gorush_serviceDesc, srv)
-}
-
-func _Gorush_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(NotificationRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(GorushServer).Send(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/proto.Gorush/Send",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(GorushServer).Send(ctx, req.(*NotificationRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-var _Gorush_serviceDesc = grpc.ServiceDesc{
- ServiceName: "proto.Gorush",
- HandlerType: (*GorushServer)(nil),
- Methods: []grpc.MethodDesc{
- {
- MethodName: "Send",
- Handler: _Gorush_Send_Handler,
- },
- },
- Streams: []grpc.StreamDesc{},
- Metadata: "gorush.proto",
-}
-
-// HealthClient is the client API for Health service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
-type HealthClient interface {
- Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error)
-}
-
-type healthClient struct {
- cc grpc.ClientConnInterface
-}
-
-func NewHealthClient(cc grpc.ClientConnInterface) HealthClient {
- return &healthClient{cc}
-}
-
-func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) {
- out := new(HealthCheckResponse)
- err := c.cc.Invoke(ctx, "/proto.Health/Check", in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// HealthServer is the server API for Health service.
-type HealthServer interface {
- Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error)
-}
-
-// UnimplementedHealthServer can be embedded to have forward compatible implementations.
-type UnimplementedHealthServer struct{}
-
-func (*UnimplementedHealthServer) Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) {
- return nil, status.Errorf(codes.Unimplemented, "method Check not implemented")
-}
-
-func RegisterHealthServer(s *grpc.Server, srv HealthServer) {
- s.RegisterService(&_Health_serviceDesc, srv)
-}
-
-func _Health_Check_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(HealthCheckRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(HealthServer).Check(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/proto.Health/Check",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(HealthServer).Check(ctx, req.(*HealthCheckRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-var _Health_serviceDesc = grpc.ServiceDesc{
- ServiceName: "proto.Health",
- HandlerType: (*HealthServer)(nil),
- Methods: []grpc.MethodDesc{
- {
- MethodName: "Check",
- Handler: _Health_Check_Handler,
- },
- },
- Streams: []grpc.StreamDesc{},
- Metadata: "gorush.proto",
-}
diff --git a/rpc/proto/gorush.proto b/rpc/proto/gorush.proto
index 25238c780..7181c66e9 100644
--- a/rpc/proto/gorush.proto
+++ b/rpc/proto/gorush.proto
@@ -33,10 +33,10 @@ message NotificationRequest {
google.protobuf.Struct data = 14;
string image = 15;
enum Priority {
- Normal = 0;
- High = 1;
+ NORMAL = 0;
+ HIGH = 1;
}
- Priority Priority = 16;
+ Priority priority = 16;
}
message NotificationReply {
diff --git a/rpc/proto/gorush_grpc.pb.go b/rpc/proto/gorush_grpc.pb.go
new file mode 100644
index 000000000..767f79828
--- /dev/null
+++ b/rpc/proto/gorush_grpc.pb.go
@@ -0,0 +1,182 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package proto
+
+import (
+ context "context"
+
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// GorushClient is the client API for Gorush service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type GorushClient interface {
+ Send(ctx context.Context, in *NotificationRequest, opts ...grpc.CallOption) (*NotificationReply, error)
+}
+
+type gorushClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewGorushClient(cc grpc.ClientConnInterface) GorushClient {
+ return &gorushClient{cc}
+}
+
+func (c *gorushClient) Send(ctx context.Context, in *NotificationRequest, opts ...grpc.CallOption) (*NotificationReply, error) {
+ out := new(NotificationReply)
+ err := c.cc.Invoke(ctx, "/proto.Gorush/Send", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// GorushServer is the server API for Gorush service.
+// All implementations should embed UnimplementedGorushServer
+// for forward compatibility
+type GorushServer interface {
+ Send(context.Context, *NotificationRequest) (*NotificationReply, error)
+}
+
+// UnimplementedGorushServer should be embedded to have forward compatible implementations.
+type UnimplementedGorushServer struct{}
+
+func (UnimplementedGorushServer) Send(context.Context, *NotificationRequest) (*NotificationReply, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Send not implemented")
+}
+
+// UnsafeGorushServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to GorushServer will
+// result in compilation errors.
+type UnsafeGorushServer interface {
+ mustEmbedUnimplementedGorushServer()
+}
+
+func RegisterGorushServer(s grpc.ServiceRegistrar, srv GorushServer) {
+ s.RegisterService(&Gorush_ServiceDesc, srv)
+}
+
+func _Gorush_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(NotificationRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(GorushServer).Send(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/proto.Gorush/Send",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(GorushServer).Send(ctx, req.(*NotificationRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// Gorush_ServiceDesc is the grpc.ServiceDesc for Gorush service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Gorush_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "proto.Gorush",
+ HandlerType: (*GorushServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "Send",
+ Handler: _Gorush_Send_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "gorush.proto",
+}
+
+// HealthClient is the client API for Health service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type HealthClient interface {
+ Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error)
+}
+
+type healthClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewHealthClient(cc grpc.ClientConnInterface) HealthClient {
+ return &healthClient{cc}
+}
+
+func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) {
+ out := new(HealthCheckResponse)
+ err := c.cc.Invoke(ctx, "/proto.Health/Check", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// HealthServer is the server API for Health service.
+// All implementations should embed UnimplementedHealthServer
+// for forward compatibility
+type HealthServer interface {
+ Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error)
+}
+
+// UnimplementedHealthServer should be embedded to have forward compatible implementations.
+type UnimplementedHealthServer struct{}
+
+func (UnimplementedHealthServer) Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Check not implemented")
+}
+
+// UnsafeHealthServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to HealthServer will
+// result in compilation errors.
+type UnsafeHealthServer interface {
+ mustEmbedUnimplementedHealthServer()
+}
+
+func RegisterHealthServer(s grpc.ServiceRegistrar, srv HealthServer) {
+ s.RegisterService(&Health_ServiceDesc, srv)
+}
+
+func _Health_Check_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(HealthCheckRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(HealthServer).Check(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/proto.Health/Check",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(HealthServer).Check(ctx, req.(*HealthCheckRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// Health_ServiceDesc is the grpc.ServiceDesc for Health service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Health_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "proto.Health",
+ HandlerType: (*HealthServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "Check",
+ Handler: _Health_Check_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "gorush.proto",
+}
diff --git a/rpc/server.go b/rpc/server.go
index e6b6b8e92..d68831523 100644
--- a/rpc/server.go
+++ b/rpc/server.go
@@ -6,7 +6,10 @@ import (
"strings"
"sync"
- "github.com/appleboy/gorush/gorush"
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/core"
+ "github.com/appleboy/gorush/logx"
+ "github.com/appleboy/gorush/notify"
"github.com/appleboy/gorush/rpc/proto"
"google.golang.org/grpc"
@@ -17,14 +20,16 @@ import (
// Server is used to implement gorush grpc server.
type Server struct {
- mu sync.Mutex
+ cfg *config.ConfYaml
+ mu sync.Mutex
// statusMap stores the serving status of the services this Server monitors.
statusMap map[string]proto.HealthCheckResponse_ServingStatus
}
// NewServer returns a new Server.
-func NewServer() *Server {
+func NewServer(cfg *config.ConfYaml) *Server {
return &Server{
+ cfg: cfg,
statusMap: make(map[string]proto.HealthCheckResponse_ServingStatus),
}
}
@@ -50,7 +55,7 @@ func (s *Server) Check(ctx context.Context, in *proto.HealthCheckRequest) (*prot
// Send implements helloworld.GreeterServer
func (s *Server) Send(ctx context.Context, in *proto.NotificationRequest) (*proto.NotificationReply, error) {
badge := int(in.Badge)
- notification := gorush.PushNotification{
+ notification := notify.PushNotification{
Platform: int(in.Platform),
Tokens: in.Tokens,
Message: in.Message,
@@ -70,12 +75,12 @@ func (s *Server) Send(ctx context.Context, in *proto.NotificationRequest) (*prot
notification.Badge = &badge
}
- if in.Topic != "" && in.Platform == gorush.PlatFormAndroid {
+ if in.Topic != "" && in.Platform == core.PlatFormAndroid {
notification.To = in.Topic
}
if in.Alert != nil {
- notification.Alert = gorush.Alert{
+ notification.Alert = notify.Alert{
Title: in.Alert.Title,
Body: in.Alert.Body,
Subtitle: in.Alert.Subtitle,
@@ -96,7 +101,12 @@ func (s *Server) Send(ctx context.Context, in *proto.NotificationRequest) (*prot
}
}
- go gorush.SendNotification(ctx, notification)
+ go func() {
+ _, err := notify.SendNotification(¬ification, s.cfg)
+ if err != nil {
+ logx.LogError.Error(err)
+ }
+ }()
return &proto.NotificationReply{
Success: true,
@@ -105,35 +115,33 @@ func (s *Server) Send(ctx context.Context, in *proto.NotificationRequest) (*prot
}
// RunGRPCServer run gorush grpc server
-func RunGRPCServer(ctx context.Context) error {
- if !gorush.PushConf.GRPC.Enabled {
- gorush.LogAccess.Info("gRPC server is disabled.")
+func RunGRPCServer(ctx context.Context, cfg *config.ConfYaml) error {
+ if !cfg.GRPC.Enabled {
+ logx.LogAccess.Info("gRPC server is disabled.")
return nil
}
s := grpc.NewServer()
- rpcSrv := NewServer()
+ rpcSrv := NewServer(cfg)
proto.RegisterGorushServer(s, rpcSrv)
proto.RegisterHealthServer(s, rpcSrv)
// Register reflection service on gRPC server.
reflection.Register(s)
- lis, err := net.Listen("tcp", ":"+gorush.PushConf.GRPC.Port)
+ lis, err := net.Listen("tcp", ":"+cfg.GRPC.Port)
if err != nil {
- gorush.LogError.Fatalln(err)
+ logx.LogError.Fatalln(err)
return err
}
- gorush.LogAccess.Info("gRPC server is running on " + gorush.PushConf.GRPC.Port + " port.")
+ logx.LogAccess.Info("gRPC server is running on " + cfg.GRPC.Port + " port.")
go func() {
- select {
- case <-ctx.Done():
- s.GracefulStop() // graceful shutdown
- gorush.LogAccess.Info("shutdown the gRPC server")
- }
+ <-ctx.Done()
+ s.GracefulStop() // graceful shutdown
+ logx.LogAccess.Info("shutdown the gRPC server")
}()
if err = s.Serve(lis); err != nil {
- gorush.LogError.Fatalln(err)
+ logx.LogError.Fatalln(err)
}
return err
}
diff --git a/rpc/server_test.go b/rpc/server_test.go
index 173637b5c..5d72061ce 100644
--- a/rpc/server_test.go
+++ b/rpc/server_test.go
@@ -4,7 +4,7 @@ import (
"context"
"testing"
- "github.com/appleboy/gorush/gorush"
+ "github.com/appleboy/gorush/config"
"google.golang.org/grpc"
"google.golang.org/grpc/connectivity"
@@ -12,17 +12,22 @@ import (
const gRPCAddr = "localhost:9000"
+func initTest() *config.ConfYaml {
+ cfg, _ := config.LoadConf()
+ cfg.Core.Mode = "test"
+ return cfg
+}
+
func TestGracefulShutDownGRPCServer(t *testing.T) {
- // server configs
- gorush.InitLog()
- gorush.PushConf.GRPC.Enabled = true
- gorush.PushConf.GRPC.Port = "9000"
- gorush.PushConf.Log.Format = "json"
+ cfg := initTest()
+ cfg.GRPC.Enabled = true
+ cfg.GRPC.Port = "9000"
+ cfg.Log.Format = "json"
// Run gRPC server
ctx, gRPCContextCancel := context.WithCancel(context.Background())
go func() {
- if err := RunGRPCServer(ctx); err != nil {
+ if err := RunGRPCServer(ctx, cfg); err != nil {
panic(err)
}
}()
diff --git a/status/status.go b/status/status.go
new file mode 100644
index 000000000..68b423d7d
--- /dev/null
+++ b/status/status.go
@@ -0,0 +1,84 @@
+package status
+
+import (
+ "errors"
+
+ "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/logx"
+ "github.com/appleboy/gorush/storage"
+ "github.com/appleboy/gorush/storage/badger"
+ "github.com/appleboy/gorush/storage/boltdb"
+ "github.com/appleboy/gorush/storage/buntdb"
+ "github.com/appleboy/gorush/storage/leveldb"
+ "github.com/appleboy/gorush/storage/memory"
+ "github.com/appleboy/gorush/storage/redis"
+
+ "github.com/thoas/stats"
+)
+
+// Stats provide response time, status code count, etc.
+var Stats *stats.Stats
+
+// StatStorage implements the storage interface
+var StatStorage storage.Storage
+
+// App is status structure
+type App struct {
+ Version string `json:"version"`
+ QueueMax int `json:"queue_max"`
+ QueueUsage int `json:"queue_usage"`
+ TotalCount int64 `json:"total_count"`
+ Ios IosStatus `json:"ios"`
+ Android AndroidStatus `json:"android"`
+ Huawei HuaweiStatus `json:"huawei"`
+}
+
+// AndroidStatus is android structure
+type AndroidStatus struct {
+ PushSuccess int64 `json:"push_success"`
+ PushError int64 `json:"push_error"`
+}
+
+// IosStatus is iOS structure
+type IosStatus struct {
+ PushSuccess int64 `json:"push_success"`
+ PushError int64 `json:"push_error"`
+}
+
+// HuaweiStatus is huawei structure
+type HuaweiStatus struct {
+ PushSuccess int64 `json:"push_success"`
+ PushError int64 `json:"push_error"`
+}
+
+// InitAppStatus for initialize app status
+func InitAppStatus(conf *config.ConfYaml) error {
+ logx.LogAccess.Info("Init App Status Engine as ", conf.Stat.Engine)
+ switch conf.Stat.Engine {
+ case "memory":
+ StatStorage = memory.New()
+ case "redis":
+ StatStorage = redis.New(conf)
+ case "boltdb":
+ StatStorage = boltdb.New(conf)
+ case "buntdb":
+ StatStorage = buntdb.New(conf)
+ case "leveldb":
+ StatStorage = leveldb.New(conf)
+ case "badger":
+ StatStorage = badger.New(conf)
+ default:
+ logx.LogError.Error("storage error: can't find storage driver")
+ return errors.New("can't find storage driver")
+ }
+
+ if err := StatStorage.Init(); err != nil {
+ logx.LogError.Error("storage error: " + err.Error())
+
+ return err
+ }
+
+ Stats = stats.New()
+
+ return nil
+}
diff --git a/gorush/status_test.go b/status/status_test.go
similarity index 84%
rename from gorush/status_test.go
rename to status/status_test.go
index 3f59f4a76..b057f4341 100644
--- a/gorush/status_test.go
+++ b/status/status_test.go
@@ -1,15 +1,23 @@
-package gorush
+package status
import (
+ "os"
"testing"
"time"
+ "github.com/appleboy/gorush/config"
+
"github.com/stretchr/testify/assert"
)
+func TestMain(m *testing.M) {
+ os.Exit(m.Run())
+}
+
func TestStorageDriverExist(t *testing.T) {
- PushConf.Stat.Engine = "Test"
- err := InitAppStatus()
+ cfg, _ := config.LoadConf()
+ cfg.Stat.Engine = "Test"
+ err := InitAppStatus(cfg)
assert.Error(t, err)
}
@@ -18,8 +26,9 @@ func TestStatForMemoryEngine(t *testing.T) {
time.Sleep(5 * time.Second)
var val int64
- PushConf.Stat.Engine = "memory"
- err := InitAppStatus()
+ cfg, _ := config.LoadConf()
+ cfg.Stat.Engine = "memory"
+ err := InitAppStatus(cfg)
assert.Nil(t, err)
StatStorage.AddTotalCount(100)
@@ -41,31 +50,34 @@ func TestStatForMemoryEngine(t *testing.T) {
}
func TestRedisServerSuccess(t *testing.T) {
- PushConf.Stat.Engine = "redis"
- PushConf.Stat.Redis.Addr = "redis:6379"
+ cfg, _ := config.LoadConf()
+ cfg.Stat.Engine = "redis"
+ cfg.Stat.Redis.Addr = "redis:6379"
- err := InitAppStatus()
+ err := InitAppStatus(cfg)
assert.NoError(t, err)
}
func TestRedisServerError(t *testing.T) {
- PushConf.Stat.Engine = "redis"
- PushConf.Stat.Redis.Addr = "redis:6370"
+ cfg, _ := config.LoadConf()
+ cfg.Stat.Engine = "redis"
+ cfg.Stat.Redis.Addr = "redis:6370"
- err := InitAppStatus()
+ err := InitAppStatus(cfg)
assert.Error(t, err)
}
func TestStatForRedisEngine(t *testing.T) {
var val int64
- PushConf.Stat.Engine = "redis"
- PushConf.Stat.Redis.Addr = "redis:6379"
- err := InitAppStatus()
+ cfg, _ := config.LoadConf()
+ cfg.Stat.Engine = "redis"
+ cfg.Stat.Redis.Addr = "redis:6379"
+ err := InitAppStatus(cfg)
assert.Nil(t, err)
- StatStorage.Init()
+ assert.Nil(t, StatStorage.Init())
StatStorage.Reset()
StatStorage.AddTotalCount(100)
@@ -89,7 +101,8 @@ func TestStatForRedisEngine(t *testing.T) {
func TestDefaultEngine(t *testing.T) {
var val int64
// defaul engine as memory
- err := InitAppStatus()
+ cfg, _ := config.LoadConf()
+ err := InitAppStatus(cfg)
assert.Nil(t, err)
StatStorage.Reset()
@@ -114,8 +127,10 @@ func TestDefaultEngine(t *testing.T) {
func TestStatForBoltDBEngine(t *testing.T) {
var val int64
- PushConf.Stat.Engine = "boltdb"
- InitAppStatus()
+ cfg, _ := config.LoadConf()
+ cfg.Stat.Engine = "boltdb"
+ err := InitAppStatus(cfg)
+ assert.Nil(t, err)
StatStorage.Reset()
@@ -139,7 +154,7 @@ func TestStatForBoltDBEngine(t *testing.T) {
// func TestStatForBuntDBEngine(t *testing.T) {
// var val int64
-// PushConf.Stat.Engine = "buntdb"
+// cfg.Stat.Engine = "buntdb"
// err := InitAppStatus()
// assert.Nil(t, err)
@@ -165,7 +180,7 @@ func TestStatForBoltDBEngine(t *testing.T) {
// func TestStatForLevelDBEngine(t *testing.T) {
// var val int64
-// PushConf.Stat.Engine = "leveldb"
+// cfg.Stat.Engine = "leveldb"
// err := InitAppStatus()
// assert.Nil(t, err)
@@ -191,7 +206,7 @@ func TestStatForBoltDBEngine(t *testing.T) {
// func TestStatForBadgerEngine(t *testing.T) {
// var val int64
-// PushConf.Stat.Engine = "badger"
+// cfg.Stat.Engine = "badger"
// err := InitAppStatus()
// assert.Nil(t, err)
diff --git a/storage/badger/badger.go b/storage/badger/badger.go
index 254a810d9..b0b02d1e2 100644
--- a/storage/badger/badger.go
+++ b/storage/badger/badger.go
@@ -1,7 +1,6 @@
package badger
import (
- "fmt"
"log"
"os"
"strconv"
@@ -9,11 +8,11 @@ import (
"github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/storage"
- "github.com/dgraph-io/badger/v2"
+ "github.com/dgraph-io/badger/v3"
)
// New func implements the storage interface for gorush (https://github.com/appleboy/gorush)
-func New(config config.ConfYaml) *Storage {
+func New(config *config.ConfYaml) *Storage {
return &Storage{
config: config,
}
@@ -21,7 +20,7 @@ func New(config config.ConfYaml) *Storage {
// Storage is interface structure
type Storage struct {
- config config.ConfYaml
+ config *config.ConfYaml
opts badger.Options
name string
db *badger.DB
@@ -84,7 +83,7 @@ func (s *Storage) getBadger(key string, count *int64) {
return err
}
- i, err := strconv.ParseInt(fmt.Sprintf("%s", val), 10, 64)
+ i, err := strconv.ParseInt(string(val), 10, 64)
if err != nil {
return err
}
diff --git a/storage/badger/badger_test.go b/storage/badger/badger_test.go
index 033e11d10..3c26b270c 100644
--- a/storage/badger/badger_test.go
+++ b/storage/badger/badger_test.go
@@ -3,16 +3,16 @@ package badger
import (
"testing"
- c "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/config"
"github.com/stretchr/testify/assert"
)
func TestBadgerEngine(t *testing.T) {
var val int64
- config, _ := c.LoadConf("")
+ cfg, _ := config.LoadConf()
- badger := New(config)
+ badger := New(cfg)
err := badger.Init()
assert.Nil(t, err)
badger.Reset()
diff --git a/storage/boltdb/boltdb.go b/storage/boltdb/boltdb.go
index b1f3425cd..1ae26a942 100644
--- a/storage/boltdb/boltdb.go
+++ b/storage/boltdb/boltdb.go
@@ -10,7 +10,7 @@ import (
)
// New func implements the storage interface for gorush (https://github.com/appleboy/gorush)
-func New(config config.ConfYaml) *Storage {
+func New(config *config.ConfYaml) *Storage {
return &Storage{
config: config,
}
@@ -18,7 +18,7 @@ func New(config config.ConfYaml) *Storage {
// Storage is interface structure
type Storage struct {
- config config.ConfYaml
+ config *config.ConfYaml
db *storm.DB
}
diff --git a/storage/boltdb/boltdb_test.go b/storage/boltdb/boltdb_test.go
index 8ea2670f6..07e16873b 100644
--- a/storage/boltdb/boltdb_test.go
+++ b/storage/boltdb/boltdb_test.go
@@ -3,16 +3,16 @@ package boltdb
import (
"testing"
- c "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/config"
"github.com/stretchr/testify/assert"
)
func TestBoltDBEngine(t *testing.T) {
var val int64
- config, _ := c.LoadConf("")
+ cfg, _ := config.LoadConf()
- boltDB := New(config)
+ boltDB := New(cfg)
err := boltDB.Init()
assert.Nil(t, err)
boltDB.Reset()
diff --git a/storage/buntdb/buntdb.go b/storage/buntdb/buntdb.go
index b09c0bb12..5bcd30ddb 100644
--- a/storage/buntdb/buntdb.go
+++ b/storage/buntdb/buntdb.go
@@ -12,7 +12,7 @@ import (
)
// New func implements the storage interface for gorush (https://github.com/appleboy/gorush)
-func New(config config.ConfYaml) *Storage {
+func New(config *config.ConfYaml) *Storage {
return &Storage{
config: config,
}
@@ -20,7 +20,7 @@ func New(config config.ConfYaml) *Storage {
// Storage is interface structure
type Storage struct {
- config config.ConfYaml
+ config *config.ConfYaml
db *buntdb.DB
}
diff --git a/storage/buntdb/buntdb_test.go b/storage/buntdb/buntdb_test.go
index 5a65f0331..022ce4214 100644
--- a/storage/buntdb/buntdb_test.go
+++ b/storage/buntdb/buntdb_test.go
@@ -4,21 +4,21 @@ import (
"os"
"testing"
- c "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/config"
"github.com/stretchr/testify/assert"
)
func TestBuntDBEngine(t *testing.T) {
var val int64
- config, _ := c.LoadConf("")
+ cfg, _ := config.LoadConf()
- if _, err := os.Stat(config.Stat.BuntDB.Path); os.IsNotExist(err) {
- err := os.RemoveAll(config.Stat.BuntDB.Path)
+ if _, err := os.Stat(cfg.Stat.BuntDB.Path); os.IsNotExist(err) {
+ err := os.RemoveAll(cfg.Stat.BuntDB.Path)
assert.Nil(t, err)
}
- buntDB := New(config)
+ buntDB := New(cfg)
err := buntDB.Init()
assert.Nil(t, err)
buntDB.Reset()
diff --git a/storage/leveldb/leveldb.go b/storage/leveldb/leveldb.go
index 82d36015e..8164fc062 100644
--- a/storage/leveldb/leveldb.go
+++ b/storage/leveldb/leveldb.go
@@ -21,7 +21,7 @@ func (s *Storage) getLevelDB(key string, count *int64) {
}
// New func implements the storage interface for gorush (https://github.com/appleboy/gorush)
-func New(config config.ConfYaml) *Storage {
+func New(config *config.ConfYaml) *Storage {
return &Storage{
config: config,
}
@@ -29,7 +29,7 @@ func New(config config.ConfYaml) *Storage {
// Storage is interface structure
type Storage struct {
- config config.ConfYaml
+ config *config.ConfYaml
db *leveldb.DB
}
diff --git a/storage/leveldb/leveldb_test.go b/storage/leveldb/leveldb_test.go
index aa6918939..826821481 100644
--- a/storage/leveldb/leveldb_test.go
+++ b/storage/leveldb/leveldb_test.go
@@ -4,21 +4,21 @@ import (
"os"
"testing"
- c "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/config"
"github.com/stretchr/testify/assert"
)
func TestLevelDBEngine(t *testing.T) {
var val int64
- config, _ := c.LoadConf("")
+ cfg, _ := config.LoadConf()
- if _, err := os.Stat(config.Stat.LevelDB.Path); os.IsNotExist(err) {
- err = os.RemoveAll(config.Stat.LevelDB.Path)
+ if _, err := os.Stat(cfg.Stat.LevelDB.Path); os.IsNotExist(err) {
+ err = os.RemoveAll(cfg.Stat.LevelDB.Path)
assert.Nil(t, err)
}
- levelDB := New(config)
+ levelDB := New(cfg)
err := levelDB.Init()
assert.Nil(t, err)
levelDB.Reset()
diff --git a/storage/memory/memory.go b/storage/memory/memory.go
index 7c0e96139..4b3c5ff20 100644
--- a/storage/memory/memory.go
+++ b/storage/memory/memory.go
@@ -4,7 +4,7 @@ import (
"sync/atomic"
)
-// StatusApp is app status structure
+// statApp is app status structure
type statApp struct {
TotalCount int64 `json:"total_count"`
Ios IosStatus `json:"ios"`
diff --git a/storage/redis/redis.go b/storage/redis/redis.go
index 7df20e409..45001a1f8 100644
--- a/storage/redis/redis.go
+++ b/storage/redis/redis.go
@@ -1,97 +1,119 @@
package redis
import (
+ "context"
+ "fmt"
+ "reflect"
"strconv"
+ "strings"
"github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/storage"
- "github.com/go-redis/redis/v7"
+ "github.com/go-redis/redis/v8"
)
// New func implements the storage interface for gorush (https://github.com/appleboy/gorush)
-func New(config config.ConfYaml) *Storage {
+func New(config *config.ConfYaml) *Storage {
return &Storage{
+ ctx: context.Background(),
config: config,
}
}
func (s *Storage) getInt64(key string, count *int64) {
- val, _ := s.client.Get(key).Result()
+ val, _ := s.client.Get(s.ctx, key).Result()
*count, _ = strconv.ParseInt(val, 10, 64)
}
// Storage is interface structure
type Storage struct {
- config config.ConfYaml
- client *redis.Client
+ ctx context.Context
+ config *config.ConfYaml
+ client redis.Cmdable
}
// Init client storage.
func (s *Storage) Init() error {
- s.client = redis.NewClient(&redis.Options{
- Addr: s.config.Stat.Redis.Addr,
- Password: s.config.Stat.Redis.Password,
- DB: s.config.Stat.Redis.DB,
- })
- _, err := s.client.Ping().Result()
+ if s.config.Stat.Redis.Cluster {
+ s.client = redis.NewClusterClient(&redis.ClusterOptions{
+ Addrs: strings.Split(s.config.Stat.Redis.Addr, ","),
+ Password: s.config.Stat.Redis.Password,
+ })
+ } else {
+ s.client = redis.NewClient(&redis.Options{
+ Addr: s.config.Stat.Redis.Addr,
+ Password: s.config.Stat.Redis.Password,
+ DB: s.config.Stat.Redis.DB,
+ })
+ }
+
+ if err := s.client.Ping(s.ctx).Err(); err != nil {
+ return err
+ }
- return err
+ return nil
}
// Close the storage connection
func (s *Storage) Close() error {
- if s.client == nil {
+ switch v := s.client.(type) {
+ case *redis.Client:
+ return v.Close()
+ case *redis.ClusterClient:
+ return v.Close()
+ case nil:
return nil
+ default:
+ // this will not happen anyway, unless we mishandle it on `Init`
+ panic(fmt.Sprintf("invalid redis client: %v", reflect.TypeOf(v)))
}
-
- return s.client.Close()
}
// Reset Client storage.
func (s *Storage) Reset() {
- s.client.Set(storage.TotalCountKey, int64(0), 0)
- s.client.Set(storage.IosSuccessKey, int64(0), 0)
- s.client.Set(storage.IosErrorKey, int64(0), 0)
- s.client.Set(storage.AndroidSuccessKey, int64(0), 0)
- s.client.Set(storage.AndroidErrorKey, int64(0), 0)
- s.client.Set(storage.HuaweiSuccessKey, int64(0), 0)
- s.client.Set(storage.HuaweiErrorKey, int64(0), 0)
+ s.client.Set(s.ctx, storage.TotalCountKey, int64(0), 0)
+ s.client.Set(s.ctx, storage.IosSuccessKey, int64(0), 0)
+ s.client.Set(s.ctx, storage.IosErrorKey, int64(0), 0)
+ s.client.Set(s.ctx, storage.AndroidSuccessKey, int64(0), 0)
+ s.client.Set(s.ctx, storage.AndroidErrorKey, int64(0), 0)
+ s.client.Set(s.ctx, storage.HuaweiSuccessKey, int64(0), 0)
+ s.client.Set(s.ctx, storage.HuaweiErrorKey, int64(0), 0)
}
// AddTotalCount record push notification count.
func (s *Storage) AddTotalCount(count int64) {
- s.client.IncrBy(storage.TotalCountKey, count)
+ s.client.IncrBy(s.ctx, storage.TotalCountKey, count)
}
// AddIosSuccess record counts of success iOS push notification.
func (s *Storage) AddIosSuccess(count int64) {
- s.client.IncrBy(storage.IosSuccessKey, count)
+ s.client.IncrBy(s.ctx, storage.IosSuccessKey, count)
}
// AddIosError record counts of error iOS push notification.
func (s *Storage) AddIosError(count int64) {
- s.client.IncrBy(storage.IosErrorKey, count)
+ s.client.IncrBy(s.ctx, storage.IosErrorKey, count)
}
// AddAndroidSuccess record counts of success Android push notification.
func (s *Storage) AddAndroidSuccess(count int64) {
- s.client.IncrBy(storage.AndroidSuccessKey, count)
+ s.client.IncrBy(s.ctx, storage.AndroidSuccessKey, count)
}
// AddAndroidError record counts of error Android push notification.
func (s *Storage) AddAndroidError(count int64) {
- s.client.IncrBy(storage.AndroidErrorKey, count)
+ s.client.IncrBy(s.ctx, storage.AndroidErrorKey, count)
}
// AddHuaweiSuccess record counts of success Android push notification.
func (s *Storage) AddHuaweiSuccess(count int64) {
- s.client.IncrBy(storage.HuaweiSuccessKey, count)
+ s.client.IncrBy(s.ctx, storage.HuaweiSuccessKey, count)
}
// AddHuaweiError record counts of error Android push notification.
func (s *Storage) AddHuaweiError(count int64) {
- s.client.IncrBy(storage.HuaweiErrorKey, count)
+ s.client.IncrBy(s.ctx, storage.HuaweiErrorKey, count)
}
// GetTotalCount show counts of all notification.
diff --git a/storage/redis/redis_test.go b/storage/redis/redis_test.go
index 3075df796..0f3107206 100644
--- a/storage/redis/redis_test.go
+++ b/storage/redis/redis_test.go
@@ -4,15 +4,15 @@ import (
"sync"
"testing"
- c "github.com/appleboy/gorush/config"
+ "github.com/appleboy/gorush/config"
"github.com/stretchr/testify/assert"
)
func TestRedisServerError(t *testing.T) {
- config, _ := c.LoadConf("")
- config.Stat.Redis.Addr = "redis:6370"
+ cfg, _ := config.LoadConf()
+ cfg.Stat.Redis.Addr = "redis:6370"
- redis := New(config)
+ redis := New(cfg)
err := redis.Init()
assert.Error(t, err)
@@ -21,10 +21,10 @@ func TestRedisServerError(t *testing.T) {
func TestRedisEngine(t *testing.T) {
var val int64
- config, _ := c.LoadConf("")
- config.Stat.Redis.Addr = "redis:6379"
+ cfg, _ := config.LoadConf()
+ cfg.Stat.Redis.Addr = "redis:6379"
- redis := New(config)
+ redis := New(cfg)
err := redis.Init()
assert.Nil(t, err)
redis.Reset()