mirror of
https://github.com/easychen/pushdeer.git
synced 2025-01-10 15:05:27 +08:00
add gorush-with-mipush
This commit is contained in:
parent
16ccf6c247
commit
ea79289d43
BIN
push/gorush-with-mipush/bin/gorush
Executable file
BIN
push/gorush-with-mipush/bin/gorush
Executable file
Binary file not shown.
31
push/gorush-with-mipush/src/.deepsource.toml
Normal file
31
push/gorush-with-mipush/src/.deepsource.toml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
version = 1
|
||||||
|
|
||||||
|
[[analyzers]]
|
||||||
|
name = "go"
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[analyzers.meta]
|
||||||
|
import_paths = ["github.com/appleboy/gorush"]
|
||||||
|
|
||||||
|
[[analyzers]]
|
||||||
|
name = "docker"
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[analyzers.meta]
|
||||||
|
dockerfile_paths = ["docker/**"]
|
||||||
|
|
||||||
|
[[analyzers]]
|
||||||
|
name = "test-coverage"
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[[analyzers]]
|
||||||
|
name = "secrets"
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
test_patterns = [
|
||||||
|
"**/**_test.go",
|
||||||
|
]
|
||||||
|
|
||||||
|
exclude_patterns = [
|
||||||
|
"**/examples/**"
|
||||||
|
]
|
2
push/gorush-with-mipush/src/.dockerignore
Normal file
2
push/gorush-with-mipush/src/.dockerignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!release/
|
16
push/gorush-with-mipush/src/.drone.jsonnet
Normal file
16
push/gorush-with-mipush/src/.drone.jsonnet
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
local pipeline = import 'pipeline.libsonnet';
|
||||||
|
local name = 'gorush';
|
||||||
|
|
||||||
|
[
|
||||||
|
pipeline.test,
|
||||||
|
pipeline.build(name, 'linux', 'amd64'),
|
||||||
|
pipeline.build(name, 'linux', 'arm64'),
|
||||||
|
pipeline.build(name, 'linux', 'arm'),
|
||||||
|
pipeline.release,
|
||||||
|
pipeline.notifications(depends_on=[
|
||||||
|
'linux-amd64',
|
||||||
|
'linux-arm64',
|
||||||
|
'linux-arm',
|
||||||
|
'release-binary',
|
||||||
|
]),
|
||||||
|
]
|
340
push/gorush-with-mipush/src/.drone.yml
Normal file
340
push/gorush-with-mipush/src/.drone.yml
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: testing
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: lint
|
||||||
|
pull: always
|
||||||
|
image: golangci/golangci-lint:v1.41.1
|
||||||
|
commands:
|
||||||
|
- golangci-lint run -v
|
||||||
|
volumes:
|
||||||
|
- name: gopath
|
||||||
|
path: /go
|
||||||
|
|
||||||
|
- name: embedmd
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- make embedmd
|
||||||
|
volumes:
|
||||||
|
- name: gopath
|
||||||
|
path: /go
|
||||||
|
|
||||||
|
- name: hadolint
|
||||||
|
pull: always
|
||||||
|
image: hadolint/hadolint:latest-debian
|
||||||
|
commands:
|
||||||
|
- hadolint --version
|
||||||
|
- hadolint docker/Dockerfile.linux.amd64
|
||||||
|
- hadolint docker/Dockerfile.linux.arm64
|
||||||
|
- hadolint docker/Dockerfile.linux.arm
|
||||||
|
volumes:
|
||||||
|
- name: gopath
|
||||||
|
path: /go
|
||||||
|
|
||||||
|
- name: test
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- make test
|
||||||
|
environment:
|
||||||
|
ANDROID_API_KEY:
|
||||||
|
from_secret: android_api_key
|
||||||
|
ANDROID_TEST_TOKEN:
|
||||||
|
from_secret: android_test_token
|
||||||
|
volumes:
|
||||||
|
- name: gopath
|
||||||
|
path: /go
|
||||||
|
|
||||||
|
- name: codecov
|
||||||
|
pull: always
|
||||||
|
image: robertstettner/drone-codecov
|
||||||
|
settings:
|
||||||
|
token:
|
||||||
|
from_secret: codecov_token
|
||||||
|
|
||||||
|
services:
|
||||||
|
- name: redis
|
||||||
|
image: redis
|
||||||
|
|
||||||
|
- name: nsq
|
||||||
|
image: nsqio/nsq
|
||||||
|
commands:
|
||||||
|
- /nsqd
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: gopath
|
||||||
|
temp: {}
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: linux-amd64
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build-push
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/amd64/gorush
|
||||||
|
environment:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
exclude:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
- name: build-tag
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- go build -v -ldflags '-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/amd64/gorush
|
||||||
|
environment:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
- name: executable
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- ./release/linux/amd64/gorush --help
|
||||||
|
|
||||||
|
- name: publish
|
||||||
|
pull: always
|
||||||
|
image: plugins/docker:linux-amd64
|
||||||
|
settings:
|
||||||
|
auto_tag: true
|
||||||
|
auto_tag_suffix: linux-amd64
|
||||||
|
cache_from: appleboy/gorush
|
||||||
|
daemon_off: false
|
||||||
|
dockerfile: docker/Dockerfile.linux.amd64
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
repo: appleboy/gorush
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
exclude:
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/heads/master
|
||||||
|
- refs/pull/**
|
||||||
|
- refs/tags/**
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- testing
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: linux-arm64
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: arm64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build-push
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm64/gorush
|
||||||
|
environment:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
exclude:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
- name: build-tag
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- go build -v -ldflags '-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm64/gorush
|
||||||
|
environment:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
- name: executable
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- ./release/linux/arm64/gorush --help
|
||||||
|
|
||||||
|
- name: publish
|
||||||
|
pull: always
|
||||||
|
image: plugins/docker:linux-arm64
|
||||||
|
settings:
|
||||||
|
auto_tag: true
|
||||||
|
auto_tag_suffix: linux-arm64
|
||||||
|
cache_from: appleboy/gorush
|
||||||
|
daemon_off: false
|
||||||
|
dockerfile: docker/Dockerfile.linux.arm64
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
repo: appleboy/gorush
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
exclude:
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/heads/master
|
||||||
|
- refs/pull/**
|
||||||
|
- refs/tags/**
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- testing
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: linux-arm
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: arm
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build-push
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm/gorush
|
||||||
|
environment:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
exclude:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
- name: build-tag
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- go build -v -ldflags '-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm/gorush
|
||||||
|
environment:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
- name: executable
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- ./release/linux/arm/gorush --help
|
||||||
|
|
||||||
|
- name: publish
|
||||||
|
pull: always
|
||||||
|
image: plugins/docker:linux-arm
|
||||||
|
settings:
|
||||||
|
auto_tag: true
|
||||||
|
auto_tag_suffix: linux-arm
|
||||||
|
cache_from: appleboy/gorush
|
||||||
|
daemon_off: false
|
||||||
|
dockerfile: docker/Dockerfile.linux.arm
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
repo: appleboy/gorush
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
exclude:
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/heads/master
|
||||||
|
- refs/pull/**
|
||||||
|
- refs/tags/**
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- testing
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: release-binary
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build-all-binary
|
||||||
|
pull: always
|
||||||
|
image: golang:1.17
|
||||||
|
commands:
|
||||||
|
- make release
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
- name: deploy-all-binary
|
||||||
|
pull: always
|
||||||
|
image: plugins/github-release
|
||||||
|
settings:
|
||||||
|
api_key:
|
||||||
|
from_secret: github_release_api_key
|
||||||
|
files:
|
||||||
|
- dist/release/*
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/tags/**
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- testing
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: notifications
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: manifest
|
||||||
|
pull: always
|
||||||
|
image: plugins/manifest
|
||||||
|
settings:
|
||||||
|
ignore_missing: true
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
spec: docker/manifest.tmpl
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/heads/master
|
||||||
|
- refs/tags/**
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- linux-amd64
|
||||||
|
- linux-arm64
|
||||||
|
- linux-arm
|
||||||
|
- release-binary
|
||||||
|
|
||||||
|
...
|
42
push/gorush-with-mipush/src/.editorconfig
Normal file
42
push/gorush-with-mipush/src/.editorconfig
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# unifying the coding style for different editors and IDEs => editorconfig.org
|
||||||
|
|
||||||
|
; indicate this is the root of the project
|
||||||
|
root = true
|
||||||
|
|
||||||
|
###########################################################
|
||||||
|
; common
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
|
||||||
|
end_of_line = LF
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
###########################################################
|
||||||
|
; make
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[makefile]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
###########################################################
|
||||||
|
; markdown
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
###########################################################
|
||||||
|
; golang
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
[*.go]
|
||||||
|
indent_style = tab
|
12
push/gorush-with-mipush/src/.github/FUNDING.yml
vendored
Normal file
12
push/gorush-with-mipush/src/.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # appleboy
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: gorush
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
39
push/gorush-with-mipush/src/.gitignore
vendored
Normal file
39
push/gorush-with-mipush/src/.gitignore
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
||||||
|
*.prof
|
||||||
|
|
||||||
|
gin-bin
|
||||||
|
key.pem
|
||||||
|
.DS_Store
|
||||||
|
gorush/log/*.log
|
||||||
|
gorush.db
|
||||||
|
.cover
|
||||||
|
*.db*
|
||||||
|
coverage.txt
|
||||||
|
dist
|
||||||
|
custom
|
||||||
|
release
|
||||||
|
coverage.txt
|
||||||
|
node_modules
|
||||||
|
config.yml
|
8
push/gorush-with-mipush/src/.idea/.gitignore
vendored
Normal file
8
push/gorush-with-mipush/src/.idea/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
9
push/gorush-with-mipush/src/.idea/gorush.iml
Normal file
9
push/gorush-with-mipush/src/.idea/gorush.iml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="Go" enabled="true" />
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
8
push/gorush-with-mipush/src/.idea/modules.xml
Normal file
8
push/gorush-with-mipush/src/.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/gorush.iml" filepath="$PROJECT_DIR$/.idea/gorush.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
push/gorush-with-mipush/src/.idea/vcs.xml
Normal file
6
push/gorush-with-mipush/src/.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
25
push/gorush-with-mipush/src/.revive.toml
Normal file
25
push/gorush-with-mipush/src/.revive.toml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
ignoreGeneratedHeader = false
|
||||||
|
severity = "warning"
|
||||||
|
confidence = 0.8
|
||||||
|
errorCode = 1
|
||||||
|
warningCode = 1
|
||||||
|
|
||||||
|
[rule.blank-imports]
|
||||||
|
[rule.context-as-argument]
|
||||||
|
[rule.context-keys-type]
|
||||||
|
[rule.dot-imports]
|
||||||
|
[rule.error-return]
|
||||||
|
[rule.error-strings]
|
||||||
|
[rule.error-naming]
|
||||||
|
[rule.exported]
|
||||||
|
[rule.if-return]
|
||||||
|
[rule.increment-decrement]
|
||||||
|
[rule.var-naming]
|
||||||
|
[rule.var-declaration]
|
||||||
|
[rule.package-comments]
|
||||||
|
[rule.range]
|
||||||
|
[rule.receiver-naming]
|
||||||
|
[rule.time-naming]
|
||||||
|
[rule.unexported-return]
|
||||||
|
[rule.indent-error-flow]
|
||||||
|
[rule.errorf]
|
17
push/gorush-with-mipush/src/HomebrewFormula/gorush.rb
Normal file
17
push/gorush-with-mipush/src/HomebrewFormula/gorush.rb
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
class Gorush < Formula
|
||||||
|
desc "A push notification server written in Go (Golang)."
|
||||||
|
homepage "https://github.com/appleboy/gorush"
|
||||||
|
head "https://github.com/appleboy/gorush.git"
|
||||||
|
|
||||||
|
depends_on "go" => :build
|
||||||
|
|
||||||
|
def install
|
||||||
|
ENV["GOPATH"] = buildpath
|
||||||
|
gorushpath = buildpath/"src/github.com/appleboy/gorush"
|
||||||
|
gorushpath.install buildpath.children
|
||||||
|
cd gorushpath do
|
||||||
|
system "go", "build", "-o", bin/"gorush"
|
||||||
|
prefix.install_metafiles
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
21
push/gorush-with-mipush/src/LICENSE
Normal file
21
push/gorush-with-mipush/src/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Bo-Yi Wu
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
176
push/gorush-with-mipush/src/Makefile
Normal file
176
push/gorush-with-mipush/src/Makefile
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
DIST := dist
|
||||||
|
EXECUTABLE := gorush
|
||||||
|
|
||||||
|
GO ?= go
|
||||||
|
DEPLOY_ACCOUNT := appleboy
|
||||||
|
DEPLOY_IMAGE := $(EXECUTABLE)
|
||||||
|
GOFMT ?= gofumpt -l -s -extra
|
||||||
|
|
||||||
|
TARGETS ?= linux darwin windows
|
||||||
|
ARCHS ?= amd64
|
||||||
|
GOFILES := $(shell find . -name "*.go" -type f)
|
||||||
|
TAGS ?= sqlite
|
||||||
|
LDFLAGS ?= -X 'main.Version=$(VERSION)'
|
||||||
|
|
||||||
|
ifneq ($(shell uname), Darwin)
|
||||||
|
EXTLDFLAGS = -extldflags "-static" $(null)
|
||||||
|
else
|
||||||
|
EXTLDFLAGS =
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DRONE_TAG),)
|
||||||
|
VERSION ?= $(DRONE_TAG)
|
||||||
|
else
|
||||||
|
VERSION ?= $(shell git describe --tags --always || git rev-parse --short HEAD)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: build
|
||||||
|
|
||||||
|
init:
|
||||||
|
ifeq ($(ANDROID_API_KEY),)
|
||||||
|
@echo "Missing ANDROID_API_KEY Parameter"
|
||||||
|
@exit 1
|
||||||
|
endif
|
||||||
|
ifeq ($(ANDROID_TEST_TOKEN),)
|
||||||
|
@echo "Missing ANDROID_TEST_TOKEN Parameter"
|
||||||
|
@exit 1
|
||||||
|
endif
|
||||||
|
@echo "Already set ANDROID_API_KEY and ANDROID_TEST_TOKEN globale variable."
|
||||||
|
|
||||||
|
.PHONY: fmt
|
||||||
|
fmt:
|
||||||
|
@hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
$(GO) install mvdan.cc/gofumpt@v0.1.1; \
|
||||||
|
fi
|
||||||
|
$(GOFMT) -w $(GOFILES)
|
||||||
|
|
||||||
|
.PHONY: fmt-check
|
||||||
|
fmt-check:
|
||||||
|
@hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
$(GO) install mvdan.cc/gofumpt@v0.1.1; \
|
||||||
|
fi
|
||||||
|
@diff=$$($(GOFMT) -d $(GOFILES)); \
|
||||||
|
if [ -n "$$diff" ]; then \
|
||||||
|
echo "Please run 'make fmt' and commit the result:"; \
|
||||||
|
echo "$${diff}"; \
|
||||||
|
exit 1; \
|
||||||
|
fi;
|
||||||
|
|
||||||
|
vet:
|
||||||
|
$(GO) vet ./...
|
||||||
|
|
||||||
|
embedmd:
|
||||||
|
@hash embedmd > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
$(GO) install github.com/campoy/embedmd@master; \
|
||||||
|
fi
|
||||||
|
embedmd -d *.md
|
||||||
|
|
||||||
|
lint:
|
||||||
|
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
$(GO) install github.com/mgechev/revive@v1.0.5; \
|
||||||
|
fi
|
||||||
|
revive -config .revive.toml ./... || exit 1
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
|
install: $(GOFILES)
|
||||||
|
$(GO) install -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)'
|
||||||
|
@echo "\n==>\033[32m Installed gorush to ${GOPATH}/bin/gorush\033[m"
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build: $(EXECUTABLE)
|
||||||
|
|
||||||
|
.PHONY: $(EXECUTABLE)
|
||||||
|
$(EXECUTABLE): $(GOFILES)
|
||||||
|
$(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/$@
|
||||||
|
|
||||||
|
.PHONY: misspell-check
|
||||||
|
misspell-check:
|
||||||
|
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
$(GO) install github.com/client9/misspell/cmd/misspell@v0.3.4; \
|
||||||
|
fi
|
||||||
|
misspell -error $(GOFILES)
|
||||||
|
|
||||||
|
.PHONY: misspell
|
||||||
|
misspell:
|
||||||
|
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
$(GO) install github.com/client9/misspell/cmd/misspell@v0.3.4; \
|
||||||
|
fi
|
||||||
|
misspell -w $(GOFILES)
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test: init fmt-check
|
||||||
|
@$(GO) test -v -cover -tags $(TAGS) -coverprofile coverage.txt ./... && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
||||||
|
|
||||||
|
release: release-dirs release-build release-copy release-compress release-check
|
||||||
|
|
||||||
|
release-dirs:
|
||||||
|
mkdir -p $(DIST)/binaries $(DIST)/release
|
||||||
|
|
||||||
|
release-build:
|
||||||
|
@hash gox > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
$(GO) install github.com/mitchellh/gox@v1.0.1; \
|
||||||
|
fi
|
||||||
|
gox -os="$(TARGETS)" -arch="$(ARCHS)" -tags="$(TAGS)" -ldflags="$(EXTLDFLAGS)-s -w $(LDFLAGS)" -output="$(DIST)/binaries/$(EXECUTABLE)-$(VERSION)-{{.OS}}-{{.Arch}}"
|
||||||
|
|
||||||
|
.PHONY: release-compress
|
||||||
|
release-compress:
|
||||||
|
@hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
$(GO) install github.com/ulikunitz/xz/cmd/gxz@v0.5.10; \
|
||||||
|
fi
|
||||||
|
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
|
||||||
|
|
||||||
|
release-copy:
|
||||||
|
$(foreach file,$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*),cp $(file) $(DIST)/release/$(notdir $(file));)
|
||||||
|
|
||||||
|
release-check:
|
||||||
|
cd $(DIST)/release; $(foreach file,$(wildcard $(DIST)/release/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
|
||||||
|
|
||||||
|
build_linux_amd64:
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/amd64/$(DEPLOY_IMAGE)
|
||||||
|
|
||||||
|
build_linux_i386:
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/i386/$(DEPLOY_IMAGE)
|
||||||
|
|
||||||
|
build_linux_arm64:
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/arm64/$(DEPLOY_IMAGE)
|
||||||
|
|
||||||
|
build_linux_arm:
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/arm/$(DEPLOY_IMAGE)
|
||||||
|
|
||||||
|
build_linux_lambda:
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags 'lambda' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/lambda/$(DEPLOY_IMAGE)
|
||||||
|
|
||||||
|
build_darwin_amd64:
|
||||||
|
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/darwin/amd64/$(DEPLOY_IMAGE)
|
||||||
|
|
||||||
|
build_darwin_i386:
|
||||||
|
CGO_ENABLED=0 GOOS=darwin GOARCH=386 go build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/darwin/i386/$(DEPLOY_IMAGE)
|
||||||
|
|
||||||
|
build_darwin_arm64:
|
||||||
|
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/darwin/arm64/$(DEPLOY_IMAGE)
|
||||||
|
|
||||||
|
build_darwin_arm:
|
||||||
|
CGO_ENABLED=0 GOOS=darwin GOARCH=arm GOARM=7 go build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/darwin/arm/$(DEPLOY_IMAGE)
|
||||||
|
|
||||||
|
build_darwin_lambda:
|
||||||
|
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -a -tags 'lambda' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/darwin/lambda/$(DEPLOY_IMAGE)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(GO) clean -modcache -x -i ./...
|
||||||
|
find . -name coverage.txt -delete
|
||||||
|
find . -name *.tar.gz -delete
|
||||||
|
find . -name *.db -delete
|
||||||
|
-rm -rf release dist .cover
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
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: generate_proto_go generate_proto_js
|
||||||
|
|
||||||
|
version:
|
||||||
|
@echo $(VERSION)
|
1
push/gorush-with-mipush/src/Procfile
Normal file
1
push/gorush-with-mipush/src/Procfile
Normal file
@ -0,0 +1 @@
|
|||||||
|
web: bin/gorush -p $PORT
|
1333
push/gorush-with-mipush/src/README.md
Normal file
1333
push/gorush-with-mipush/src/README.md
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,3 @@
|
|||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgEbVzfPnZPxfAyxqE
|
||||||
|
ZV05laAoJAl+/6Xt2O4mOB611sOhRANCAASgFTKjwJAAU95g++/vzKWHkzAVmNMI
|
||||||
|
tB5vTjZOOIwnEb70MsWZFIyUFD1P9Gwstz4+akHX7vI8BH6hHmBmfZZZ
|
5
push/gorush-with-mipush/src/certificate/authkey-valid.p8
Normal file
5
push/gorush-with-mipush/src/certificate/authkey-valid.p8
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgEbVzfPnZPxfAyxqE
|
||||||
|
ZV05laAoJAl+/6Xt2O4mOB611sOhRANCAASgFTKjwJAAU95g++/vzKWHkzAVmNMI
|
||||||
|
tB5vTjZOOIwnEb70MsWZFIyUFD1P9Gwstz4+akHX7vI8BH6hHmBmfeQl
|
||||||
|
-----END PRIVATE KEY-----
|
BIN
push/gorush-with-mipush/src/certificate/certificate-valid.p12
Normal file
BIN
push/gorush-with-mipush/src/certificate/certificate-valid.p12
Normal file
Binary file not shown.
@ -0,0 +1,59 @@
|
|||||||
|
Bag Attributes
|
||||||
|
localKeyID: 8C 1A 9F 00 66 BD 24 42 B9 5D 1E EB FE 5E 8B CA 04 3D 73 83
|
||||||
|
friendlyName: APNS/2 Private Key
|
||||||
|
subject=/C=NZ/ST=Wellington/L=Wellington/O=Internet Widgits Pty Ltd/OU=9ZEH62KRVV/CN=APNS/2 Development IOS Push Services: com.sideshow.Apns2
|
||||||
|
issuer=/C=NZ/ST=Wellington/L=Wellington/O=APNS/2 Inc./OU=APNS/2 Worldwide Developer Relations/CN=APNS/2 Worldwide Developer Relations Certification Authority
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID6zCCAtMCAQIwDQYJKoZIhvcNAQELBQAwgcMxCzAJBgNVBAYTAk5aMRMwEQYD
|
||||||
|
VQQIEwpXZWxsaW5ndG9uMRMwEQYDVQQHEwpXZWxsaW5ndG9uMRQwEgYDVQQKEwtB
|
||||||
|
UE5TLzIgSW5jLjEtMCsGA1UECxMkQVBOUy8yIFdvcmxkd2lkZSBEZXZlbG9wZXIg
|
||||||
|
UmVsYXRpb25zMUUwQwYDVQQDEzxBUE5TLzIgV29ybGR3aWRlIERldmVsb3BlciBS
|
||||||
|
ZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTYwMTA4MDgzNDMw
|
||||||
|
WhcNMjYwMTA1MDgzNDMwWjCBsjELMAkGA1UEBhMCTloxEzARBgNVBAgTCldlbGxp
|
||||||
|
bmd0b24xEzARBgNVBAcTCldlbGxpbmd0b24xITAfBgNVBAoTGEludGVybmV0IFdp
|
||||||
|
ZGdpdHMgUHR5IEx0ZDETMBEGA1UECxMKOVpFSDYyS1JWVjFBMD8GA1UEAxM4QVBO
|
||||||
|
Uy8yIERldmVsb3BtZW50IElPUyBQdXNoIFNlcnZpY2VzOiBjb20uc2lkZXNob3cu
|
||||||
|
QXBuczIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDY0c1TKB5oZPwQ
|
||||||
|
7t1CwMIrvqB6GIU3tPy6RhckZXTkOB8YeBWJ7UKfCz8HGHFVomBP0T5OUbeqQzqW
|
||||||
|
YJbQzZ8a6ZMszbL0lO4X9++3Oi5/TtAwOUOK8rOFN25m2KfsayHQZ/4vWStK2Fwm
|
||||||
|
5aJbGLlpH/b/7z1D4vhmMgoBuT1IuyhGiyFxlZ9EtTloFvsqM1E5fYZOSZACyXTa
|
||||||
|
K4vdgbQMgUVsI714FAgLTlK0UeiRkmKm3pdbtfVbrthzI+IHXKItUIy+Fn20PRMh
|
||||||
|
dSnaztSz7tgBWCIx22qvcYogHWiOgUYIM772zE2y8UVOr8DsiRlsOHSA7EI4MJcQ
|
||||||
|
G2FUq2Z/AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGyfyO2HMgcdeBcz3bt5BILX
|
||||||
|
f7RA2/UmVIwcKR1qotTsF+PnBmcILeyOQgDe9tGU5cRc79kDt3JRmMYROFIMgFRf
|
||||||
|
Wf22uOKtho7GQQaKvG+bkgMVdYFRlBHnF+KeqKH81qb9p+CT4Iw0GehIL1DijFLR
|
||||||
|
VIAIBYpz4oBPCIE1ISVT+Fgaf3JAh59kbPbNw9AIDxaBtP8EuzSTNwfbxoGbCobS
|
||||||
|
Wi1U8IsCwQFt8tM1m4ZXD1CcZIrGdryeAhVkvKIJRiU5QYWI2nqZN+JqQucm9ad0
|
||||||
|
mYO5mJkIobUa4+ZJhCPKEdmgpFbRGk0wVuaDM9Cv6P2srsYAjaO4y3VP0GvNKRI=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
Bag Attributes
|
||||||
|
localKeyID: 8C 1A 9F 00 66 BD 24 42 B9 5D 1E EB FE 5E 8B CA 04 3D 73 83
|
||||||
|
friendlyName: APNS/2 Private Key
|
||||||
|
Key Attributes: <No Attributes>
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEA2NHNUygeaGT8EO7dQsDCK76gehiFN7T8ukYXJGV05DgfGHgV
|
||||||
|
ie1Cnws/BxhxVaJgT9E+TlG3qkM6lmCW0M2fGumTLM2y9JTuF/fvtzouf07QMDlD
|
||||||
|
ivKzhTduZtin7Gsh0Gf+L1krSthcJuWiWxi5aR/2/+89Q+L4ZjIKAbk9SLsoRosh
|
||||||
|
cZWfRLU5aBb7KjNROX2GTkmQAsl02iuL3YG0DIFFbCO9eBQIC05StFHokZJipt6X
|
||||||
|
W7X1W67YcyPiB1yiLVCMvhZ9tD0TIXUp2s7Us+7YAVgiMdtqr3GKIB1ojoFGCDO+
|
||||||
|
9sxNsvFFTq/A7IkZbDh0gOxCODCXEBthVKtmfwIDAQABAoIBAQCW8ZCI+OAae1tE
|
||||||
|
ipZ9F2bWP3LHLXTo8FYVdCA+VWeITk3PoiIUkJmV0aWCUhDstgto5doDej5sCTur
|
||||||
|
Xvj/ynaerMeqJFYWkewjwZcgLyAZvwuO1v7fp9E0x/9TGDfnjjnPNeaundxW0cNt
|
||||||
|
zOY3l0HVHsy9Jpe3QDcAJovy4Tv5+hFY4kDxUBGsyjvhScVgKg5tLkJclm3sOu/L
|
||||||
|
GyLqpwNI3OJAdMIuVD4N2BZ1aOEap6mp2y8Ie0/R4YWcaZ5A4Pw7xUPl6SXc9uua
|
||||||
|
/78QTERtPC6ejyCBiE05a8m3Q3iud3Xtnlyws2KwhgBAfE6M4zR/f3OQB7ZIXMhy
|
||||||
|
ZpmZZw5xAoGBAPYn84IrlIQetWQfvPdM7Kzgh6UDHCugnlCDghwYpRJGi8hMfuZV
|
||||||
|
xNIrYAJzLYDQ01lFJRJgWXTcbqz9NBz1nhg+cNOz1/KY+38eudee6DNYmztP7jDP
|
||||||
|
2jnaS+dtjC8hAXObnFqG+NilMDLLu6aRmrJaImbjSrfyLiE6mvJ7u81nAoGBAOF9
|
||||||
|
g93wZ0mL1rk2s5WwHGTNU/HaOtmWS4z7kA7f4QaRub+MwppZmmDZPHpiZX7BPcZz
|
||||||
|
iOPQh+xn7IqRGoQWBLykBVt8zZFoLZJoCR3n63lex5A4p/0Pp1gFZrR+xX8PYVos
|
||||||
|
3yeeiWyPKsXXNc0s5QwHZcX6Wb8EHThTXGCBetcpAoGAMeQJC9IPaPPcae2w3CLA
|
||||||
|
OY3MkFpgBEuqqsDsxwsLsfeQb0lp0v+BQ+O8suJrT5eDrq1ABUh3+SKQYAl13YS+
|
||||||
|
xUUqkw35b9cn6iztF9HCWF3WIKBjs4r9PQqMpdxjNE4pQChC+Wov16ErcrAuWWVb
|
||||||
|
iFiSbm4U/9FbHisFqq3/c3MCgYB+vzSuPgFw37+0oEDVtQZgyuGSop5NzCNvfb/9
|
||||||
|
/G3aaXNFbnO8mv0hzzoleMWgODLnJ+4cUAz3H3tgcCu9bzr+Zhv0zvQl9a8YCo6F
|
||||||
|
VuWPdW0rbg1PO8tOuMqATnno79ZC/9H3zS9l7BuY1V2SlNeyqT3VyOFFc6SREpps
|
||||||
|
TJul8QKBgAxnQB8MA7zPULu1clyaJLdtEdRPkKWN7lKYptc0e/VHfSsKxseWkfqi
|
||||||
|
zgXZ51kQTrT6Zb6HYRfwC1mMXHWRKRyYjAnCxVim6YQd+KVT49iRDDAiIFoMGA4i
|
||||||
|
vvcIlneqOZZPDIoKJ60IjO/DZHWkw5mLjaIrT+qQ3XAGdJA13hcm
|
||||||
|
-----END RSA PRIVATE KEY-----
|
18
push/gorush-with-mipush/src/certificate/localhost.cert
Normal file
18
push/gorush-with-mipush/src/certificate/localhost.cert
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC+zCCAeOgAwIBAgIJALbZEDvUQrFKMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
|
||||||
|
BAMMCWxvY2FsaG9zdDAeFw0xNjAzMjgwMzMwNDFaFw0yNjAzMjYwMzMwNDFaMBQx
|
||||||
|
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
|
ggEBAMj1+xg4jVLzVnB5j7n1ul30WEE4BCzcNFxg5AOB5H5q+wje0YYiVFg6PQyv
|
||||||
|
GCipqIRXVRdVQ1hHSeunYGKe8lq3Sb1X8PUJ12v9uRbpS9DK1Owqk8rsPDu6sVTL
|
||||||
|
qKKgH1Z8yazzaS0AbXuA5e9gO/RzijbnpEP+quM4dueiMPVEJyLq+EoIQY+MM8MP
|
||||||
|
8dZzL4XZl7wL4UsCN7rPcO6W3tlnT0iO3h9c/Ym2hFhz+KNJ9KRRCvtPGZESigtK
|
||||||
|
bHsXH099WDo8v/Wp5/evBw/+JD0opxmCfHIBALHt9v53RvvsDZ1t33Rpu5C8znEY
|
||||||
|
Y2Ay7NgxhqjqoWJqA48lJeA0clsCAwEAAaNQME4wHQYDVR0OBBYEFC0bTU1Xofeh
|
||||||
|
NKIelashIsqKidDYMB8GA1UdIwQYMBaAFC0bTU1XofehNKIelashIsqKidDYMAwG
|
||||||
|
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAiJL8IMTwNX9XqQWYDFgkG4
|
||||||
|
AnrVwQhreAqC9rSxDCjqqnMHPHGzcCeDMLAMoh0kOy20nowUGNtCZ0uBvnX2q1bN
|
||||||
|
g1jt+GBcLJDR3LL4CpNOlm3YhOycuNfWMxTA7BXkmnSrZD/7KhArsBEY8aulxwKJ
|
||||||
|
HRgNlIwe1oFD1YdX1BS5pp4t25B6Vq4A3FMMUkVoWE688nE168hvQgwjrHkgHhwe
|
||||||
|
eN8lGE2DhFraXnWmDMdwaHD3HRFGhyppIFN+f7BqbWX9gM+T2YRTfObIXLWbqJLD
|
||||||
|
3Mk/NkxqVcg4eY54wJ1ufCUGAYAIaY6fQqiNUz8nhwK3t45NBVT9y/uJXqnTLyY=
|
||||||
|
-----END CERTIFICATE-----
|
27
push/gorush-with-mipush/src/certificate/localhost.key
Normal file
27
push/gorush-with-mipush/src/certificate/localhost.key
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEogIBAAKCAQEAyPX7GDiNUvNWcHmPufW6XfRYQTgELNw0XGDkA4Hkfmr7CN7R
|
||||||
|
hiJUWDo9DK8YKKmohFdVF1VDWEdJ66dgYp7yWrdJvVfw9QnXa/25FulL0MrU7CqT
|
||||||
|
yuw8O7qxVMuooqAfVnzJrPNpLQBte4Dl72A79HOKNuekQ/6q4zh256Iw9UQnIur4
|
||||||
|
SghBj4wzww/x1nMvhdmXvAvhSwI3us9w7pbe2WdPSI7eH1z9ibaEWHP4o0n0pFEK
|
||||||
|
+08ZkRKKC0psexcfT31YOjy/9ann968HD/4kPSinGYJ8cgEAse32/ndG++wNnW3f
|
||||||
|
dGm7kLzOcRhjYDLs2DGGqOqhYmoDjyUl4DRyWwIDAQABAoIBAGTKqsN9KbSfA42q
|
||||||
|
CqI0UuLouJMNa1qsnz5uAi6YKWgWdA4A44mpEjCmFRSVhUJvxWuK+cyYIQzXxIWD
|
||||||
|
D16nZdqF72AeCWZ9JySsvvZ00GfKM3y35iRy08sJWgOzmcLnGJCiSeyKsQe3HTJC
|
||||||
|
dhDXbXqvsHTVPZg01LTeDxUiTffU8NMKqR2AecQ2sTDwXEhAnTyAtnzl/XaBgFzu
|
||||||
|
U6G7FzGM5y9bxkfQVkvy+DEJkHGNOjzwcVfByyVl610ixmG1vmxVj9PbWmIPsUV8
|
||||||
|
ySmjhvDQbOfoxW0h9vTlTqGtQcBw962osnDDMWFCdM7lzO0T7RRnPVGIRpCJOKhq
|
||||||
|
keqHKwECgYEA8wwI/iZughoTXTNG9LnQQ/WAtsqO80EjMTUheo5I1kOzmUz09pyh
|
||||||
|
iAsUDoN0/26tZ5WNjlnyZu7dvTc/x3dTZpmNnoo8gcVbQNECDRzqfuQ9PPXm1SN5
|
||||||
|
6peBqAvBv78hjV05aXzPG/VBbeig7l299EarEA+a/oH3KrgDoqVqE0ECgYEA06vA
|
||||||
|
YJmgg4fZRucAYoaYsLz9Z9rCFjTe1PBTmUJkbOR8vFIHHTTEWi/SuxXL0wDSeoE2
|
||||||
|
7BQm86gCC7/KgRdrzoBqZ5qS9Mv2dsLgY635VSgjjfZkVLiH1VRRpSQObYnfoysg
|
||||||
|
gatcHSKMExd4SLQByAuImXP+L5ayDBcEJfbqSpsCgYB78Is1b0uzNLDjOh7Y9Vhr
|
||||||
|
D2qPzEORcIoNsdZctOoXuXaAmmngyIbm5R9ZN1gWWc47oFwLV3rxWqXgs6fmg8cX
|
||||||
|
7v309vFcC9Q4/Vxaa4B5LNK9n3gTAIBPTOtlUnl+2my1tfBtBqRm0W6IKbTHWS5g
|
||||||
|
vxjEm/CiEIyGUEgqTMgHAQKBgBKuXdQoutng63QufwIzDtbKVzMLQ4XiNKhmbXph
|
||||||
|
OavCnp+gPbB+L7Yl8ltAmTSOJgVZ0hcT0DxA361Zx+2Mu58GBl4OblnchmwE1vj1
|
||||||
|
KcQyPrEQxdoUTyiswGfqvrs8J9imvb+z9/U6T1KAB8Wi3WViXzPr4MsiaaRXg642
|
||||||
|
FIdxAoGAZ7/735dkhJcyOfs+LKsLr68JSstoorXOYvdMu1+JGa9iLuhnHEcMVWC8
|
||||||
|
IuihzPfloZtMbGYkZJn8l3BeGd8hmfFtgTgZGPoVRetft2LDFLnPxp2sEH5OFLsQ
|
||||||
|
R+K/kAOul8eStWuMXOFA9pMzGkGEgIFJMJOyaJON3kedQI8deCM=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
449
push/gorush-with-mipush/src/config/config.go
Normal file
449
push/gorush-with-mipush/src/config/config.go
Normal file
@ -0,0 +1,449 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
var defaultConf = []byte(`
|
||||||
|
core:
|
||||||
|
enabled: true # enable httpd server
|
||||||
|
address: "" # ip address to bind (default: any)
|
||||||
|
shutdown_timeout: 30 # default is 30 second
|
||||||
|
port: "8088" # ignore this port number if auto_tls is enabled (listen 443).
|
||||||
|
worker_num: 0 # default worker number is runtime.NumCPU()
|
||||||
|
queue_num: 0 # default queue number is 8192
|
||||||
|
max_notification: 100
|
||||||
|
sync: false # set true if you need get error message from fail push notification in API response.
|
||||||
|
feedback_hook_url: "" # set webhook url if you need get error message asynchronously from fail push notification in API response.
|
||||||
|
feedback_timeout: 10 # default is 10 second
|
||||||
|
mode: "release"
|
||||||
|
ssl: false
|
||||||
|
cert_path: "cert.pem"
|
||||||
|
key_path: "key.pem"
|
||||||
|
cert_base64: ""
|
||||||
|
key_base64: ""
|
||||||
|
http_proxy: ""
|
||||||
|
pid:
|
||||||
|
enabled: false
|
||||||
|
path: "gorush.pid"
|
||||||
|
override: true
|
||||||
|
auto_tls:
|
||||||
|
enabled: false # Automatically install TLS certificates from Let's Encrypt.
|
||||||
|
folder: ".cache" # folder for storing TLS certificates
|
||||||
|
host: "" # which domains the Let's Encrypt will attempt
|
||||||
|
|
||||||
|
grpc:
|
||||||
|
enabled: false # enable gRPC server
|
||||||
|
port: 9000
|
||||||
|
|
||||||
|
api:
|
||||||
|
push_uri: "/api/push"
|
||||||
|
stat_go_uri: "/api/stat/go"
|
||||||
|
stat_app_uri: "/api/stat/app"
|
||||||
|
config_uri: "/api/config"
|
||||||
|
sys_stat_uri: "/sys/stats"
|
||||||
|
metric_uri: "/metrics"
|
||||||
|
health_uri: "/healthz"
|
||||||
|
|
||||||
|
android:
|
||||||
|
enabled: true
|
||||||
|
apikey: "YOUR_API_KEY"
|
||||||
|
max_retry: 0 # resend fail notification, default value zero is disabled
|
||||||
|
|
||||||
|
huawei:
|
||||||
|
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", "nats" and "redis" 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
|
||||||
|
redis:
|
||||||
|
addr: 127.0.0.1:6379
|
||||||
|
channel: gorush
|
||||||
|
size: 1024
|
||||||
|
|
||||||
|
ios:
|
||||||
|
enabled: false
|
||||||
|
key_path: ""
|
||||||
|
key_base64: "" # load iOS key from base64 input
|
||||||
|
key_type: "pem" # could be pem, p12 or p8 type
|
||||||
|
password: "" # certificate password, default as empty string.
|
||||||
|
production: false
|
||||||
|
max_concurrent_pushes: 100 # just for push ios notification
|
||||||
|
max_retry: 0 # resend fail notification, default value zero is disabled
|
||||||
|
key_id: "" # KeyID from developer account (Certificates, Identifiers & Profiles -> Keys)
|
||||||
|
team_id: "" # TeamID from developer account (View Account -> Membership)
|
||||||
|
|
||||||
|
log:
|
||||||
|
format: "string" # string or json
|
||||||
|
access_log: "stdout" # stdout: output to console, or define log path like "log/access_log"
|
||||||
|
access_level: "debug"
|
||||||
|
error_log: "stderr" # stderr: output to console, or define log path like "log/error_log"
|
||||||
|
error_level: "error"
|
||||||
|
hide_token: true
|
||||||
|
|
||||||
|
stat:
|
||||||
|
engine: "memory" # support memory, redis, boltdb, buntdb or leveldb
|
||||||
|
redis:
|
||||||
|
cluster: false
|
||||||
|
addr: "localhost:6379" # if cluster is true, you may set this to "localhost:6379,localhost:6380,localhost:6381"
|
||||||
|
password: ""
|
||||||
|
db: 0
|
||||||
|
boltdb:
|
||||||
|
path: "bolt.db"
|
||||||
|
bucket: "gorush"
|
||||||
|
buntdb:
|
||||||
|
path: "bunt.db"
|
||||||
|
leveldb:
|
||||||
|
path: "level.db"
|
||||||
|
badgerdb:
|
||||||
|
path: "badger.db"
|
||||||
|
`)
|
||||||
|
|
||||||
|
// ConfYaml is config structure.
|
||||||
|
type ConfYaml struct {
|
||||||
|
Core SectionCore `yaml:"core"`
|
||||||
|
API SectionAPI `yaml:"api"`
|
||||||
|
Android SectionAndroid `yaml:"android"`
|
||||||
|
Huawei SectionHuawei `yaml:"huawei"`
|
||||||
|
MI SectionMI `yaml:"mi"`
|
||||||
|
Ios SectionIos `yaml:"ios"`
|
||||||
|
Queue SectionQueue `yaml:"queue"`
|
||||||
|
Log SectionLog `yaml:"log"`
|
||||||
|
Stat SectionStat `yaml:"stat"`
|
||||||
|
GRPC SectionGRPC `yaml:"grpc"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionCore is sub section of config.
|
||||||
|
type SectionCore struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Address string `yaml:"address"`
|
||||||
|
ShutdownTimeout int64 `yaml:"shutdown_timeout"`
|
||||||
|
Port string `yaml:"port"`
|
||||||
|
MaxNotification int64 `yaml:"max_notification"`
|
||||||
|
WorkerNum int64 `yaml:"worker_num"`
|
||||||
|
QueueNum int64 `yaml:"queue_num"`
|
||||||
|
Mode string `yaml:"mode"`
|
||||||
|
Sync bool `yaml:"sync"`
|
||||||
|
SSL bool `yaml:"ssl"`
|
||||||
|
CertPath string `yaml:"cert_path"`
|
||||||
|
KeyPath string `yaml:"key_path"`
|
||||||
|
CertBase64 string `yaml:"cert_base64"`
|
||||||
|
KeyBase64 string `yaml:"key_base64"`
|
||||||
|
HTTPProxy string `yaml:"http_proxy"`
|
||||||
|
FeedbackURL string `yaml:"feedback_hook_url"`
|
||||||
|
FeedbackTimeout int64 `yaml:"feedback_timeout"`
|
||||||
|
PID SectionPID `yaml:"pid"`
|
||||||
|
AutoTLS SectionAutoTLS `yaml:"auto_tls"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionAutoTLS support Let's Encrypt setting.
|
||||||
|
type SectionAutoTLS struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Folder string `yaml:"folder"`
|
||||||
|
Host string `yaml:"host"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionAPI is sub section of config.
|
||||||
|
type SectionAPI struct {
|
||||||
|
PushURI string `yaml:"push_uri"`
|
||||||
|
StatGoURI string `yaml:"stat_go_uri"`
|
||||||
|
StatAppURI string `yaml:"stat_app_uri"`
|
||||||
|
ConfigURI string `yaml:"config_uri"`
|
||||||
|
SysStatURI string `yaml:"sys_stat_uri"`
|
||||||
|
MetricURI string `yaml:"metric_uri"`
|
||||||
|
HealthURI string `yaml:"health_uri"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionAndroid is sub section of config.
|
||||||
|
type SectionAndroid struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
APIKey string `yaml:"apikey"`
|
||||||
|
MaxRetry int `yaml:"max_retry"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionHuawei is sub section of config.
|
||||||
|
type SectionHuawei struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
AppSecret string `yaml:"appsecret"`
|
||||||
|
AppID string `yaml:"appid"`
|
||||||
|
MaxRetry int `yaml:"max_retry"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionMI is sub section of config.
|
||||||
|
type SectionMI struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
AppSecret string `yaml:"app_secret"`
|
||||||
|
Package string `yaml:"package"`
|
||||||
|
MaxRetry int `yaml:"max_retry"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionIos is sub section of config.
|
||||||
|
type SectionIos struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
KeyPath string `yaml:"key_path"`
|
||||||
|
KeyBase64 string `yaml:"key_base64"`
|
||||||
|
KeyType string `yaml:"key_type"`
|
||||||
|
Password string `yaml:"password"`
|
||||||
|
Production bool `yaml:"production"`
|
||||||
|
MaxConcurrentPushes uint `yaml:"max_concurrent_pushes"`
|
||||||
|
MaxRetry int `yaml:"max_retry"`
|
||||||
|
KeyID string `yaml:"key_id"`
|
||||||
|
TeamID string `yaml:"team_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionLog is sub section of config.
|
||||||
|
type SectionLog struct {
|
||||||
|
Format string `yaml:"format"`
|
||||||
|
AccessLog string `yaml:"access_log"`
|
||||||
|
AccessLevel string `yaml:"access_level"`
|
||||||
|
ErrorLog string `yaml:"error_log"`
|
||||||
|
ErrorLevel string `yaml:"error_level"`
|
||||||
|
HideToken bool `yaml:"hide_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionStat is sub section of config.
|
||||||
|
type SectionStat struct {
|
||||||
|
Engine string `yaml:"engine"`
|
||||||
|
Redis SectionRedis `yaml:"redis"`
|
||||||
|
BoltDB SectionBoltDB `yaml:"boltdb"`
|
||||||
|
BuntDB SectionBuntDB `yaml:"buntdb"`
|
||||||
|
LevelDB SectionLevelDB `yaml:"leveldb"`
|
||||||
|
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"`
|
||||||
|
Redis SectionRedisQueue `yaml:"redis"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionRedisQueue is sub section of config.
|
||||||
|
type SectionRedisQueue struct {
|
||||||
|
Addr string `yaml:"addr"`
|
||||||
|
Channel string `yaml:"channel"`
|
||||||
|
Size int `yaml:"size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionBoltDB is sub section of config.
|
||||||
|
type SectionBoltDB struct {
|
||||||
|
Path string `yaml:"path"`
|
||||||
|
Bucket string `yaml:"bucket"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionBuntDB is sub section of config.
|
||||||
|
type SectionBuntDB struct {
|
||||||
|
Path string `yaml:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionLevelDB is sub section of config.
|
||||||
|
type SectionLevelDB struct {
|
||||||
|
Path string `yaml:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionBadgerDB is sub section of config.
|
||||||
|
type SectionBadgerDB struct {
|
||||||
|
Path string `yaml:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionPID is sub section of config.
|
||||||
|
type SectionPID struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Path string `yaml:"path"`
|
||||||
|
Override bool `yaml:"override"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionGRPC is sub section of config.
|
||||||
|
type SectionGRPC struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Port string `yaml:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func setDefault() {
|
||||||
|
viper.SetDefault("ios.max_concurrent_pushes", uint(100))
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadConf load config from file and read in environment variables that match
|
||||||
|
func LoadConf(confPath ...string) (*ConfYaml, error) {
|
||||||
|
conf := &ConfYaml{}
|
||||||
|
|
||||||
|
// load default values
|
||||||
|
setDefault()
|
||||||
|
|
||||||
|
viper.SetConfigType("yaml")
|
||||||
|
viper.AutomaticEnv() // read in environment variables that match
|
||||||
|
viper.SetEnvPrefix("gorush") // will be uppercased automatically
|
||||||
|
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||||
|
|
||||||
|
if len(confPath) > 0 && confPath[0] != "" {
|
||||||
|
content, err := ioutil.ReadFile(confPath[0])
|
||||||
|
if err != nil {
|
||||||
|
return conf, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := viper.ReadConfig(bytes.NewBuffer(content)); err != nil {
|
||||||
|
return conf, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Search config in home directory with name ".gorush" (without extension).
|
||||||
|
viper.AddConfigPath("/etc/gorush/")
|
||||||
|
viper.AddConfigPath("$HOME/.gorush")
|
||||||
|
viper.AddConfigPath(".")
|
||||||
|
viper.SetConfigName("config")
|
||||||
|
|
||||||
|
// If a config file is found, read it in.
|
||||||
|
if err := viper.ReadInConfig(); err == nil {
|
||||||
|
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||||
|
} else if err := viper.ReadConfig(bytes.NewBuffer(defaultConf)); err != nil {
|
||||||
|
// load default config
|
||||||
|
return conf, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Core
|
||||||
|
conf.Core.Address = viper.GetString("core.address")
|
||||||
|
conf.Core.Port = viper.GetString("core.port")
|
||||||
|
conf.Core.ShutdownTimeout = int64(viper.GetInt("core.shutdown_timeout"))
|
||||||
|
conf.Core.Enabled = viper.GetBool("core.enabled")
|
||||||
|
conf.Core.WorkerNum = int64(viper.GetInt("core.worker_num"))
|
||||||
|
conf.Core.QueueNum = int64(viper.GetInt("core.queue_num"))
|
||||||
|
conf.Core.Mode = viper.GetString("core.mode")
|
||||||
|
conf.Core.Sync = viper.GetBool("core.sync")
|
||||||
|
conf.Core.FeedbackURL = viper.GetString("core.feedback_hook_url")
|
||||||
|
conf.Core.FeedbackTimeout = int64(viper.GetInt("core.feedback_timeout"))
|
||||||
|
conf.Core.SSL = viper.GetBool("core.ssl")
|
||||||
|
conf.Core.CertPath = viper.GetString("core.cert_path")
|
||||||
|
conf.Core.KeyPath = viper.GetString("core.key_path")
|
||||||
|
conf.Core.CertBase64 = viper.GetString("core.cert_base64")
|
||||||
|
conf.Core.KeyBase64 = viper.GetString("core.key_base64")
|
||||||
|
conf.Core.MaxNotification = int64(viper.GetInt("core.max_notification"))
|
||||||
|
conf.Core.HTTPProxy = viper.GetString("core.http_proxy")
|
||||||
|
conf.Core.PID.Enabled = viper.GetBool("core.pid.enabled")
|
||||||
|
conf.Core.PID.Path = viper.GetString("core.pid.path")
|
||||||
|
conf.Core.PID.Override = viper.GetBool("core.pid.override")
|
||||||
|
conf.Core.AutoTLS.Enabled = viper.GetBool("core.auto_tls.enabled")
|
||||||
|
conf.Core.AutoTLS.Folder = viper.GetString("core.auto_tls.folder")
|
||||||
|
conf.Core.AutoTLS.Host = viper.GetString("core.auto_tls.host")
|
||||||
|
|
||||||
|
// Api
|
||||||
|
conf.API.PushURI = viper.GetString("api.push_uri")
|
||||||
|
conf.API.StatGoURI = viper.GetString("api.stat_go_uri")
|
||||||
|
conf.API.StatAppURI = viper.GetString("api.stat_app_uri")
|
||||||
|
conf.API.ConfigURI = viper.GetString("api.config_uri")
|
||||||
|
conf.API.SysStatURI = viper.GetString("api.sys_stat_uri")
|
||||||
|
conf.API.MetricURI = viper.GetString("api.metric_uri")
|
||||||
|
conf.API.HealthURI = viper.GetString("api.health_uri")
|
||||||
|
|
||||||
|
// Android
|
||||||
|
conf.Android.Enabled = viper.GetBool("android.enabled")
|
||||||
|
conf.Android.APIKey = viper.GetString("android.apikey")
|
||||||
|
conf.Android.MaxRetry = viper.GetInt("android.max_retry")
|
||||||
|
|
||||||
|
// Huawei
|
||||||
|
conf.Huawei.Enabled = viper.GetBool("huawei.enabled")
|
||||||
|
conf.Huawei.AppSecret = viper.GetString("huawei.appsecret")
|
||||||
|
conf.Huawei.AppID = viper.GetString("huawei.appid")
|
||||||
|
conf.Huawei.MaxRetry = viper.GetInt("huawei.max_retry")
|
||||||
|
|
||||||
|
conf.MI.Enabled = viper.GetBool("mi.enabled")
|
||||||
|
conf.MI.AppSecret = viper.GetString("mi.appsecret")
|
||||||
|
conf.MI.Package = viper.GetString("mi.package")
|
||||||
|
conf.MI.MaxRetry = viper.GetInt("mi.max_retry")
|
||||||
|
|
||||||
|
// iOS
|
||||||
|
conf.Ios.Enabled = viper.GetBool("ios.enabled")
|
||||||
|
conf.Ios.KeyPath = viper.GetString("ios.key_path")
|
||||||
|
conf.Ios.KeyBase64 = viper.GetString("ios.key_base64")
|
||||||
|
conf.Ios.KeyType = viper.GetString("ios.key_type")
|
||||||
|
conf.Ios.Password = viper.GetString("ios.password")
|
||||||
|
conf.Ios.Production = viper.GetBool("ios.production")
|
||||||
|
conf.Ios.MaxConcurrentPushes = viper.GetUint("ios.max_concurrent_pushes")
|
||||||
|
conf.Ios.MaxRetry = viper.GetInt("ios.max_retry")
|
||||||
|
conf.Ios.KeyID = viper.GetString("ios.key_id")
|
||||||
|
conf.Ios.TeamID = viper.GetString("ios.team_id")
|
||||||
|
|
||||||
|
// log
|
||||||
|
conf.Log.Format = viper.GetString("log.format")
|
||||||
|
conf.Log.AccessLog = viper.GetString("log.access_log")
|
||||||
|
conf.Log.AccessLevel = viper.GetString("log.access_level")
|
||||||
|
conf.Log.ErrorLog = viper.GetString("log.error_log")
|
||||||
|
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")
|
||||||
|
conf.Queue.Redis.Addr = viper.GetString("queue.redis.addr")
|
||||||
|
conf.Queue.Redis.Channel = viper.GetString("queue.redis.channel")
|
||||||
|
conf.Queue.Redis.Size = viper.GetInt("queue.redis.size")
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
conf.Stat.BoltDB.Path = viper.GetString("stat.boltdb.path")
|
||||||
|
conf.Stat.BoltDB.Bucket = viper.GetString("stat.boltdb.bucket")
|
||||||
|
conf.Stat.BuntDB.Path = viper.GetString("stat.buntdb.path")
|
||||||
|
conf.Stat.LevelDB.Path = viper.GetString("stat.leveldb.path")
|
||||||
|
conf.Stat.BadgerDB.Path = viper.GetString("stat.badgerdb.path")
|
||||||
|
|
||||||
|
// gRPC Server
|
||||||
|
conf.GRPC.Enabled = viper.GetBool("grpc.enabled")
|
||||||
|
conf.GRPC.Port = viper.GetString("grpc.port")
|
||||||
|
|
||||||
|
if conf.Core.WorkerNum == int64(0) {
|
||||||
|
conf.Core.WorkerNum = int64(runtime.NumCPU())
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf.Core.QueueNum == int64(0) {
|
||||||
|
conf.Core.QueueNum = int64(8192)
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf, nil
|
||||||
|
}
|
245
push/gorush-with-mipush/src/config/config_test.go
Normal file
245
push/gorush-with-mipush/src/config/config_test.go
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test file is missing
|
||||||
|
func TestMissingFile(t *testing.T) {
|
||||||
|
filename := "test"
|
||||||
|
_, err := LoadConf(filename)
|
||||||
|
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptyConfig(t *testing.T) {
|
||||||
|
conf, err := LoadConf("testdata/empty.yml")
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to load config.yml from file")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, uint(100), conf.Ios.MaxConcurrentPushes)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
ConfGorushDefault *ConfYaml
|
||||||
|
ConfGorush *ConfYaml
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ConfigTestSuite) SetupTest() {
|
||||||
|
var err error
|
||||||
|
suite.ConfGorushDefault, err = LoadConf()
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to load default config.yml")
|
||||||
|
}
|
||||||
|
suite.ConfGorush, err = LoadConf("testdata/config.yml")
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to load config.yml from file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ConfigTestSuite) TestValidateConfDefault() {
|
||||||
|
// Core
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Core.Address)
|
||||||
|
assert.Equal(suite.T(), "8088", suite.ConfGorushDefault.Core.Port)
|
||||||
|
assert.Equal(suite.T(), int64(30), suite.ConfGorushDefault.Core.ShutdownTimeout)
|
||||||
|
assert.Equal(suite.T(), true, suite.ConfGorushDefault.Core.Enabled)
|
||||||
|
assert.Equal(suite.T(), int64(runtime.NumCPU()), suite.ConfGorushDefault.Core.WorkerNum)
|
||||||
|
assert.Equal(suite.T(), int64(8192), suite.ConfGorushDefault.Core.QueueNum)
|
||||||
|
assert.Equal(suite.T(), "release", suite.ConfGorushDefault.Core.Mode)
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Core.Sync)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Core.FeedbackURL)
|
||||||
|
assert.Equal(suite.T(), int64(10), suite.ConfGorushDefault.Core.FeedbackTimeout)
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Core.SSL)
|
||||||
|
assert.Equal(suite.T(), "cert.pem", suite.ConfGorushDefault.Core.CertPath)
|
||||||
|
assert.Equal(suite.T(), "key.pem", suite.ConfGorushDefault.Core.KeyPath)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Core.KeyBase64)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Core.CertBase64)
|
||||||
|
assert.Equal(suite.T(), int64(100), suite.ConfGorushDefault.Core.MaxNotification)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Core.HTTPProxy)
|
||||||
|
// Pid
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Core.PID.Enabled)
|
||||||
|
assert.Equal(suite.T(), "gorush.pid", suite.ConfGorushDefault.Core.PID.Path)
|
||||||
|
assert.Equal(suite.T(), true, suite.ConfGorushDefault.Core.PID.Override)
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Core.AutoTLS.Enabled)
|
||||||
|
assert.Equal(suite.T(), ".cache", suite.ConfGorushDefault.Core.AutoTLS.Folder)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Core.AutoTLS.Host)
|
||||||
|
|
||||||
|
// Api
|
||||||
|
assert.Equal(suite.T(), "/api/push", suite.ConfGorushDefault.API.PushURI)
|
||||||
|
assert.Equal(suite.T(), "/api/stat/go", suite.ConfGorushDefault.API.StatGoURI)
|
||||||
|
assert.Equal(suite.T(), "/api/stat/app", suite.ConfGorushDefault.API.StatAppURI)
|
||||||
|
assert.Equal(suite.T(), "/api/config", suite.ConfGorushDefault.API.ConfigURI)
|
||||||
|
assert.Equal(suite.T(), "/sys/stats", suite.ConfGorushDefault.API.SysStatURI)
|
||||||
|
assert.Equal(suite.T(), "/metrics", suite.ConfGorushDefault.API.MetricURI)
|
||||||
|
assert.Equal(suite.T(), "/healthz", suite.ConfGorushDefault.API.HealthURI)
|
||||||
|
|
||||||
|
// Android
|
||||||
|
assert.Equal(suite.T(), true, suite.ConfGorushDefault.Android.Enabled)
|
||||||
|
assert.Equal(suite.T(), "YOUR_API_KEY", suite.ConfGorushDefault.Android.APIKey)
|
||||||
|
assert.Equal(suite.T(), 0, suite.ConfGorushDefault.Android.MaxRetry)
|
||||||
|
|
||||||
|
// iOS
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Ios.Enabled)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Ios.KeyPath)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Ios.KeyBase64)
|
||||||
|
assert.Equal(suite.T(), "pem", suite.ConfGorushDefault.Ios.KeyType)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Ios.Password)
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Ios.Production)
|
||||||
|
assert.Equal(suite.T(), uint(100), suite.ConfGorushDefault.Ios.MaxConcurrentPushes)
|
||||||
|
assert.Equal(suite.T(), 0, suite.ConfGorushDefault.Ios.MaxRetry)
|
||||||
|
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)
|
||||||
|
|
||||||
|
assert.Equal(suite.T(), "127.0.0.1:6379", suite.ConfGorushDefault.Queue.Redis.Addr)
|
||||||
|
assert.Equal(suite.T(), "gorush", suite.ConfGorushDefault.Queue.Redis.Channel)
|
||||||
|
assert.Equal(suite.T(), 1024, suite.ConfGorushDefault.Queue.Redis.Size)
|
||||||
|
|
||||||
|
// log
|
||||||
|
assert.Equal(suite.T(), "string", suite.ConfGorushDefault.Log.Format)
|
||||||
|
assert.Equal(suite.T(), "stdout", suite.ConfGorushDefault.Log.AccessLog)
|
||||||
|
assert.Equal(suite.T(), "debug", suite.ConfGorushDefault.Log.AccessLevel)
|
||||||
|
assert.Equal(suite.T(), "stderr", suite.ConfGorushDefault.Log.ErrorLog)
|
||||||
|
assert.Equal(suite.T(), "error", suite.ConfGorushDefault.Log.ErrorLevel)
|
||||||
|
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)
|
||||||
|
|
||||||
|
assert.Equal(suite.T(), "bolt.db", suite.ConfGorushDefault.Stat.BoltDB.Path)
|
||||||
|
assert.Equal(suite.T(), "gorush", suite.ConfGorushDefault.Stat.BoltDB.Bucket)
|
||||||
|
|
||||||
|
assert.Equal(suite.T(), "bunt.db", suite.ConfGorushDefault.Stat.BuntDB.Path)
|
||||||
|
assert.Equal(suite.T(), "level.db", suite.ConfGorushDefault.Stat.LevelDB.Path)
|
||||||
|
assert.Equal(suite.T(), "badger.db", suite.ConfGorushDefault.Stat.BadgerDB.Path)
|
||||||
|
|
||||||
|
// gRPC
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorushDefault.GRPC.Enabled)
|
||||||
|
assert.Equal(suite.T(), "9000", suite.ConfGorushDefault.GRPC.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ConfigTestSuite) TestValidateConf() {
|
||||||
|
// Core
|
||||||
|
assert.Equal(suite.T(), "8088", suite.ConfGorush.Core.Port)
|
||||||
|
assert.Equal(suite.T(), int64(30), suite.ConfGorush.Core.ShutdownTimeout)
|
||||||
|
assert.Equal(suite.T(), true, suite.ConfGorush.Core.Enabled)
|
||||||
|
assert.Equal(suite.T(), int64(runtime.NumCPU()), suite.ConfGorush.Core.WorkerNum)
|
||||||
|
assert.Equal(suite.T(), int64(8192), suite.ConfGorush.Core.QueueNum)
|
||||||
|
assert.Equal(suite.T(), "release", suite.ConfGorush.Core.Mode)
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorush.Core.Sync)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorush.Core.FeedbackURL)
|
||||||
|
assert.Equal(suite.T(), int64(10), suite.ConfGorush.Core.FeedbackTimeout)
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorush.Core.SSL)
|
||||||
|
assert.Equal(suite.T(), "cert.pem", suite.ConfGorush.Core.CertPath)
|
||||||
|
assert.Equal(suite.T(), "key.pem", suite.ConfGorush.Core.KeyPath)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorush.Core.CertBase64)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorush.Core.KeyBase64)
|
||||||
|
assert.Equal(suite.T(), int64(100), suite.ConfGorush.Core.MaxNotification)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorush.Core.HTTPProxy)
|
||||||
|
// Pid
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorush.Core.PID.Enabled)
|
||||||
|
assert.Equal(suite.T(), "gorush.pid", suite.ConfGorush.Core.PID.Path)
|
||||||
|
assert.Equal(suite.T(), true, suite.ConfGorush.Core.PID.Override)
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorush.Core.AutoTLS.Enabled)
|
||||||
|
assert.Equal(suite.T(), ".cache", suite.ConfGorush.Core.AutoTLS.Folder)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorush.Core.AutoTLS.Host)
|
||||||
|
|
||||||
|
// Api
|
||||||
|
assert.Equal(suite.T(), "/api/push", suite.ConfGorush.API.PushURI)
|
||||||
|
assert.Equal(suite.T(), "/api/stat/go", suite.ConfGorush.API.StatGoURI)
|
||||||
|
assert.Equal(suite.T(), "/api/stat/app", suite.ConfGorush.API.StatAppURI)
|
||||||
|
assert.Equal(suite.T(), "/api/config", suite.ConfGorush.API.ConfigURI)
|
||||||
|
assert.Equal(suite.T(), "/sys/stats", suite.ConfGorush.API.SysStatURI)
|
||||||
|
assert.Equal(suite.T(), "/metrics", suite.ConfGorush.API.MetricURI)
|
||||||
|
assert.Equal(suite.T(), "/healthz", suite.ConfGorush.API.HealthURI)
|
||||||
|
|
||||||
|
// Android
|
||||||
|
assert.Equal(suite.T(), true, suite.ConfGorush.Android.Enabled)
|
||||||
|
assert.Equal(suite.T(), "YOUR_API_KEY", suite.ConfGorush.Android.APIKey)
|
||||||
|
assert.Equal(suite.T(), 0, suite.ConfGorush.Android.MaxRetry)
|
||||||
|
|
||||||
|
// iOS
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorush.Ios.Enabled)
|
||||||
|
assert.Equal(suite.T(), "key.pem", suite.ConfGorush.Ios.KeyPath)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorush.Ios.KeyBase64)
|
||||||
|
assert.Equal(suite.T(), "pem", suite.ConfGorush.Ios.KeyType)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorush.Ios.Password)
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorush.Ios.Production)
|
||||||
|
assert.Equal(suite.T(), uint(100), suite.ConfGorush.Ios.MaxConcurrentPushes)
|
||||||
|
assert.Equal(suite.T(), 0, suite.ConfGorush.Ios.MaxRetry)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorush.Ios.KeyID)
|
||||||
|
assert.Equal(suite.T(), "", suite.ConfGorush.Ios.TeamID)
|
||||||
|
|
||||||
|
// log
|
||||||
|
assert.Equal(suite.T(), "string", suite.ConfGorush.Log.Format)
|
||||||
|
assert.Equal(suite.T(), "stdout", suite.ConfGorush.Log.AccessLog)
|
||||||
|
assert.Equal(suite.T(), "debug", suite.ConfGorush.Log.AccessLevel)
|
||||||
|
assert.Equal(suite.T(), "stderr", suite.ConfGorush.Log.ErrorLog)
|
||||||
|
assert.Equal(suite.T(), "error", suite.ConfGorush.Log.ErrorLevel)
|
||||||
|
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)
|
||||||
|
|
||||||
|
assert.Equal(suite.T(), "bolt.db", suite.ConfGorush.Stat.BoltDB.Path)
|
||||||
|
assert.Equal(suite.T(), "gorush", suite.ConfGorush.Stat.BoltDB.Bucket)
|
||||||
|
|
||||||
|
assert.Equal(suite.T(), "bunt.db", suite.ConfGorush.Stat.BuntDB.Path)
|
||||||
|
assert.Equal(suite.T(), "level.db", suite.ConfGorush.Stat.LevelDB.Path)
|
||||||
|
assert.Equal(suite.T(), "badger.db", suite.ConfGorush.Stat.BadgerDB.Path)
|
||||||
|
|
||||||
|
// gRPC
|
||||||
|
assert.Equal(suite.T(), false, suite.ConfGorush.GRPC.Enabled)
|
||||||
|
assert.Equal(suite.T(), "9000", suite.ConfGorush.GRPC.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigTestSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(ConfigTestSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadConfigFromEnv(t *testing.T) {
|
||||||
|
os.Setenv("GORUSH_CORE_PORT", "9001")
|
||||||
|
os.Setenv("GORUSH_GRPC_ENABLED", "true")
|
||||||
|
os.Setenv("GORUSH_CORE_MAX_NOTIFICATION", "200")
|
||||||
|
os.Setenv("GORUSH_IOS_KEY_ID", "ABC123DEFG")
|
||||||
|
os.Setenv("GORUSH_IOS_TEAM_ID", "DEF123GHIJ")
|
||||||
|
os.Setenv("GORUSH_API_HEALTH_URI", "/healthz")
|
||||||
|
ConfGorush, err := LoadConf("testdata/config.yml")
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to load config.yml from file")
|
||||||
|
}
|
||||||
|
assert.Equal(t, "9001", ConfGorush.Core.Port)
|
||||||
|
assert.Equal(t, int64(200), ConfGorush.Core.MaxNotification)
|
||||||
|
assert.True(t, ConfGorush.GRPC.Enabled)
|
||||||
|
assert.Equal(t, "ABC123DEFG", ConfGorush.Ios.KeyID)
|
||||||
|
assert.Equal(t, "DEF123GHIJ", ConfGorush.Ios.TeamID)
|
||||||
|
assert.Equal(t, "/healthz", ConfGorush.API.HealthURI)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadWrongDefaultYAMLConfig(t *testing.T) {
|
||||||
|
defaultConf = []byte(`a`)
|
||||||
|
_, err := LoadConf()
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
0
push/gorush-with-mipush/src/config/testdata/empty.yml
vendored
Normal file
0
push/gorush-with-mipush/src/config/testdata/empty.yml
vendored
Normal file
37
push/gorush-with-mipush/src/contrib/init/debian/README.md
Normal file
37
push/gorush-with-mipush/src/contrib/init/debian/README.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Run gorush in Debian/Ubuntu
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Put `gorush` binary into `/usr/bin` folder.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cp gorush /usr/bin/
|
||||||
|
chmod +x /usr/bin/gorush
|
||||||
|
```
|
||||||
|
|
||||||
|
put `gorush` init script into `/etc/rc.d`
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cp contrib/init/debian/gorush /etc.rc.d/
|
||||||
|
```
|
||||||
|
|
||||||
|
install and remove System-V style init script links
|
||||||
|
|
||||||
|
```sh
|
||||||
|
update-rc.d gorush start 20 2 3 4 5 . stop 80 0 1 6 .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Start service
|
||||||
|
|
||||||
|
create gorush configuration file.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir -p /etc/gorush
|
||||||
|
cp config/testdata/config.yml /etc/gorush/
|
||||||
|
```
|
||||||
|
|
||||||
|
start gorush service.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
/etc/init.d/gorush start
|
||||||
|
```
|
87
push/gorush-with-mipush/src/contrib/init/debian/gorush
Normal file
87
push/gorush-with-mipush/src/contrib/init/debian/gorush
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: gorush
|
||||||
|
# Required-Start: $syslog $network
|
||||||
|
# Required-Stop: $syslog $network
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: starts the gorush web server
|
||||||
|
# Description: starts gorush using start-stop-daemon
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
# Original Author: Bo-Yi Wu (appleboy)
|
||||||
|
|
||||||
|
# Do NOT "set -e"
|
||||||
|
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||||
|
DESC="the gorush web server"
|
||||||
|
NAME=gorush
|
||||||
|
DAEMON=$(which gorush)
|
||||||
|
|
||||||
|
DAEMONUSER=www-data
|
||||||
|
PIDFILE=/var/run/$NAME.pid
|
||||||
|
CONFIGFILE=/etc/gorush/config.yml
|
||||||
|
DAEMONOPTS="-c $CONFIGFILE"
|
||||||
|
|
||||||
|
USERBIND="setcap cap_net_bind_service=+ep"
|
||||||
|
STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/5/KILL/5}"
|
||||||
|
|
||||||
|
# Read configuration variable file if it is present
|
||||||
|
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
|
||||||
|
|
||||||
|
# Exit if the package is not installed
|
||||||
|
[ -x "$DAEMON" ] || exit 0
|
||||||
|
|
||||||
|
# Set the ulimits
|
||||||
|
ulimit -n 8192
|
||||||
|
|
||||||
|
do_start()
|
||||||
|
{
|
||||||
|
$USERBIND $DAEMON
|
||||||
|
sh -c "USER=$DAEMONUSER start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile \\
|
||||||
|
--background --chuid $DAEMONUSER --exec $DAEMON -- $DAEMONOPTS"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_stop()
|
||||||
|
{
|
||||||
|
start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PIDFILE --name $NAME --oknodo
|
||||||
|
rm -f $PIDFILE
|
||||||
|
}
|
||||||
|
|
||||||
|
do_status()
|
||||||
|
{
|
||||||
|
if [ -f $PIDFILE ]; then
|
||||||
|
if kill -0 $(cat "$PIDFILE"); then
|
||||||
|
echo "$NAME is running, PID is $(cat $PIDFILE)"
|
||||||
|
else
|
||||||
|
echo "$NAME process is dead, but pidfile exists"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "$NAME is not running"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
echo "Starting $DESC" "$NAME"
|
||||||
|
do_start
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
echo "Stopping $DESC" "$NAME"
|
||||||
|
do_stop
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
do_status
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
echo "Restarting $DESC" "$NAME"
|
||||||
|
do_stop
|
||||||
|
do_start
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
19
push/gorush-with-mipush/src/core/core.go
Normal file
19
push/gorush-with-mipush/src/core/core.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
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
|
||||||
|
//PlaFormMI constant is 4 for MI
|
||||||
|
PlaFormMI
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SucceededPush is log block
|
||||||
|
SucceededPush = "succeeded-push"
|
||||||
|
// FailedPush is log block
|
||||||
|
FailedPush = "failed-push"
|
||||||
|
)
|
20
push/gorush-with-mipush/src/core/queue.go
Normal file
20
push/gorush-with-mipush/src/core/queue.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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"
|
||||||
|
// Redis Pub/Sub
|
||||||
|
Redis Queue = "redis"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsLocalQueue check is Local Queue
|
||||||
|
func IsLocalQueue(q Queue) bool {
|
||||||
|
return q == LocalQueue
|
||||||
|
}
|
55
push/gorush-with-mipush/src/doc.go
Normal file
55
push/gorush-with-mipush/src/doc.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// A push notification server using Gin framework written in Go (Golang).
|
||||||
|
//
|
||||||
|
// Details about the gorush project are found in github page:
|
||||||
|
//
|
||||||
|
// https://github.com/appleboy/gorush
|
||||||
|
//
|
||||||
|
// The pre-compiled binaries can be downloaded from release page.
|
||||||
|
//
|
||||||
|
// Send Android notification
|
||||||
|
//
|
||||||
|
// $ gorush -android -m="your message" -k="API Key" -t="Device token"
|
||||||
|
//
|
||||||
|
// Send iOS notification
|
||||||
|
//
|
||||||
|
// $ gorush -ios -m="your message" -i="API Key" -t="Device token"
|
||||||
|
//
|
||||||
|
// The default endpoint is APNs development. Please add -production flag for APNs production push endpoint.
|
||||||
|
//
|
||||||
|
// $ gorush -ios -m="your message" -i="API Key" -t="Device token" -production
|
||||||
|
//
|
||||||
|
// Run gorush web server
|
||||||
|
//
|
||||||
|
// $ gorush -c config.yml
|
||||||
|
//
|
||||||
|
// Get go status of api server using httpie tool:
|
||||||
|
//
|
||||||
|
// $ http -v --verify=no --json GET https://localhost:8088/api/stat/go
|
||||||
|
//
|
||||||
|
// Simple send iOS notification example, the platform value is 1:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "notifications": [
|
||||||
|
// {
|
||||||
|
// "tokens": ["token_a", "token_b"],
|
||||||
|
// "platform": 1,
|
||||||
|
// "message": "Hello World iOS!"
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Simple send Android notification example, the platform value is 2:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "notifications": [
|
||||||
|
// {
|
||||||
|
// "tokens": ["token_a", "token_b"],
|
||||||
|
// "platform": 2,
|
||||||
|
// "message": "Hello World Android!"
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// For more details, see the documentation and example.
|
||||||
|
//
|
||||||
|
package main
|
15
push/gorush-with-mipush/src/docker-compose.yml
Normal file
15
push/gorush-with-mipush/src/docker-compose.yml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
gorush:
|
||||||
|
image: appleboy/gorush
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "8088:8088"
|
||||||
|
- "9000:9000"
|
||||||
|
logging:
|
||||||
|
options:
|
||||||
|
max-size: "100k"
|
||||||
|
max-file: "3"
|
||||||
|
environment:
|
||||||
|
- GORUSH_CORE_QUEUE_NUM=512
|
14
push/gorush-with-mipush/src/docker/Dockerfile.linux.amd64
Normal file
14
push/gorush-with-mipush/src/docker/Dockerfile.linux.amd64
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM plugins/base:linux-amd64
|
||||||
|
|
||||||
|
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
|
||||||
|
org.label-schema.name="Gorush" \
|
||||||
|
org.label-schema.vendor="Bo-Yi Wu" \
|
||||||
|
org.label-schema.schema-version="1.0"
|
||||||
|
|
||||||
|
COPY release/linux/amd64/gorush /bin/
|
||||||
|
|
||||||
|
EXPOSE 8088 9000
|
||||||
|
HEALTHCHECK --start-period=1s --interval=10s --timeout=5s \
|
||||||
|
CMD ["/bin/gorush", "--ping"]
|
||||||
|
|
||||||
|
ENTRYPOINT ["/bin/gorush"]
|
14
push/gorush-with-mipush/src/docker/Dockerfile.linux.arm
Normal file
14
push/gorush-with-mipush/src/docker/Dockerfile.linux.arm
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM plugins/base:linux-arm
|
||||||
|
|
||||||
|
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
|
||||||
|
org.label-schema.name="Gorush" \
|
||||||
|
org.label-schema.vendor="Bo-Yi Wu" \
|
||||||
|
org.label-schema.schema-version="1.0"
|
||||||
|
|
||||||
|
COPY release/linux/arm/gorush /bin/
|
||||||
|
|
||||||
|
EXPOSE 8088 9000
|
||||||
|
HEALTHCHECK --start-period=1s --interval=10s --timeout=5s \
|
||||||
|
CMD ["/bin/gorush", "--ping"]
|
||||||
|
|
||||||
|
ENTRYPOINT ["/bin/gorush"]
|
14
push/gorush-with-mipush/src/docker/Dockerfile.linux.arm64
Normal file
14
push/gorush-with-mipush/src/docker/Dockerfile.linux.arm64
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM plugins/base:linux-arm64
|
||||||
|
|
||||||
|
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
|
||||||
|
org.label-schema.name="Gorush" \
|
||||||
|
org.label-schema.vendor="Bo-Yi Wu" \
|
||||||
|
org.label-schema.schema-version="1.0"
|
||||||
|
|
||||||
|
COPY release/linux/arm64/gorush /bin/
|
||||||
|
|
||||||
|
EXPOSE 8088 9000
|
||||||
|
HEALTHCHECK --start-period=1s --interval=10s --timeout=5s \
|
||||||
|
CMD ["/bin/gorush", "--ping"]
|
||||||
|
|
||||||
|
ENTRYPOINT ["/bin/gorush"]
|
14
push/gorush-with-mipush/src/docker/Dockerfile.windows.amd64
Normal file
14
push/gorush-with-mipush/src/docker/Dockerfile.windows.amd64
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM mcr.microsoft.com/windows/nanoserver:1809-amd64
|
||||||
|
|
||||||
|
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
|
||||||
|
org.label-schema.name="Gorush" \
|
||||||
|
org.label-schema.vendor="Bo-Yi Wu" \
|
||||||
|
org.label-schema.schema-version="1.0"
|
||||||
|
|
||||||
|
COPY release/gorush.exe C:/bin/gorush.exe
|
||||||
|
|
||||||
|
EXPOSE 8088 9000
|
||||||
|
HEALTHCHECK --start-period=1s --interval=10s --timeout=5s \
|
||||||
|
CMD ["\\gorush.exe", "--ping"]
|
||||||
|
|
||||||
|
ENTRYPOINT [ "C:\\bin\\gorush.exe" ]
|
25
push/gorush-with-mipush/src/docker/manifest.tmpl
Normal file
25
push/gorush-with-mipush/src/docker/manifest.tmpl
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
image: appleboy/gorush:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
|
||||||
|
{{#if build.tags}}
|
||||||
|
tags:
|
||||||
|
{{#each build.tags}}
|
||||||
|
- {{this}}
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
||||||
|
manifests:
|
||||||
|
-
|
||||||
|
image: appleboy/gorush:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
|
||||||
|
platform:
|
||||||
|
architecture: amd64
|
||||||
|
os: linux
|
||||||
|
-
|
||||||
|
image: appleboy/gorush:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
|
||||||
|
platform:
|
||||||
|
architecture: arm64
|
||||||
|
os: linux
|
||||||
|
variant: v8
|
||||||
|
-
|
||||||
|
image: appleboy/gorush:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
|
||||||
|
platform:
|
||||||
|
architecture: arm
|
||||||
|
os: linux
|
||||||
|
variant: v7
|
46
push/gorush-with-mipush/src/go.mod
Normal file
46
push/gorush-with-mipush/src/go.mod
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
module github.com/appleboy/gorush
|
||||||
|
|
||||||
|
go 1.15
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/apex/gateway v1.1.2
|
||||||
|
github.com/appleboy/gin-status-api v1.1.0
|
||||||
|
github.com/appleboy/go-fcm v0.1.5
|
||||||
|
github.com/appleboy/gofight/v2 v2.1.2
|
||||||
|
github.com/appleboy/graceful v0.0.3
|
||||||
|
github.com/asdine/storm/v3 v3.2.1
|
||||||
|
github.com/buger/jsonparser v1.1.1
|
||||||
|
github.com/dgraph-io/badger/v3 v3.2103.1
|
||||||
|
github.com/geek-go/xmpush v0.0.0-20200624150426-da36515dfc49 // indirect
|
||||||
|
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.4
|
||||||
|
github.com/golang-queue/nsq v0.0.6
|
||||||
|
github.com/golang-queue/queue v0.0.10
|
||||||
|
github.com/golang-queue/redisdb v0.0.5
|
||||||
|
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-20210731212030-00e7b986815b
|
||||||
|
github.com/prometheus/client_golang v1.10.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
|
||||||
|
github.com/stretchr/testify v1.7.0
|
||||||
|
github.com/syndtr/goleveldb v1.0.0
|
||||||
|
github.com/thoas/stats v0.0.0-20190407194641-965cb2de1678
|
||||||
|
github.com/tidwall/buntdb v1.2.0
|
||||||
|
github.com/tidwall/gjson v1.12.1 // indirect
|
||||||
|
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.27.1
|
||||||
|
)
|
||||||
|
|
||||||
|
replace github.com/msalihkarakasli/go-hms-push => github.com/spawn2kill/go-hms-push v0.0.0-20211125124117-e20af53b1304
|
807
push/gorush-with-mipush/src/go.sum
Normal file
807
push/gorush-with-mipush/src/go.sum
Normal file
@ -0,0 +1,807 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||||
|
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
|
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||||
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
|
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||||
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
|
||||||
|
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||||
|
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
|
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||||
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863 h1:BRrxwOZBolJN4gIwvZMJY1tzqBvQgpaZiQRuIDD40jM=
|
||||||
|
github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
|
||||||
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
|
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||||
|
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
|
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
|
github.com/apex/gateway v1.1.2 h1:OWyLov8eaau8YhkYKkRuOAYqiUhpBJalBR1o+3FzX+8=
|
||||||
|
github.com/apex/gateway v1.1.2/go.mod h1:AMTkVbz5u5Hvd6QOGhhg0JUrNgCcLVu3XNJOGntdoB4=
|
||||||
|
github.com/appleboy/gin-status-api v1.1.0 h1:zoXePlNxk/Aa3Jmh8TI2xX0KTF8iET/QwOM065pcrok=
|
||||||
|
github.com/appleboy/gin-status-api v1.1.0/go.mod h1:qUmpFERWhlzRX4Hx+fEznIio8gXAXEDpEnb0Ald1d+g=
|
||||||
|
github.com/appleboy/go-fcm v0.1.5 h1:fKbcZf/7vwGsvDkcop8a+kCHnK+tt4wXX0X7uEzwI6E=
|
||||||
|
github.com/appleboy/go-fcm v0.1.5/go.mod h1:MSxZ4LqGRsnywOjnlXJXMqbjZrG4vf+0oHitfC9HRH0=
|
||||||
|
github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4=
|
||||||
|
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
|
||||||
|
github.com/appleboy/graceful v0.0.3 h1:qEnm61ofF76fTo2UISfjRZVhMhFnkLKTBJoWcK9lBXQ=
|
||||||
|
github.com/appleboy/graceful v0.0.3/go.mod h1:Q2mVx0t+N0lCDZc5MJudbcpTm6cgGM/J2gZCZIqD9dc=
|
||||||
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||||
|
github.com/asdine/storm/v3 v3.2.1 h1:I5AqhkPK6nBZ/qJXySdI7ot5BlXSZ7qvDY1zAn5ZJac=
|
||||||
|
github.com/asdine/storm/v3 v3.2.1/go.mod h1:LEpXwGt4pIqrE/XcTvCnZHT5MgZCV6Ub9q7yQzOFWr0=
|
||||||
|
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||||
|
github.com/aws/aws-lambda-go v1.17.0 h1:Ogihmi8BnpmCNktKAGpNwSiILNNING1MiosnKUfU8m0=
|
||||||
|
github.com/aws/aws-lambda-go v1.17.0/go.mod h1:FEwgPLE6+8wcGBTe5cJN3JWurd1Ztm9zN4jsXsjzKKw=
|
||||||
|
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||||
|
github.com/buger/jsonparser v0.0.0-20191204142016-1a29609e0929/go.mod h1:tgcrVJ81GPSF0mz+0nu1Xaz0fazGPrmmJfJtxjbHhUQ=
|
||||||
|
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
|
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||||
|
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
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=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
|
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/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=
|
||||||
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||||
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
|
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
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/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/geek-go/xmpush v0.0.0-20200624150426-da36515dfc49 h1:naokiojfByv5V87OEWLYGeqDk0HNSn9jJ5fK0M/g6kw=
|
||||||
|
github.com/geek-go/xmpush v0.0.0-20200624150426-da36515dfc49/go.mod h1:tS5MqiTbVThcXwqKqn2KQIphJZ7xlWEkWy55SG3Ey0I=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
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.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||||
|
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=
|
||||||
|
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||||
|
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||||
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
|
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.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.4 h1:in1fM5Aa5HYeuyXCC5A00zvWxvVvBs9gdCiIr429u7I=
|
||||||
|
github.com/golang-queue/nats v0.0.4/go.mod h1:P82IIiPlNT+hGUvfddwJCn+yXd8tPeKtS9UK4AU5+I4=
|
||||||
|
github.com/golang-queue/nsq v0.0.6 h1:GXk9Dx9ex3/rQDSaK78RK2B0CBNc0ym45hclEjNDNEk=
|
||||||
|
github.com/golang-queue/nsq v0.0.6/go.mod h1:oKhZjEiAZ4scaQTePCSSnsmvyHb6ID0AsqE5rtKrAOE=
|
||||||
|
github.com/golang-queue/queue v0.0.10 h1:cGqMgHMf2eamwdd3hmOzGcSQogGu9tMhhVYPQMrMC1g=
|
||||||
|
github.com/golang-queue/queue v0.0.10/go.mod h1:ku8iyjYffqYY6Duts+xl+QYfN3/KDK4MEvXMZUkHyio=
|
||||||
|
github.com/golang-queue/redisdb v0.0.5 h1:kW+zXopFVtBmd0/19aD3fZCWc1OoRbOV+MpXo2OBp+s=
|
||||||
|
github.com/golang-queue/redisdb v0.0.5/go.mod h1:3LzXV4ldTCNKT0LsZXiKEhbrOM5gGISLQjYuPip+geM=
|
||||||
|
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=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
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.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/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/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=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||||
|
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||||
|
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
|
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
|
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||||
|
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||||
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||||
|
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/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=
|
||||||
|
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||||
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
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=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||||
|
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||||
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
|
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||||
|
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||||
|
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||||
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
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.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=
|
||||||
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
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=
|
||||||
|
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
|
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||||
|
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||||
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
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/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.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.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=
|
||||||
|
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
|
||||||
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
|
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||||
|
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||||
|
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||||
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
|
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||||
|
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||||
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||||
|
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||||
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
|
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
|
||||||
|
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||||
|
github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg=
|
||||||
|
github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||||
|
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||||
|
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||||
|
github.com/prometheus/common v0.18.0 h1:WCVKW7aL6LEe1uryfI9dnEc2ZqNB1Fn0ok930v0iL1Y=
|
||||||
|
github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||||
|
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
|
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||||
|
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
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.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=
|
||||||
|
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||||
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
github.com/sideshow/apns2 v0.20.0 h1:5Lzk4DUq+waVc6/BkKzpDTpQjtk/BZOP0YsayBpY1NE=
|
||||||
|
github.com/sideshow/apns2 v0.20.0/go.mod h1:f7dArLPLbiZ3qPdzzrZXdCSlMp8FD0p6z7tHssDOLvk=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
|
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||||
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
|
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||||
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||||
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
github.com/spawn2kill/go-hms-push v0.0.0-20211125124117-e20af53b1304 h1:NFx3I+/cQkqXlnrDzyOAXUDKWFjPQBcO0LSqowMn1Jo=
|
||||||
|
github.com/spawn2kill/go-hms-push v0.0.0-20211125124117-e20af53b1304/go.mod h1:4X2lQHsWGt+e3uRK124A6ndq3IIVymTAzEI9A1kIQKc=
|
||||||
|
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||||
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||||
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
|
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
|
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||||
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
|
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
||||||
|
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
|
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
|
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
|
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
|
github.com/thoas/stats v0.0.0-20190407194641-965cb2de1678 h1:kFej3rMKjbzysHYvLmv5iOlbRymDMkNJxbovYb/iP0c=
|
||||||
|
github.com/thoas/stats v0.0.0-20190407194641-965cb2de1678/go.mod h1:GkZsNBOco11YY68OnXUARbSl26IOXXAeYf6ZKmSZR2M=
|
||||||
|
github.com/tidwall/btree v0.3.0 h1:LcwmLI5kv+AaH/xnBgOuKfbu5eLBWVdWTpD2o+qSRdU=
|
||||||
|
github.com/tidwall/btree v0.3.0/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8=
|
||||||
|
github.com/tidwall/buntdb v1.2.0 h1:8KOzf5Gg97DoCMSOgcwZjnM0FfROtq0fcZkPW54oGKU=
|
||||||
|
github.com/tidwall/buntdb v1.2.0/go.mod h1:XLza/dhlwzO6dc5o/KWor4kfZSt3BP8QV+77ZMKfI58=
|
||||||
|
github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
|
||||||
|
github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
|
||||||
|
github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo=
|
||||||
|
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
|
github.com/tidwall/grect v0.1.0 h1:ICcKWD5uu5A5fmxApGIa0QRvfGnSWKRd07POT08CQSA=
|
||||||
|
github.com/tidwall/grect v0.1.0/go.mod h1:sa5O42oP6jWfTShL9ka6Sgmg3TgIK649veZe05B7+J8=
|
||||||
|
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
|
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
|
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||||
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8=
|
||||||
|
github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ=
|
||||||
|
github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE=
|
||||||
|
github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw=
|
||||||
|
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.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=
|
||||||
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
|
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
|
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
|
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||||
|
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||||
|
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/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
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=
|
||||||
|
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||||
|
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||||
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
|
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=
|
||||||
|
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||||
|
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||||
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
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-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=
|
||||||
|
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||||
|
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
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/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||||
|
golang.org/x/mod v0.4.2/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=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
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-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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
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=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
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-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=
|
||||||
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
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-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-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=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
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/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=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
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-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=
|
||||||
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
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/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
|
||||||
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
|
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||||
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||||
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.36.1 h1:cmUfbeGKnz9+2DD/UYsMQXeqbHZqZDs4eQwW0sFOpBY=
|
||||||
|
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
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/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=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
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/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.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=
|
||||||
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
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/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=
|
||||||
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||||
|
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
23
push/gorush-with-mipush/src/helm/gorush/.helmignore
Normal file
23
push/gorush-with-mipush/src/helm/gorush/.helmignore
Normal file
@ -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/
|
11
push/gorush-with-mipush/src/helm/gorush/Chart.yaml
Normal file
11
push/gorush-with-mipush/src/helm/gorush/Chart.yaml
Normal file
@ -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
|
22
push/gorush-with-mipush/src/helm/gorush/templates/NOTES.txt
Normal file
22
push/gorush-with-mipush/src/helm/gorush/templates/NOTES.txt
Normal file
@ -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 }}
|
@ -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 }}
|
@ -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 }}
|
@ -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 }}
|
29
push/gorush-with-mipush/src/helm/gorush/templates/hpa.yaml
Normal file
29
push/gorush-with-mipush/src/helm/gorush/templates/hpa.yaml
Normal file
@ -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 }}
|
@ -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 }}
|
@ -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 }}
|
@ -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 }}
|
73
push/gorush-with-mipush/src/helm/gorush/values.yaml
Normal file
73
push/gorush-with-mipush/src/helm/gorush/values.yaml
Normal file
@ -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: {}
|
20
push/gorush-with-mipush/src/k8s/gorush-aws-alb-ingress.yaml
Normal file
20
push/gorush-with-mipush/src/k8s/gorush-aws-alb-ingress.yaml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: gorush
|
||||||
|
namespace: gorush
|
||||||
|
annotations:
|
||||||
|
# Kubernetes Ingress Controller for AWS ALB
|
||||||
|
# https://github.com/coreos/alb-ingress-controller
|
||||||
|
alb.ingress.kubernetes.io/scheme: internet-facing
|
||||||
|
alb.ingress.kubernetes.io/subnets: subnet-aa3dfbe3,subnet-4aff342d
|
||||||
|
alb.ingress.kubernetes.io/security-groups: sg-71069b17
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: gorush.example.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
backend:
|
||||||
|
serviceName: gorush
|
||||||
|
servicePort: 8088
|
9
push/gorush-with-mipush/src/k8s/gorush-configmap.yaml
Normal file
9
push/gorush-with-mipush/src/k8s/gorush-configmap.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: gorush-config
|
||||||
|
namespace: gorush
|
||||||
|
data:
|
||||||
|
# stat
|
||||||
|
stat.engine: redis
|
||||||
|
stat.redis.host: redis:6379
|
40
push/gorush-with-mipush/src/k8s/gorush-deployment.yaml
Normal file
40
push/gorush-with-mipush/src/k8s/gorush-deployment.yaml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: gorush
|
||||||
|
namespace: gorush
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: gorush
|
||||||
|
tier: frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: gorush
|
||||||
|
tier: frontend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: appleboy/gorush
|
||||||
|
name: gorush
|
||||||
|
imagePullPolicy: Always
|
||||||
|
ports:
|
||||||
|
- containerPort: 8088
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 8088
|
||||||
|
initialDelaySeconds: 3
|
||||||
|
periodSeconds: 3
|
||||||
|
env:
|
||||||
|
- name: GORUSH_STAT_ENGINE
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: gorush-config
|
||||||
|
key: stat.engine
|
||||||
|
- name: GORUSH_STAT_REDIS_ADDR
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: gorush-config
|
||||||
|
key: stat.redis.host
|
4
push/gorush-with-mipush/src/k8s/gorush-namespace.yaml
Normal file
4
push/gorush-with-mipush/src/k8s/gorush-namespace.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: gorush
|
24
push/gorush-with-mipush/src/k8s/gorush-redis-deployment.yaml
Normal file
24
push/gorush-with-mipush/src/k8s/gorush-redis-deployment.yaml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: redis
|
||||||
|
namespace: gorush
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: redis
|
||||||
|
role: master
|
||||||
|
tier: backend
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: redis
|
||||||
|
role: master
|
||||||
|
tier: backend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: master
|
||||||
|
image: redis
|
||||||
|
ports:
|
||||||
|
- containerPort: 6379
|
17
push/gorush-with-mipush/src/k8s/gorush-redis-service.yaml
Normal file
17
push/gorush-with-mipush/src/k8s/gorush-redis-service.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: redis
|
||||||
|
namespace: gorush
|
||||||
|
labels:
|
||||||
|
app: redis
|
||||||
|
role: master
|
||||||
|
tier: backend
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 6379
|
||||||
|
targetPort: 6379
|
||||||
|
selector:
|
||||||
|
app: redis
|
||||||
|
role: master
|
||||||
|
tier: backend
|
25
push/gorush-with-mipush/src/k8s/gorush-service.yaml
Normal file
25
push/gorush-with-mipush/src/k8s/gorush-service.yaml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: gorush
|
||||||
|
namespace: gorush
|
||||||
|
labels:
|
||||||
|
app: gorush
|
||||||
|
tier: frontend
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: gorush
|
||||||
|
tier: frontend
|
||||||
|
# if your cluster supports it, uncomment the following to automatically create
|
||||||
|
# an external load-balanced IP for the frontend service.
|
||||||
|
# type: LoadBalancer
|
||||||
|
#
|
||||||
|
# if you want to expose the service to the outside (without a load balancer in front)
|
||||||
|
# type: NodePort
|
||||||
|
#
|
||||||
|
# if you want gorush to be accessible only within the cluster
|
||||||
|
# type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 80
|
||||||
|
targetPort: 8088
|
251
push/gorush-with-mipush/src/logx/log.go
Normal file
251
push/gorush-with-mipush/src/logx/log.go
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
package logx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"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})
|
||||||
|
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
|
||||||
|
type LogPushEntry struct {
|
||||||
|
ID string `json:"notif_id,omitempty"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Platform string `json:"platform"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var isTerm bool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
isTerm = isatty.IsTerminal(os.Stdout.Fd())
|
||||||
|
}
|
||||||
|
|
||||||
|
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{})
|
||||||
|
LogError.SetFormatter(&logrus.JSONFormatter{})
|
||||||
|
} else {
|
||||||
|
LogAccess.Formatter = &logrus.TextFormatter{
|
||||||
|
TimestampFormat: "2006/01/02 - 15:04:05",
|
||||||
|
FullTimestamp: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
LogError.Formatter = &logrus.TextFormatter{
|
||||||
|
TimestampFormat: "2006/01/02 - 15:04:05",
|
||||||
|
FullTimestamp: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set logger
|
||||||
|
if err = SetLogLevel(LogAccess, accessLevel); err != nil {
|
||||||
|
return errors.New("Set access log level error: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = SetLogLevel(LogError, errorLevel); err != nil {
|
||||||
|
return errors.New("Set error log level error: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = SetLogOut(LogAccess, accessLog); err != nil {
|
||||||
|
return errors.New("Set access log path error: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = SetLogOut(LogError, errorLog); err != nil {
|
||||||
|
return errors.New("Set error log path error: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogOut provide log stdout and stderr output
|
||||||
|
func SetLogOut(log *logrus.Logger, outString string) error {
|
||||||
|
switch outString {
|
||||||
|
case "stdout":
|
||||||
|
log.Out = os.Stdout
|
||||||
|
case "stderr":
|
||||||
|
log.Out = os.Stderr
|
||||||
|
default:
|
||||||
|
f, err := os.OpenFile(outString, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Out = f
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogLevel is define log level what you want
|
||||||
|
// log level: panic, fatal, error, warn, info and debug
|
||||||
|
func SetLogLevel(log *logrus.Logger, levelString string) error {
|
||||||
|
level, err := logrus.ParseLevel(levelString)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Level = level
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func colorForPlatForm(platform int) string {
|
||||||
|
switch platform {
|
||||||
|
case core.PlatFormIos:
|
||||||
|
return blue
|
||||||
|
case core.PlatFormAndroid:
|
||||||
|
return yellow
|
||||||
|
case core.PlatFormHuawei:
|
||||||
|
return green
|
||||||
|
default:
|
||||||
|
return reset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func typeForPlatForm(platform int) string {
|
||||||
|
switch platform {
|
||||||
|
case core.PlatFormIos:
|
||||||
|
return "ios"
|
||||||
|
case core.PlatFormAndroid:
|
||||||
|
return "android"
|
||||||
|
case core.PlatFormHuawei:
|
||||||
|
return "huawei"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hideToken(token string, markLen int) string {
|
||||||
|
if token == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(token) < markLen*2 {
|
||||||
|
return strings.Repeat("*", len(token))
|
||||||
|
}
|
||||||
|
|
||||||
|
start := token[len(token)-markLen:]
|
||||||
|
end := token[0:markLen]
|
||||||
|
|
||||||
|
result := strings.Replace(token, start, strings.Repeat("*", markLen), -1)
|
||||||
|
result = strings.Replace(result, end, strings.Repeat("*", markLen), -1)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLogPushEntry get push data into log structure
|
||||||
|
func GetLogPushEntry(input *InputLog) LogPushEntry {
|
||||||
|
var errMsg string
|
||||||
|
|
||||||
|
plat := typeForPlatForm(input.Platform)
|
||||||
|
|
||||||
|
if input.Error != nil {
|
||||||
|
errMsg = input.Error.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
token := input.Token
|
||||||
|
if input.HideToken {
|
||||||
|
token = hideToken(input.Token, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
return LogPushEntry{
|
||||||
|
ID: input.ID,
|
||||||
|
Type: input.Status,
|
||||||
|
Platform: plat,
|
||||||
|
Token: token,
|
||||||
|
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(input *InputLog) LogPushEntry {
|
||||||
|
var platColor, resetColor, output string
|
||||||
|
|
||||||
|
if isTerm {
|
||||||
|
platColor = colorForPlatForm(input.Platform)
|
||||||
|
resetColor = reset
|
||||||
|
}
|
||||||
|
|
||||||
|
log := GetLogPushEntry(input)
|
||||||
|
|
||||||
|
if input.Format == "json" {
|
||||||
|
logJSON, _ := json.Marshal(log)
|
||||||
|
|
||||||
|
output = string(logJSON)
|
||||||
|
} else {
|
||||||
|
var typeColor string
|
||||||
|
switch input.Status {
|
||||||
|
case core.SucceededPush:
|
||||||
|
if isTerm {
|
||||||
|
typeColor = green
|
||||||
|
}
|
||||||
|
|
||||||
|
output = fmt.Sprintf("|%s %s %s| %s%s%s [%s] %s",
|
||||||
|
typeColor, log.Type, resetColor,
|
||||||
|
platColor, log.Platform, resetColor,
|
||||||
|
log.Token,
|
||||||
|
log.Message,
|
||||||
|
)
|
||||||
|
case core.FailedPush:
|
||||||
|
if isTerm {
|
||||||
|
typeColor = red
|
||||||
|
}
|
||||||
|
|
||||||
|
output = fmt.Sprintf("|%s %s %s| %s%s%s [%s] | %s | Error Message: %s",
|
||||||
|
typeColor, log.Type, resetColor,
|
||||||
|
platColor, log.Platform, resetColor,
|
||||||
|
log.Token,
|
||||||
|
log.Message,
|
||||||
|
log.Error,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch input.Status {
|
||||||
|
case core.SucceededPush:
|
||||||
|
LogAccess.Info(output)
|
||||||
|
case core.FailedPush:
|
||||||
|
LogError.Error(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
return log
|
||||||
|
}
|
0
push/gorush-with-mipush/src/logx/log/.gitkeep
Normal file
0
push/gorush-with-mipush/src/logx/log/.gitkeep
Normal file
0
push/gorush-with-mipush/src/logx/log/access.log
Normal file
0
push/gorush-with-mipush/src/logx/log/access.log
Normal file
45
push/gorush-with-mipush/src/logx/log_interface.go
Normal file
45
push/gorush-with-mipush/src/logx/log_interface.go
Normal file
@ -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...))
|
||||||
|
}
|
172
push/gorush-with-mipush/src/logx/log_test.go
Normal file
172
push/gorush-with-mipush/src/logx/log_test.go
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
package logx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"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,
|
||||||
|
))
|
||||||
|
|
||||||
|
isTerm = true
|
||||||
|
|
||||||
|
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, "huawei", typeForPlatForm(core.PlatFormHuawei))
|
||||||
|
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, green, colorForPlatForm(core.PlatFormHuawei))
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogPushEntry(t *testing.T) {
|
||||||
|
in := InputLog{}
|
||||||
|
|
||||||
|
in.Platform = 1
|
||||||
|
assert.Equal(t, "ios", GetLogPushEntry(&in).Platform)
|
||||||
|
|
||||||
|
in.Error = errors.New("error")
|
||||||
|
assert.Equal(t, "error", GetLogPushEntry(&in).Error)
|
||||||
|
|
||||||
|
in.Token = "1234567890"
|
||||||
|
in.HideToken = true
|
||||||
|
assert.Equal(t, "**********", GetLogPushEntry(&in).Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogPush(t *testing.T) {
|
||||||
|
in := InputLog{}
|
||||||
|
isTerm = true
|
||||||
|
|
||||||
|
in.Format = "json"
|
||||||
|
in.Status = "succeeded-push"
|
||||||
|
assert.Equal(t, "succeeded-push", LogPush(&in).Type)
|
||||||
|
|
||||||
|
in.Format = ""
|
||||||
|
in.Message = "success"
|
||||||
|
assert.Equal(t, "success", LogPush(&in).Message)
|
||||||
|
|
||||||
|
in.Status = "failed-push"
|
||||||
|
in.Message = "failed"
|
||||||
|
assert.Equal(t, "failed", LogPush(&in).Message)
|
||||||
|
}
|
502
push/gorush-with-mipush/src/main.go
Normal file
502
push/gorush-with-mipush/src/main.go
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"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/router"
|
||||||
|
"github.com/appleboy/gorush/rpc"
|
||||||
|
"github.com/appleboy/gorush/status"
|
||||||
|
|
||||||
|
"github.com/appleboy/graceful"
|
||||||
|
"github.com/golang-queue/nats"
|
||||||
|
"github.com/golang-queue/nsq"
|
||||||
|
"github.com/golang-queue/queue"
|
||||||
|
"github.com/golang-queue/redisdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
opts := config.ConfYaml{}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ping bool
|
||||||
|
showVersion bool
|
||||||
|
configFile string
|
||||||
|
topic string
|
||||||
|
message string
|
||||||
|
token string
|
||||||
|
title string
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.BoolVar(&showVersion, "version", 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.")
|
||||||
|
flag.StringVar(&opts.Ios.KeyPath, "i", "", "iOS certificate key file path")
|
||||||
|
flag.StringVar(&opts.Ios.KeyPath, "key", "", "iOS certificate key file path")
|
||||||
|
flag.StringVar(&opts.Ios.KeyID, "key-id", "", "iOS Key ID for P8 token")
|
||||||
|
flag.StringVar(&opts.Ios.TeamID, "team-id", "", "iOS Team ID for P8 token")
|
||||||
|
flag.StringVar(&opts.Ios.Password, "P", "", "iOS certificate password for gorush")
|
||||||
|
flag.StringVar(&opts.Ios.Password, "password", "", "iOS certificate password for gorush")
|
||||||
|
flag.StringVar(&opts.Android.APIKey, "k", "", "Android api key configuration for gorush")
|
||||||
|
flag.StringVar(&opts.Android.APIKey, "apikey", "", "Android api key configuration for gorush")
|
||||||
|
|
||||||
|
flag.StringVar(&opts.Huawei.AppSecret, "hk", "", "Huawei api key configuration for gorush")
|
||||||
|
flag.StringVar(&opts.Huawei.AppSecret, "hmskey", "", "Huawei api key configuration for gorush")
|
||||||
|
flag.StringVar(&opts.Huawei.AppID, "hid", "", "HMS app id configuration for gorush")
|
||||||
|
flag.StringVar(&opts.Huawei.AppID, "hmsid", "", "HMS app id configuration for gorush")
|
||||||
|
|
||||||
|
flag.StringVar(&opts.MI.AppSecret, "mk", "", "MIPUSH api key configuration for gorush")
|
||||||
|
flag.StringVar(&opts.MI.AppSecret, "mikey", "", "MIPUSH api key configuration for gorush")
|
||||||
|
flag.StringVar(&opts.MI.Package, "mp", "", "MIPUSH package id configuration for gorush")
|
||||||
|
flag.StringVar(&opts.MI.Package, "mipkg", "", "MIPUSH package id configuration for gorush")
|
||||||
|
|
||||||
|
flag.StringVar(&opts.Core.Address, "A", "", "address to bind")
|
||||||
|
flag.StringVar(&opts.Core.Address, "address", "", "address to bind")
|
||||||
|
flag.StringVar(&opts.Core.Port, "p", "", "port number for gorush")
|
||||||
|
flag.StringVar(&opts.Core.Port, "port", "", "port number for gorush")
|
||||||
|
flag.StringVar(&token, "t", "", "token string")
|
||||||
|
flag.StringVar(&token, "token", "", "token string")
|
||||||
|
flag.StringVar(&opts.Stat.Engine, "e", "", "store engine")
|
||||||
|
flag.StringVar(&opts.Stat.Engine, "engine", "", "store engine")
|
||||||
|
flag.StringVar(&opts.Stat.Redis.Addr, "redis-addr", "", "redis addr")
|
||||||
|
flag.StringVar(&message, "m", "", "notification message")
|
||||||
|
flag.StringVar(&message, "message", "", "notification message")
|
||||||
|
flag.StringVar(&title, "title", "", "notification title")
|
||||||
|
flag.BoolVar(&opts.Android.Enabled, "android", false, "send android notification")
|
||||||
|
flag.BoolVar(&opts.Huawei.Enabled, "huawei", false, "send huawei notification")
|
||||||
|
flag.BoolVar(&opts.Ios.Enabled, "ios", false, "send ios notification")
|
||||||
|
flag.BoolVar(&opts.MI.Enabled, "mi", false, "send mi notification")
|
||||||
|
flag.BoolVar(&opts.Ios.Production, "production", false, "production mode in iOS")
|
||||||
|
flag.StringVar(&topic, "topic", "", "apns topic in iOS")
|
||||||
|
flag.StringVar(&opts.Core.HTTPProxy, "proxy", "", "http proxy url")
|
||||||
|
flag.BoolVar(&ping, "ping", false, "ping server")
|
||||||
|
|
||||||
|
flag.Usage = usage
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
router.SetVersion(Version)
|
||||||
|
|
||||||
|
// Show version and exit
|
||||||
|
if showVersion {
|
||||||
|
router.PrintGoRushVersion()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set default parameters.
|
||||||
|
cfg, err := config.LoadConf(configFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Load yaml config file error: '%v'", err)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize push slots for concurrent iOS pushes
|
||||||
|
notify.MaxConcurrentIOSPushes = make(chan struct{}, cfg.Ios.MaxConcurrentPushes)
|
||||||
|
|
||||||
|
if opts.Ios.KeyPath != "" {
|
||||||
|
cfg.Ios.KeyPath = opts.Ios.KeyPath
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Ios.KeyID != "" {
|
||||||
|
cfg.Ios.KeyID = opts.Ios.KeyID
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Ios.TeamID != "" {
|
||||||
|
cfg.Ios.TeamID = opts.Ios.TeamID
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Ios.Password != "" {
|
||||||
|
cfg.Ios.Password = opts.Ios.Password
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Android.APIKey != "" {
|
||||||
|
cfg.Android.APIKey = opts.Android.APIKey
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Huawei.AppSecret != "" {
|
||||||
|
cfg.Huawei.AppSecret = opts.Huawei.AppSecret
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Huawei.AppID != "" {
|
||||||
|
cfg.Huawei.AppID = opts.Huawei.AppID
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Stat.Engine != "" {
|
||||||
|
cfg.Stat.Engine = opts.Stat.Engine
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Stat.Redis.Addr != "" {
|
||||||
|
cfg.Stat.Redis.Addr = opts.Stat.Redis.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// overwrite server port and address
|
||||||
|
if opts.Core.Port != "" {
|
||||||
|
cfg.Core.Port = opts.Core.Port
|
||||||
|
}
|
||||||
|
if opts.Core.Address != "" {
|
||||||
|
cfg.Core.Address = opts.Core.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
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 != "" {
|
||||||
|
cfg.Core.HTTPProxy = opts.Core.HTTPProxy
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Core.HTTPProxy != "" {
|
||||||
|
err = notify.SetProxy(cfg.Core.HTTPProxy)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logx.LogError.Fatalf("Set Proxy error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ping {
|
||||||
|
if err := pinger(cfg); err != nil {
|
||||||
|
logx.LogError.Warnf("ping server error: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// send android notification
|
||||||
|
if opts.Android.Enabled {
|
||||||
|
cfg.Android.Enabled = opts.Android.Enabled
|
||||||
|
req := ¬ify.PushNotification{
|
||||||
|
Platform: core.PlatFormAndroid,
|
||||||
|
Message: message,
|
||||||
|
Title: title,
|
||||||
|
}
|
||||||
|
|
||||||
|
// send message to single device
|
||||||
|
if token != "" {
|
||||||
|
req.Tokens = []string{token}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send topic message
|
||||||
|
if topic != "" {
|
||||||
|
req.To = topic
|
||||||
|
}
|
||||||
|
|
||||||
|
err := notify.CheckMessage(req)
|
||||||
|
if err != nil {
|
||||||
|
logx.LogError.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := status.InitAppStatus(cfg); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := notify.PushToAndroid(req, cfg); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// send huawei notification
|
||||||
|
if opts.Huawei.Enabled {
|
||||||
|
cfg.Huawei.Enabled = opts.Huawei.Enabled
|
||||||
|
req := ¬ify.PushNotification{
|
||||||
|
Platform: core.PlatFormHuawei,
|
||||||
|
Message: message,
|
||||||
|
Title: title,
|
||||||
|
}
|
||||||
|
|
||||||
|
// send message to single device
|
||||||
|
if token != "" {
|
||||||
|
req.Tokens = []string{token}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send topic message
|
||||||
|
if topic != "" {
|
||||||
|
req.To = topic
|
||||||
|
}
|
||||||
|
|
||||||
|
err := notify.CheckMessage(req)
|
||||||
|
if err != nil {
|
||||||
|
logx.LogError.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := status.InitAppStatus(cfg); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := notify.PushToHuawei(req, cfg); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// send ios notification
|
||||||
|
if opts.Ios.Enabled {
|
||||||
|
if opts.Ios.Production {
|
||||||
|
cfg.Ios.Production = opts.Ios.Production
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Ios.Enabled = opts.Ios.Enabled
|
||||||
|
req := ¬ify.PushNotification{
|
||||||
|
Platform: core.PlatFormIos,
|
||||||
|
Message: message,
|
||||||
|
Title: title,
|
||||||
|
}
|
||||||
|
|
||||||
|
// send message to single device
|
||||||
|
if token != "" {
|
||||||
|
req.Tokens = []string{token}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send topic message
|
||||||
|
if topic != "" {
|
||||||
|
req.Topic = topic
|
||||||
|
}
|
||||||
|
|
||||||
|
err := notify.CheckMessage(req)
|
||||||
|
if err != nil {
|
||||||
|
logx.LogError.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := status.InitAppStatus(cfg); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := notify.InitAPNSClient(cfg); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := notify.PushToIOS(req, cfg); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = notify.CheckPushConf(cfg); err != nil {
|
||||||
|
logx.LogError.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Core.PID.Path != "" {
|
||||||
|
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()),
|
||||||
|
)
|
||||||
|
case core.Redis:
|
||||||
|
w = redisdb.NewWorker(
|
||||||
|
redisdb.WithAddr(cfg.Queue.Redis.Addr),
|
||||||
|
redisdb.WithChannel(cfg.Queue.Redis.Channel),
|
||||||
|
redisdb.WithChannelSize(cfg.Queue.Redis.Size),
|
||||||
|
redisdb.WithRunFunc(notify.Run(cfg)),
|
||||||
|
redisdb.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()),
|
||||||
|
)
|
||||||
|
|
||||||
|
g := graceful.NewManager(
|
||||||
|
graceful.WithLogger(logx.QueueLogger()),
|
||||||
|
)
|
||||||
|
|
||||||
|
g.AddShutdownJob(func() error {
|
||||||
|
logx.LogAccess.Info("close the queue system, current queue usage: ", q.Usage())
|
||||||
|
// stop queue system and wait job completed
|
||||||
|
q.Release()
|
||||||
|
// close the connection with storage
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if cfg.Ios.Enabled {
|
||||||
|
if err = notify.InitAPNSClient(cfg); err != nil {
|
||||||
|
logx.LogError.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Android.Enabled {
|
||||||
|
if _, err = notify.InitFCMClient(cfg, cfg.Android.APIKey); err != nil {
|
||||||
|
logx.LogError.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Huawei.Enabled {
|
||||||
|
if _, err = notify.InitHMSClient(cfg, cfg.Huawei.AppSecret, cfg.Huawei.AppID); err != nil {
|
||||||
|
logx.LogError.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.AddRunningJob(func(ctx context.Context) error {
|
||||||
|
return router.RunHTTPServer(ctx, cfg, q)
|
||||||
|
})
|
||||||
|
|
||||||
|
g.AddRunningJob(func(ctx context.Context) error {
|
||||||
|
return rpc.RunGRPCServer(ctx, cfg)
|
||||||
|
})
|
||||||
|
|
||||||
|
<-g.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version control for notify.
|
||||||
|
var Version = "No Version Provided"
|
||||||
|
|
||||||
|
var usageStr = `
|
||||||
|
________ .__
|
||||||
|
/ _____/ ____ _______ __ __ ______| |__
|
||||||
|
/ \ ___ / _ \\_ __ \| | \/ ___/| | \
|
||||||
|
\ \_\ \( <_> )| | \/| | /\___ \ | Y \
|
||||||
|
\______ / \____/ |__| |____//____ >|___| /
|
||||||
|
\/ \/ \/
|
||||||
|
|
||||||
|
Usage: gorush [options]
|
||||||
|
|
||||||
|
Server Options:
|
||||||
|
-A, --address <address> Address to bind (default: any)
|
||||||
|
-p, --port <port> Use port for clients (default: 8088)
|
||||||
|
-c, --config <file> Configuration file path
|
||||||
|
-m, --message <message> Notification message
|
||||||
|
-t, --token <token> Notification token
|
||||||
|
-e, --engine <engine> Storage engine (memory, redis ...)
|
||||||
|
--title <title> Notification title
|
||||||
|
--proxy <proxy> Proxy URL
|
||||||
|
--pid <pid path> Process identifier path
|
||||||
|
--redis-addr <redis addr> Redis addr (default: localhost:6379)
|
||||||
|
--ping healthy check command for container
|
||||||
|
iOS Options:
|
||||||
|
-i, --key <file> certificate key file path
|
||||||
|
-P, --password <password> certificate key password
|
||||||
|
--ios enabled iOS (default: false)
|
||||||
|
--production iOS production mode (default: false)
|
||||||
|
Android Options:
|
||||||
|
-k, --apikey <api_key> Android API Key
|
||||||
|
--android enabled android (default: false)
|
||||||
|
Huawei Options:
|
||||||
|
-hk, --hmskey <hms_key> HMS App Secret
|
||||||
|
-hid, --hmsid <hms_id> HMS App ID
|
||||||
|
--huawei enabled huawei (default: false)
|
||||||
|
MIPUSH Options:
|
||||||
|
-mk, --mikey <mipush_key> MIPUSH App Secret
|
||||||
|
-mp, --mipkg <mipush_package> MIPUSH Package
|
||||||
|
--mi enabled mipush (default: false)
|
||||||
|
Common Options:
|
||||||
|
--topic <topic> iOS, Android or Huawei topic message
|
||||||
|
-h, --help Show this message
|
||||||
|
-V, --version Show version
|
||||||
|
`
|
||||||
|
|
||||||
|
// usage will print out the flag options for the server.
|
||||||
|
func usage() {
|
||||||
|
fmt.Printf("%s\n", usageStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handles pinging the endpoint and returns an error if the
|
||||||
|
// agent is in an unhealthy state.
|
||||||
|
func pinger(cfg *config.ConfYaml) error {
|
||||||
|
transport := &http.Transport{
|
||||||
|
Dial: (&net.Dialer{
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
}).Dial,
|
||||||
|
TLSHandshakeTimeout: 5 * time.Second,
|
||||||
|
}
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: time.Second * 10,
|
||||||
|
Transport: transport,
|
||||||
|
}
|
||||||
|
resp, err := client.Get("http://localhost:" + cfg.Core.Port + cfg.API.HealthURI)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return fmt.Errorf("server returned non-200 status code")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPIDFile(cfg *config.ConfYaml) error {
|
||||||
|
if !cfg.Core.PID.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pidPath := cfg.Core.PID.Path
|
||||||
|
_, err := os.Stat(pidPath)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Create(pidPath)
|
||||||
|
if err != nil {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("%s already exists", pidPath)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
134
push/gorush-with-mipush/src/metric/metrics.go
Normal file
134
push/gorush-with-mipush/src/metric/metrics.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package metric
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/appleboy/gorush/status"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const namespace = "gorush_"
|
||||||
|
|
||||||
|
// Metrics implements the prometheus.Metrics interface and
|
||||||
|
// exposes gorush metrics for prometheus
|
||||||
|
type Metrics struct {
|
||||||
|
TotalPushCount *prometheus.Desc
|
||||||
|
IosSuccess *prometheus.Desc
|
||||||
|
IosError *prometheus.Desc
|
||||||
|
AndroidSuccess *prometheus.Desc
|
||||||
|
AndroidError *prometheus.Desc
|
||||||
|
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(c ...func() int) Metrics {
|
||||||
|
m := Metrics{
|
||||||
|
TotalPushCount: prometheus.NewDesc(
|
||||||
|
namespace+"total_push_count",
|
||||||
|
"Number of push count",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
IosSuccess: prometheus.NewDesc(
|
||||||
|
namespace+"ios_success",
|
||||||
|
"Number of iOS success count",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
IosError: prometheus.NewDesc(
|
||||||
|
namespace+"ios_error",
|
||||||
|
"Number of iOS fail count",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
AndroidSuccess: prometheus.NewDesc(
|
||||||
|
namespace+"android_success",
|
||||||
|
"Number of android success count",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
AndroidError: prometheus.NewDesc(
|
||||||
|
namespace+"android_fail",
|
||||||
|
"Number of android fail count",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
HuaweiSuccess: prometheus.NewDesc(
|
||||||
|
namespace+"huawei_success",
|
||||||
|
"Number of huawei success count",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
HuaweiError: prometheus.NewDesc(
|
||||||
|
namespace+"huawei_fail",
|
||||||
|
"Number of huawei fail count",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
QueueUsage: prometheus.NewDesc(
|
||||||
|
namespace+"queue_usage",
|
||||||
|
"Length of internal queue",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
GetQueueUsage: getGetQueueUsage,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c) > 0 {
|
||||||
|
m.GetQueueUsage = c[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe returns all possible prometheus.Desc
|
||||||
|
func (c Metrics) Describe(ch chan<- *prometheus.Desc) {
|
||||||
|
ch <- c.TotalPushCount
|
||||||
|
ch <- c.IosSuccess
|
||||||
|
ch <- c.IosError
|
||||||
|
ch <- c.AndroidSuccess
|
||||||
|
ch <- c.AndroidError
|
||||||
|
ch <- c.HuaweiSuccess
|
||||||
|
ch <- c.HuaweiError
|
||||||
|
ch <- c.QueueUsage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect returns the metrics with values
|
||||||
|
func (c Metrics) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.TotalPushCount,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(status.StatStorage.GetTotalCount()),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.IosSuccess,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(status.StatStorage.GetIosSuccess()),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.IosError,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(status.StatStorage.GetIosError()),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.AndroidSuccess,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(status.StatStorage.GetAndroidSuccess()),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.AndroidError,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(status.StatStorage.GetAndroidError()),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.HuaweiSuccess,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(status.StatStorage.GetHuaweiSuccess()),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.HuaweiError,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(status.StatStorage.GetHuaweiError()),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.QueueUsage,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(c.GetQueueUsage()),
|
||||||
|
)
|
||||||
|
}
|
15
push/gorush-with-mipush/src/metric/metrics_test.go
Normal file
15
push/gorush-with-mipush/src/metric/metrics_test.go
Normal file
@ -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())
|
||||||
|
}
|
13
push/gorush-with-mipush/src/netlify.toml
Normal file
13
push/gorush-with-mipush/src/netlify.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[build]
|
||||||
|
command = "make build_linux_lambda"
|
||||||
|
functions = "release/linux/lambda"
|
||||||
|
|
||||||
|
[build.environment]
|
||||||
|
GO_VERSION = "1.16"
|
||||||
|
GO_IMPORT_PATH = "github.com/appleboy/gorush"
|
||||||
|
GO111MODULE = "on"
|
||||||
|
|
||||||
|
[[redirects]]
|
||||||
|
from = "/*"
|
||||||
|
to = "/.netlify/functions/gorush/:splat"
|
||||||
|
status = 200
|
53
push/gorush-with-mipush/src/notify/feedback.go
Normal file
53
push/gorush-with-mipush/src/notify/feedback.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DispatchFeedback sends a feedback to the configured gateway.
|
||||||
|
func DispatchFeedback(log logx.LogPushEntry, url string, timeout int64) error {
|
||||||
|
if url == "" {
|
||||||
|
return errors.New("url can't be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, err := json.Marshal(log)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
|
||||||
|
transport := &http.Transport{
|
||||||
|
Dial: (&net.Dialer{
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
}).Dial,
|
||||||
|
TLSHandshakeTimeout: 5 * time.Second,
|
||||||
|
}
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: time.Duration(timeout) * time.Second,
|
||||||
|
Transport: transport,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
|
||||||
|
if resp != nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
75
push/gorush-with-mipush/src/notify/feedback_test.go
Normal file
75
push/gorush-with-mipush/src/notify/feedback_test.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/config"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEmptyFeedbackURL(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
logEntry := logx.LogPushEntry{
|
||||||
|
ID: "",
|
||||||
|
Type: "",
|
||||||
|
Platform: "",
|
||||||
|
Token: "",
|
||||||
|
Message: "",
|
||||||
|
Error: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := DispatchFeedback(logEntry, cfg.Core.FeedbackURL, cfg.Core.FeedbackTimeout)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHTTPErrorInFeedbackCall(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
cfg.Core.FeedbackURL = "http://test.example.com/api/"
|
||||||
|
logEntry := logx.LogPushEntry{
|
||||||
|
ID: "",
|
||||||
|
Type: "",
|
||||||
|
Platform: "",
|
||||||
|
Token: "",
|
||||||
|
Message: "",
|
||||||
|
Error: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := DispatchFeedback(logEntry, cfg.Core.FeedbackURL, cfg.Core.FeedbackTimeout)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSuccessfulFeedbackCall(t *testing.T) {
|
||||||
|
// Mock http server
|
||||||
|
httpMock := httptest.NewServer(
|
||||||
|
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.URL.Path == "/dispatch" {
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
_, err := w.Write([]byte(`{}`))
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
defer httpMock.Close()
|
||||||
|
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
cfg.Core.FeedbackURL = httpMock.URL
|
||||||
|
logEntry := logx.LogPushEntry{
|
||||||
|
ID: "",
|
||||||
|
Type: "",
|
||||||
|
Platform: "",
|
||||||
|
Token: "",
|
||||||
|
Message: "",
|
||||||
|
Error: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := DispatchFeedback(logEntry, cfg.Core.FeedbackURL, cfg.Core.FeedbackTimeout)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
20
push/gorush-with-mipush/src/notify/global.go
Normal file
20
push/gorush-with-mipush/src/notify/global.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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
|
||||||
|
// MIPUSHClient is mi push client
|
||||||
|
MIPUSHClient *XMPush
|
||||||
|
// MaxConcurrentIOSPushes pool to limit the number of concurrent iOS pushes
|
||||||
|
MaxConcurrentIOSPushes chan struct{}
|
||||||
|
)
|
19
push/gorush-with-mipush/src/notify/main_test.go
Normal file
19
push/gorush-with-mipush/src/notify/main_test.go
Normal file
@ -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())
|
||||||
|
}
|
273
push/gorush-with-mipush/src/notify/notification.go
Normal file
273
push/gorush-with-mipush/src/notify/notification.go
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"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{}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ApnsPriorityLow will tell APNs to send the push message at a time that takes
|
||||||
|
// into account power considerations for the device. Notifications with this
|
||||||
|
// priority might be grouped and delivered in bursts. They are throttled, and
|
||||||
|
// in some cases are not delivered.
|
||||||
|
ApnsPriorityLow = 5
|
||||||
|
|
||||||
|
// ApnsPriorityHigh will tell APNs to send the push message immediately.
|
||||||
|
// Notifications with this priority must trigger an alert, sound, or badge on
|
||||||
|
// the target device. It is an error to use this priority for a push
|
||||||
|
// notification that contains only the content-available key.
|
||||||
|
ApnsPriorityHigh = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
// Alert is APNs payload
|
||||||
|
type Alert struct {
|
||||||
|
Action string `json:"action,omitempty"`
|
||||||
|
ActionLocKey string `json:"action-loc-key,omitempty"`
|
||||||
|
Body string `json:"body,omitempty"`
|
||||||
|
LaunchImage string `json:"launch-image,omitempty"`
|
||||||
|
LocArgs []string `json:"loc-args,omitempty"`
|
||||||
|
LocKey string `json:"loc-key,omitempty"`
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
Subtitle string `json:"subtitle,omitempty"`
|
||||||
|
TitleLocArgs []string `json:"title-loc-args,omitempty"`
|
||||||
|
TitleLocKey string `json:"title-loc-key,omitempty"`
|
||||||
|
SummaryArg string `json:"summary-arg,omitempty"`
|
||||||
|
SummaryArgCount int `json:"summary-arg-count,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestPush support multiple notification request.
|
||||||
|
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 {
|
||||||
|
// Common
|
||||||
|
ID string `json:"notif_id,omitempty"`
|
||||||
|
Tokens []string `json:"tokens" binding:"required"`
|
||||||
|
Platform int `json:"platform" binding:"required"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
Image string `json:"image,omitempty"`
|
||||||
|
Priority string `json:"priority,omitempty"`
|
||||||
|
ContentAvailable bool `json:"content_available,omitempty"`
|
||||||
|
MutableContent bool `json:"mutable_content,omitempty"`
|
||||||
|
Sound interface{} `json:"sound,omitempty"`
|
||||||
|
Data D `json:"data,omitempty"`
|
||||||
|
Retry int `json:"retry,omitempty"`
|
||||||
|
|
||||||
|
// Android
|
||||||
|
APIKey string `json:"api_key,omitempty"`
|
||||||
|
To string `json:"to,omitempty"`
|
||||||
|
CollapseKey string `json:"collapse_key,omitempty"`
|
||||||
|
DelayWhileIdle bool `json:"delay_while_idle,omitempty"`
|
||||||
|
TimeToLive *uint `json:"time_to_live,omitempty"`
|
||||||
|
RestrictedPackageName string `json:"restricted_package_name,omitempty"`
|
||||||
|
DryRun bool `json:"dry_run,omitempty"`
|
||||||
|
Condition string `json:"condition,omitempty"`
|
||||||
|
Notification *fcm.Notification `json:"notification,omitempty"`
|
||||||
|
|
||||||
|
// Huawei
|
||||||
|
AppID string `json:"app_id,omitempty"`
|
||||||
|
AppSecret string `json:"app_secret,omitempty"`
|
||||||
|
HuaweiNotification *model.AndroidNotification `json:"huawei_notification,omitempty"`
|
||||||
|
HuaweiData string `json:"huawei_data,omitempty"`
|
||||||
|
HuaweiCollapseKey int `json:"huawei_collapse_key,omitempty"`
|
||||||
|
HuaweiTTL string `json:"huawei_ttl,omitempty"`
|
||||||
|
BiTag string `json:"bi_tag,omitempty"`
|
||||||
|
FastAppTarget int `json:"fast_app_target,omitempty"`
|
||||||
|
|
||||||
|
// iOS
|
||||||
|
Expiration *int64 `json:"expiration,omitempty"`
|
||||||
|
ApnsID string `json:"apns_id,omitempty"`
|
||||||
|
CollapseID string `json:"collapse_id,omitempty"`
|
||||||
|
Topic string `json:"topic,omitempty"`
|
||||||
|
PushType string `json:"push_type,omitempty"`
|
||||||
|
Badge *int `json:"badge,omitempty"`
|
||||||
|
Category string `json:"category,omitempty"`
|
||||||
|
ThreadID string `json:"thread-id,omitempty"`
|
||||||
|
URLArgs []string `json:"url-args,omitempty"`
|
||||||
|
Alert Alert `json:"alert,omitempty"`
|
||||||
|
Production bool `json:"production,omitempty"`
|
||||||
|
Development bool `json:"development,omitempty"`
|
||||||
|
SoundName string `json:"name,omitempty"`
|
||||||
|
SoundVolume float32 `json:"volume,omitempty"`
|
||||||
|
Apns D `json:"apns,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 == core.PlatFormAndroid {
|
||||||
|
return p.To != "" && strings.HasPrefix(p.To, "/topics/") || p.Condition != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Platform == core.PlatFormHuawei {
|
||||||
|
return p.Topic != "" || p.Condition != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckMessage for check request message
|
||||||
|
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"
|
||||||
|
logx.LogAccess.Debug(msg)
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Tokens) == core.PlatFormIos && req.Tokens[0] == "" {
|
||||||
|
msg = "the token must not be empty"
|
||||||
|
logx.LogAccess.Debug(msg)
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Platform == core.PlatFormAndroid && len(req.Tokens) > 1000 {
|
||||||
|
msg = "the message may specify at most 1000 registration IDs"
|
||||||
|
logx.LogAccess.Debug(msg)
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Platform == core.PlatFormHuawei && len(req.Tokens) > 500 {
|
||||||
|
msg = "the message may specify at most 500 registration IDs for Huawei"
|
||||||
|
logx.LogAccess.Debug(msg)
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref
|
||||||
|
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)"
|
||||||
|
logx.LogAccess.Debug(msg)
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProxy only working for FCM server.
|
||||||
|
func SetProxy(proxy string) error {
|
||||||
|
proxyURL, err := url.ParseRequestURI(proxy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
http.DefaultTransport = &http.Transport{Proxy: http.ProxyURL(proxyURL)}
|
||||||
|
logx.LogAccess.Debug("Set http proxy as " + proxy)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckPushConf provide check your 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 cfg.Ios.Enabled {
|
||||||
|
if cfg.Ios.KeyPath == "" && cfg.Ios.KeyBase64 == "" {
|
||||||
|
return errors.New("missing iOS certificate key")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check certificate file exist
|
||||||
|
if cfg.Ios.KeyPath != "" {
|
||||||
|
if _, err := os.Stat(cfg.Ios.KeyPath); os.IsNotExist(err) {
|
||||||
|
return errors.New("certificate file does not exist")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Android.Enabled {
|
||||||
|
if cfg.Android.APIKey == "" {
|
||||||
|
return errors.New("Missing Android API Key")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Huawei.Enabled {
|
||||||
|
if cfg.Huawei.AppSecret == "" {
|
||||||
|
return errors.New("Missing Huawei App Secret")
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
case core.PlaFormMI:
|
||||||
|
resp, err = PushToMI(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
|
||||||
|
}
|
||||||
|
}
|
463
push/gorush-with-mipush/src/notify/notification_apns.go
Normal file
463
push/gorush-with-mipush/src/notify/notification_apns.go
Normal file
@ -0,0 +1,463 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
"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"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
idleConnTimeout = 90 * time.Second
|
||||||
|
tlsDialTimeout = 20 * time.Second
|
||||||
|
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) {
|
||||||
|
return func(network, addr string) (net.Conn, error) {
|
||||||
|
dialer := &net.Dialer{
|
||||||
|
Timeout: tlsDialTimeout,
|
||||||
|
KeepAlive: tcpKeepAlive,
|
||||||
|
}
|
||||||
|
return tls.DialWithDialer(dialer, network, addr, cfg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sound sets the aps sound on the payload.
|
||||||
|
type Sound struct {
|
||||||
|
Critical int `json:"critical,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Volume float32 `json:"volume,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitAPNSClient use for initialize APNs Client.
|
||||||
|
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 cfg.Ios.KeyPath != "" {
|
||||||
|
ext = filepath.Ext(cfg.Ios.KeyPath)
|
||||||
|
|
||||||
|
switch ext {
|
||||||
|
case ".p12":
|
||||||
|
certificateKey, err = certificate.FromP12File(cfg.Ios.KeyPath, cfg.Ios.Password)
|
||||||
|
case ".pem":
|
||||||
|
certificateKey, err = certificate.FromPemFile(cfg.Ios.KeyPath, cfg.Ios.Password)
|
||||||
|
case ".p8":
|
||||||
|
authKey, err = token.AuthKeyFromFile(cfg.Ios.KeyPath)
|
||||||
|
default:
|
||||||
|
err = errors.New("wrong certificate key extension")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logx.LogError.Error("Cert Error:", err.Error())
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if cfg.Ios.KeyBase64 != "" {
|
||||||
|
ext = "." + cfg.Ios.KeyType
|
||||||
|
key, err := base64.StdEncoding.DecodeString(cfg.Ios.KeyBase64)
|
||||||
|
if err != nil {
|
||||||
|
logx.LogError.Error("base64 decode error:", err.Error())
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch ext {
|
||||||
|
case ".p12":
|
||||||
|
certificateKey, err = certificate.FromP12Bytes(key, cfg.Ios.Password)
|
||||||
|
case ".pem":
|
||||||
|
certificateKey, err = certificate.FromPemBytes(key, cfg.Ios.Password)
|
||||||
|
case ".p8":
|
||||||
|
authKey, err = token.AuthKeyFromBytes(key)
|
||||||
|
default:
|
||||||
|
err = errors.New("wrong certificate key type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logx.LogError.Error("Cert Error:", err.Error())
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ext == ".p8" {
|
||||||
|
if cfg.Ios.KeyID == "" || cfg.Ios.TeamID == "" {
|
||||||
|
msg := "You should provide ios.KeyID and ios.TeamID for P8 token"
|
||||||
|
logx.LogError.Error(msg)
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
token := &token.Token{
|
||||||
|
AuthKey: authKey,
|
||||||
|
// KeyID from developer account (Certificates, Identifiers & Profiles -> Keys)
|
||||||
|
KeyID: cfg.Ios.KeyID,
|
||||||
|
// TeamID from developer account (View Account -> Membership)
|
||||||
|
TeamID: cfg.Ios.TeamID,
|
||||||
|
}
|
||||||
|
|
||||||
|
ApnsClient, err = newApnsTokenClient(cfg, token)
|
||||||
|
} else {
|
||||||
|
ApnsClient, err = newApnsClient(cfg, certificateKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if h2Transport, ok := ApnsClient.HTTPClient.Transport.(*http2.Transport); ok {
|
||||||
|
configureHTTP2ConnHealthCheck(h2Transport)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logx.LogError.Error("Transport Error:", err.Error())
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
doOnce.Do(func() {
|
||||||
|
MaxConcurrentIOSPushes = make(chan struct{}, cfg.Ios.MaxConcurrentPushes)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newApnsClient(cfg *config.ConfYaml, certificate tls.Certificate) (*apns2.Client, error) {
|
||||||
|
var client *apns2.Client
|
||||||
|
|
||||||
|
if cfg.Ios.Production {
|
||||||
|
client = apns2.NewClient(certificate).Production()
|
||||||
|
} else {
|
||||||
|
client = apns2.NewClient(certificate).Development()
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Core.HTTPProxy == "" {
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{certificate},
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(certificate.Certificate) > 0 {
|
||||||
|
tlsConfig.BuildNameToCertificate()
|
||||||
|
}
|
||||||
|
|
||||||
|
transport := &http.Transport{
|
||||||
|
TLSClientConfig: tlsConfig,
|
||||||
|
DialTLS: DialTLS(tlsConfig),
|
||||||
|
Proxy: http.DefaultTransport.(*http.Transport).Proxy,
|
||||||
|
IdleConnTimeout: idleConnTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
h2Transport, err := http2.ConfigureTransports(transport)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
configureHTTP2ConnHealthCheck(h2Transport)
|
||||||
|
|
||||||
|
client.HTTPClient.Transport = transport
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newApnsTokenClient(cfg *config.ConfYaml, token *token.Token) (*apns2.Client, error) {
|
||||||
|
var client *apns2.Client
|
||||||
|
|
||||||
|
if cfg.Ios.Production {
|
||||||
|
client = apns2.NewTokenClient(token).Production()
|
||||||
|
} else {
|
||||||
|
client = apns2.NewTokenClient(token).Development()
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Core.HTTPProxy == "" {
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
transport := &http.Transport{
|
||||||
|
DialTLS: DialTLS(nil),
|
||||||
|
Proxy: http.DefaultTransport.(*http.Transport).Proxy,
|
||||||
|
IdleConnTimeout: idleConnTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
h2Transport, err := http2.ConfigureTransports(transport)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
configureHTTP2ConnHealthCheck(h2Transport)
|
||||||
|
|
||||||
|
client.HTTPClient.Transport = transport
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureHTTP2ConnHealthCheck(h2Transport *http2.Transport) {
|
||||||
|
h2Transport.ReadIdleTimeout = 1 * time.Second
|
||||||
|
h2Transport.PingTimeout = 1 * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
func iosAlertDictionary(payload *payload.Payload, req *PushNotification) *payload.Payload {
|
||||||
|
// Alert dictionary
|
||||||
|
|
||||||
|
if len(req.Title) > 0 {
|
||||||
|
payload.AlertTitle(req.Title)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Message) > 0 && len(req.Title) > 0 {
|
||||||
|
payload.AlertBody(req.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Alert.Title) > 0 {
|
||||||
|
payload.AlertTitle(req.Alert.Title)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apple Watch & Safari display this string as part of the notification interface.
|
||||||
|
if len(req.Alert.Subtitle) > 0 {
|
||||||
|
payload.AlertSubtitle(req.Alert.Subtitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Alert.TitleLocKey) > 0 {
|
||||||
|
payload.AlertTitleLocKey(req.Alert.TitleLocKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Alert.LocArgs) > 0 {
|
||||||
|
payload.AlertLocArgs(req.Alert.LocArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Alert.TitleLocArgs) > 0 {
|
||||||
|
payload.AlertTitleLocArgs(req.Alert.TitleLocArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Alert.Body) > 0 {
|
||||||
|
payload.AlertBody(req.Alert.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Alert.LaunchImage) > 0 {
|
||||||
|
payload.AlertLaunchImage(req.Alert.LaunchImage)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Alert.LocKey) > 0 {
|
||||||
|
payload.AlertLocKey(req.Alert.LocKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Alert.Action) > 0 {
|
||||||
|
payload.AlertAction(req.Alert.Action)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Alert.ActionLocKey) > 0 {
|
||||||
|
payload.AlertActionLocKey(req.Alert.ActionLocKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// General
|
||||||
|
if len(req.Category) > 0 {
|
||||||
|
payload.Category(req.Category)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Alert.SummaryArg) > 0 {
|
||||||
|
payload.AlertSummaryArg(req.Alert.SummaryArg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Alert.SummaryArgCount > 0 {
|
||||||
|
payload.AlertSummaryArgCount(req.Alert.SummaryArgCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIOSNotification use for define iOS notification.
|
||||||
|
// The iOS Notification Payload (Payload Key Reference)
|
||||||
|
// Ref: https://apple.co/2VtH6Iu
|
||||||
|
func GetIOSNotification(req *PushNotification) *apns2.Notification {
|
||||||
|
notification := &apns2.Notification{
|
||||||
|
ApnsID: req.ApnsID,
|
||||||
|
Topic: req.Topic,
|
||||||
|
CollapseID: req.CollapseID,
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Expiration != nil {
|
||||||
|
notification.Expiration = time.Unix(*req.Expiration, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Priority) > 0 {
|
||||||
|
if req.Priority == "normal" {
|
||||||
|
notification.Priority = apns2.PriorityLow
|
||||||
|
} else if req.Priority == "high" {
|
||||||
|
notification.Priority = apns2.PriorityHigh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.PushType) > 0 {
|
||||||
|
notification.PushType = apns2.EPushType(req.PushType)
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := payload.NewPayload()
|
||||||
|
|
||||||
|
// add alert object if message length > 0 and title is empty
|
||||||
|
if len(req.Message) > 0 && req.Title == "" {
|
||||||
|
payload.Alert(req.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// zero value for clear the badge on the app icon.
|
||||||
|
if req.Badge != nil && *req.Badge >= 0 {
|
||||||
|
payload.Badge(*req.Badge)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.MutableContent {
|
||||||
|
payload.MutableContent()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch req.Sound.(type) {
|
||||||
|
// from http request binding
|
||||||
|
case map[string]interface{}:
|
||||||
|
result := &Sound{}
|
||||||
|
_ = mapstructure.Decode(req.Sound, &result)
|
||||||
|
payload.Sound(result)
|
||||||
|
// from http request binding for non critical alerts
|
||||||
|
case string:
|
||||||
|
payload.Sound(&req.Sound)
|
||||||
|
case Sound:
|
||||||
|
payload.Sound(&req.Sound)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.SoundName) > 0 {
|
||||||
|
payload.SoundName(req.SoundName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.SoundVolume > 0 {
|
||||||
|
payload.SoundVolume(req.SoundVolume)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.ContentAvailable {
|
||||||
|
payload.ContentAvailable()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.URLArgs) > 0 {
|
||||||
|
payload.URLArgs(req.URLArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.ThreadID) > 0 {
|
||||||
|
payload.ThreadID(req.ThreadID)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range req.Data {
|
||||||
|
payload.Custom(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
payload = iosAlertDictionary(payload, req)
|
||||||
|
|
||||||
|
notification.Payload = payload
|
||||||
|
|
||||||
|
return notification
|
||||||
|
}
|
||||||
|
|
||||||
|
func getApnsClient(cfg *config.ConfYaml, req *PushNotification) (client *apns2.Client) {
|
||||||
|
switch {
|
||||||
|
case req.Production:
|
||||||
|
client = ApnsClient.Production()
|
||||||
|
case req.Development:
|
||||||
|
client = ApnsClient.Development()
|
||||||
|
default:
|
||||||
|
if cfg.Ios.Production {
|
||||||
|
client = ApnsClient.Production()
|
||||||
|
} else {
|
||||||
|
client = ApnsClient.Development()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushToIOS provide send notification to APNs server.
|
||||||
|
func PushToIOS(req *PushNotification, cfg *config.ConfYaml) (resp *ResponsePush, err error) {
|
||||||
|
logx.LogAccess.Debug("Start push notification for iOS")
|
||||||
|
|
||||||
|
var (
|
||||||
|
retryCount = 0
|
||||||
|
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(cfg, req)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for _, token := range req.Tokens {
|
||||||
|
// occupy push slot
|
||||||
|
MaxConcurrentIOSPushes <- struct{}{}
|
||||||
|
wg.Add(1)
|
||||||
|
go func(notification apns2.Notification, token string) {
|
||||||
|
notification.DeviceToken = token
|
||||||
|
|
||||||
|
// send ios notification
|
||||||
|
res, err := client.Push(¬ification)
|
||||||
|
if err != nil || (res != nil && res.StatusCode != http.StatusOK) {
|
||||||
|
if err == nil {
|
||||||
|
// error message:
|
||||||
|
// ref: https://github.com/sideshow/apns2/blob/master/response.go#L14-L65
|
||||||
|
err = errors.New(res.Reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
// apns server error
|
||||||
|
errLog := logPush(cfg, core.FailedPush, token, req, err)
|
||||||
|
resp.Logs = append(resp.Logs, errLog)
|
||||||
|
|
||||||
|
status.StatStorage.AddIosError(1)
|
||||||
|
// We should retry only "retryable" statuses. More info about response:
|
||||||
|
// 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(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 {
|
||||||
|
retryCount++
|
||||||
|
|
||||||
|
// resend fail token
|
||||||
|
req.Tokens = newTokens
|
||||||
|
goto Retry
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
774
push/gorush-with-mipush/src/notify/notification_apns_test.go
Normal file
774
push/gorush-with-mipush/src/notify/notification_apns_test.go
Normal file
@ -0,0 +1,774 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"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 (
|
||||||
|
// 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) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
cfg.Android.Enabled = false
|
||||||
|
cfg.Huawei.Enabled = false
|
||||||
|
|
||||||
|
err := CheckPushConf(cfg)
|
||||||
|
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, "please enable iOS, Android or Huawei config in yml config", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMissingIOSCertificate(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
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())
|
||||||
|
|
||||||
|
cfg.Ios.KeyPath = "test.pem"
|
||||||
|
err = CheckPushConf(cfg)
|
||||||
|
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, "certificate file does not exist", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIOSNotificationStructure(t *testing.T) {
|
||||||
|
var dat map[string]interface{}
|
||||||
|
unix := time.Now().Unix()
|
||||||
|
|
||||||
|
test := "test"
|
||||||
|
expectBadge := 0
|
||||||
|
message := "Welcome notification Server"
|
||||||
|
expiration := time.Now().Unix()
|
||||||
|
req := &PushNotification{
|
||||||
|
ApnsID: test,
|
||||||
|
Topic: test,
|
||||||
|
Expiration: &expiration,
|
||||||
|
Priority: "normal",
|
||||||
|
Message: message,
|
||||||
|
Badge: &expectBadge,
|
||||||
|
Sound: Sound{
|
||||||
|
Critical: 1,
|
||||||
|
Name: test,
|
||||||
|
Volume: 1.0,
|
||||||
|
},
|
||||||
|
ContentAvailable: true,
|
||||||
|
Data: D{
|
||||||
|
"key1": "test",
|
||||||
|
"key2": 2,
|
||||||
|
},
|
||||||
|
Category: test,
|
||||||
|
URLArgs: []string{"a", "b"},
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := GetIOSNotification(req)
|
||||||
|
|
||||||
|
dump, _ := json.Marshal(notification.Payload)
|
||||||
|
data := []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
alert, _ := jsonparser.GetString(data, "aps", "alert")
|
||||||
|
badge, _ := jsonparser.GetInt(data, "aps", "badge")
|
||||||
|
soundName, _ := jsonparser.GetString(data, "aps", "sound", "name")
|
||||||
|
soundCritical, _ := jsonparser.GetInt(data, "aps", "sound", "critical")
|
||||||
|
soundVolume, _ := jsonparser.GetFloat(data, "aps", "sound", "volume")
|
||||||
|
contentAvailable, _ := jsonparser.GetInt(data, "aps", "content-available")
|
||||||
|
category, _ := jsonparser.GetString(data, "aps", "category")
|
||||||
|
key1 := dat["key1"]
|
||||||
|
key2 := dat["key2"]
|
||||||
|
aps := dat["aps"].(map[string]interface{})
|
||||||
|
urlArgs := aps["url-args"].([]interface{})
|
||||||
|
|
||||||
|
assert.Equal(t, test, notification.ApnsID)
|
||||||
|
assert.Equal(t, test, notification.Topic)
|
||||||
|
assert.Equal(t, unix, notification.Expiration.Unix())
|
||||||
|
assert.Equal(t, ApnsPriorityLow, notification.Priority)
|
||||||
|
assert.Equal(t, message, alert)
|
||||||
|
assert.Equal(t, expectBadge, int(badge))
|
||||||
|
assert.Equal(t, expectBadge, *req.Badge)
|
||||||
|
assert.Equal(t, test, soundName)
|
||||||
|
assert.Equal(t, 1.0, soundVolume)
|
||||||
|
assert.Equal(t, int64(1), soundCritical)
|
||||||
|
assert.Equal(t, 1, int(contentAvailable))
|
||||||
|
assert.Equal(t, "test", key1)
|
||||||
|
assert.Equal(t, 2, int(key2.(float64)))
|
||||||
|
assert.Equal(t, test, category)
|
||||||
|
assert.Contains(t, urlArgs, "a")
|
||||||
|
assert.Contains(t, urlArgs, "b")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIOSSoundAndVolume(t *testing.T) {
|
||||||
|
var dat map[string]interface{}
|
||||||
|
|
||||||
|
test := "test"
|
||||||
|
message := "Welcome notification Server"
|
||||||
|
req := &PushNotification{
|
||||||
|
ApnsID: test,
|
||||||
|
Topic: test,
|
||||||
|
Priority: "normal",
|
||||||
|
Message: message,
|
||||||
|
Sound: Sound{
|
||||||
|
Critical: 3,
|
||||||
|
Name: test,
|
||||||
|
Volume: 4.5,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := GetIOSNotification(req)
|
||||||
|
|
||||||
|
dump, _ := json.Marshal(notification.Payload)
|
||||||
|
data := []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
alert, _ := jsonparser.GetString(data, "aps", "alert")
|
||||||
|
soundName, _ := jsonparser.GetString(data, "aps", "sound", "name")
|
||||||
|
soundCritical, _ := jsonparser.GetInt(data, "aps", "sound", "critical")
|
||||||
|
soundVolume, _ := jsonparser.GetFloat(data, "aps", "sound", "volume")
|
||||||
|
|
||||||
|
assert.Equal(t, test, notification.ApnsID)
|
||||||
|
assert.Equal(t, test, notification.Topic)
|
||||||
|
assert.Equal(t, ApnsPriorityLow, notification.Priority)
|
||||||
|
assert.Equal(t, message, alert)
|
||||||
|
assert.Equal(t, test, soundName)
|
||||||
|
assert.Equal(t, 4.5, soundVolume)
|
||||||
|
assert.Equal(t, int64(3), soundCritical)
|
||||||
|
|
||||||
|
req.SoundName = "foobar"
|
||||||
|
req.SoundVolume = 5.5
|
||||||
|
notification = GetIOSNotification(req)
|
||||||
|
dump, _ = json.Marshal(notification.Payload)
|
||||||
|
data = []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
soundName, _ = jsonparser.GetString(data, "aps", "sound", "name")
|
||||||
|
soundVolume, _ = jsonparser.GetFloat(data, "aps", "sound", "volume")
|
||||||
|
soundCritical, _ = jsonparser.GetInt(data, "aps", "sound", "critical")
|
||||||
|
assert.Equal(t, 5.5, soundVolume)
|
||||||
|
assert.Equal(t, int64(1), soundCritical)
|
||||||
|
assert.Equal(t, "foobar", soundName)
|
||||||
|
|
||||||
|
req = &PushNotification{
|
||||||
|
ApnsID: test,
|
||||||
|
Topic: test,
|
||||||
|
Priority: "normal",
|
||||||
|
Message: message,
|
||||||
|
Sound: map[string]interface{}{
|
||||||
|
"critical": 3,
|
||||||
|
"name": "test",
|
||||||
|
"volume": 4.5,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
notification = GetIOSNotification(req)
|
||||||
|
dump, _ = json.Marshal(notification.Payload)
|
||||||
|
data = []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
soundName, _ = jsonparser.GetString(data, "aps", "sound", "name")
|
||||||
|
soundVolume, _ = jsonparser.GetFloat(data, "aps", "sound", "volume")
|
||||||
|
soundCritical, _ = jsonparser.GetInt(data, "aps", "sound", "critical")
|
||||||
|
assert.Equal(t, 4.5, soundVolume)
|
||||||
|
assert.Equal(t, int64(3), soundCritical)
|
||||||
|
assert.Equal(t, "test", soundName)
|
||||||
|
|
||||||
|
req = &PushNotification{
|
||||||
|
ApnsID: test,
|
||||||
|
Topic: test,
|
||||||
|
Priority: "normal",
|
||||||
|
Message: message,
|
||||||
|
Sound: "default",
|
||||||
|
}
|
||||||
|
|
||||||
|
notification = GetIOSNotification(req)
|
||||||
|
dump, _ = json.Marshal(notification.Payload)
|
||||||
|
data = []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
soundName, _ = jsonparser.GetString(data, "aps", "sound")
|
||||||
|
assert.Equal(t, "default", soundName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIOSSummaryArg(t *testing.T) {
|
||||||
|
var dat map[string]interface{}
|
||||||
|
|
||||||
|
test := "test"
|
||||||
|
message := "Welcome notification Server"
|
||||||
|
req := &PushNotification{
|
||||||
|
ApnsID: test,
|
||||||
|
Topic: test,
|
||||||
|
Priority: "normal",
|
||||||
|
Message: message,
|
||||||
|
Alert: Alert{
|
||||||
|
SummaryArg: "test",
|
||||||
|
SummaryArgCount: 3,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := GetIOSNotification(req)
|
||||||
|
|
||||||
|
dump, _ := json.Marshal(notification.Payload)
|
||||||
|
data := []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, test, notification.ApnsID)
|
||||||
|
assert.Equal(t, test, notification.Topic)
|
||||||
|
assert.Equal(t, ApnsPriorityLow, notification.Priority)
|
||||||
|
assert.Equal(t, "test", dat["aps"].(map[string]interface{})["alert"].(map[string]interface{})["summary-arg"])
|
||||||
|
assert.Equal(t, float64(3), dat["aps"].(map[string]interface{})["alert"].(map[string]interface{})["summary-arg-count"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Silent Notification which payload’s aps dictionary must not contain the alert, sound, or badge keys.
|
||||||
|
// ref: https://goo.gl/m9xyqG
|
||||||
|
func TestSendZeroValueForBadgeKey(t *testing.T) {
|
||||||
|
var dat map[string]interface{}
|
||||||
|
|
||||||
|
test := "test"
|
||||||
|
message := "Welcome notification Server"
|
||||||
|
req := &PushNotification{
|
||||||
|
ApnsID: test,
|
||||||
|
Topic: test,
|
||||||
|
Priority: "normal",
|
||||||
|
Message: message,
|
||||||
|
Sound: test,
|
||||||
|
ContentAvailable: true,
|
||||||
|
MutableContent: true,
|
||||||
|
ThreadID: test,
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := GetIOSNotification(req)
|
||||||
|
|
||||||
|
dump, _ := json.Marshal(notification.Payload)
|
||||||
|
data := []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
alert, _ := jsonparser.GetString(data, "aps", "alert")
|
||||||
|
badge, _ := jsonparser.GetInt(data, "aps", "badge")
|
||||||
|
sound, _ := jsonparser.GetString(data, "aps", "sound")
|
||||||
|
threadID, _ := jsonparser.GetString(data, "aps", "thread-id")
|
||||||
|
contentAvailable, _ := jsonparser.GetInt(data, "aps", "content-available")
|
||||||
|
mutableContent, _ := jsonparser.GetInt(data, "aps", "mutable-content")
|
||||||
|
|
||||||
|
if req.Badge != nil {
|
||||||
|
t.Errorf("req.Badge must be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, test, notification.ApnsID)
|
||||||
|
assert.Equal(t, test, notification.Topic)
|
||||||
|
assert.Equal(t, ApnsPriorityLow, notification.Priority)
|
||||||
|
assert.Equal(t, message, alert)
|
||||||
|
assert.Equal(t, 0, int(badge))
|
||||||
|
assert.Equal(t, test, sound)
|
||||||
|
assert.Equal(t, test, threadID)
|
||||||
|
assert.Equal(t, 1, int(contentAvailable))
|
||||||
|
assert.Equal(t, 1, int(mutableContent))
|
||||||
|
|
||||||
|
// Add Bage
|
||||||
|
expectBadge := 10
|
||||||
|
req.Badge = &expectBadge
|
||||||
|
|
||||||
|
notification = GetIOSNotification(req)
|
||||||
|
|
||||||
|
dump, _ = json.Marshal(notification.Payload)
|
||||||
|
data = []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Badge == nil {
|
||||||
|
t.Errorf("req.Badge must be equal %d", *req.Badge)
|
||||||
|
}
|
||||||
|
|
||||||
|
badge, _ = jsonparser.GetInt(data, "aps", "badge")
|
||||||
|
assert.Equal(t, expectBadge, *req.Badge)
|
||||||
|
assert.Equal(t, expectBadge, int(badge))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Silent Notification:
|
||||||
|
// The payload’s aps dictionary must include the content-available key with a value of 1.
|
||||||
|
// The payload’s aps dictionary must not contain the alert, sound, or badge keys.
|
||||||
|
// ref: https://goo.gl/m9xyqG
|
||||||
|
func TestCheckSilentNotification(t *testing.T) {
|
||||||
|
var dat map[string]interface{}
|
||||||
|
|
||||||
|
test := "test"
|
||||||
|
req := &PushNotification{
|
||||||
|
ApnsID: test,
|
||||||
|
Topic: test,
|
||||||
|
CollapseID: test,
|
||||||
|
Priority: "normal",
|
||||||
|
ContentAvailable: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := GetIOSNotification(req)
|
||||||
|
|
||||||
|
dump, _ := json.Marshal(notification.Payload)
|
||||||
|
data := []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, test, notification.CollapseID)
|
||||||
|
assert.Equal(t, test, notification.ApnsID)
|
||||||
|
assert.Equal(t, test, notification.Topic)
|
||||||
|
assert.Nil(t, dat["aps"].(map[string]interface{})["alert"])
|
||||||
|
assert.Nil(t, dat["aps"].(map[string]interface{})["sound"])
|
||||||
|
assert.Nil(t, dat["aps"].(map[string]interface{})["badge"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL: https://goo.gl/5xFo3C
|
||||||
|
// Example 2
|
||||||
|
// {
|
||||||
|
// "aps" : {
|
||||||
|
// "alert" : {
|
||||||
|
// "title" : "Game Request",
|
||||||
|
// "body" : "Bob wants to play poker",
|
||||||
|
// "action-loc-key" : "PLAY"
|
||||||
|
// },
|
||||||
|
// "badge" : 5
|
||||||
|
// },
|
||||||
|
// "acme1" : "bar",
|
||||||
|
// "acme2" : [ "bang", "whiz" ]
|
||||||
|
// }
|
||||||
|
func TestAlertStringExample2ForIos(t *testing.T) {
|
||||||
|
var dat map[string]interface{}
|
||||||
|
|
||||||
|
test := "test"
|
||||||
|
title := "Game Request"
|
||||||
|
body := "Bob wants to play poker"
|
||||||
|
actionLocKey := "PLAY"
|
||||||
|
req := &PushNotification{
|
||||||
|
ApnsID: test,
|
||||||
|
Topic: test,
|
||||||
|
Priority: "normal",
|
||||||
|
Alert: Alert{
|
||||||
|
Title: title,
|
||||||
|
Body: body,
|
||||||
|
ActionLocKey: actionLocKey,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := GetIOSNotification(req)
|
||||||
|
|
||||||
|
dump, _ := json.Marshal(notification.Payload)
|
||||||
|
data := []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, title, dat["aps"].(map[string]interface{})["alert"].(map[string]interface{})["title"])
|
||||||
|
assert.Equal(t, body, dat["aps"].(map[string]interface{})["alert"].(map[string]interface{})["body"])
|
||||||
|
assert.Equal(t, actionLocKey, dat["aps"].(map[string]interface{})["alert"].(map[string]interface{})["action-loc-key"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL: https://goo.gl/5xFo3C
|
||||||
|
// Example 3
|
||||||
|
// {
|
||||||
|
// "aps" : {
|
||||||
|
// "alert" : "You got your emails.",
|
||||||
|
// "badge" : 9,
|
||||||
|
// "sound" : "bingbong.aiff"
|
||||||
|
// },
|
||||||
|
// "acme1" : "bar",
|
||||||
|
// "acme2" : 42
|
||||||
|
// }
|
||||||
|
func TestAlertStringExample3ForIos(t *testing.T) {
|
||||||
|
var dat map[string]interface{}
|
||||||
|
|
||||||
|
test := "test"
|
||||||
|
badge := 9
|
||||||
|
sound := "bingbong.aiff"
|
||||||
|
req := &PushNotification{
|
||||||
|
ApnsID: test,
|
||||||
|
Topic: test,
|
||||||
|
Priority: "normal",
|
||||||
|
ContentAvailable: true,
|
||||||
|
Message: test,
|
||||||
|
Badge: &badge,
|
||||||
|
Sound: sound,
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := GetIOSNotification(req)
|
||||||
|
|
||||||
|
dump, _ := json.Marshal(notification.Payload)
|
||||||
|
data := []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, sound, dat["aps"].(map[string]interface{})["sound"])
|
||||||
|
assert.Equal(t, float64(badge), dat["aps"].(map[string]interface{})["badge"].(float64))
|
||||||
|
assert.Equal(t, test, dat["aps"].(map[string]interface{})["alert"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMessageAndTitle(t *testing.T) {
|
||||||
|
var dat map[string]interface{}
|
||||||
|
|
||||||
|
test := "test"
|
||||||
|
message := "Welcome notification Server"
|
||||||
|
title := "Welcome notification Server title"
|
||||||
|
req := &PushNotification{
|
||||||
|
ApnsID: test,
|
||||||
|
Topic: test,
|
||||||
|
Priority: "normal",
|
||||||
|
Message: message,
|
||||||
|
Title: title,
|
||||||
|
ContentAvailable: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := GetIOSNotification(req)
|
||||||
|
|
||||||
|
dump, _ := json.Marshal(notification.Payload)
|
||||||
|
data := []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
alert, _ := jsonparser.GetString(data, "aps", "alert")
|
||||||
|
alertBody, _ := jsonparser.GetString(data, "aps", "alert", "body")
|
||||||
|
alertTitle, _ := jsonparser.GetString(data, "aps", "alert", "title")
|
||||||
|
|
||||||
|
assert.Equal(t, test, notification.ApnsID)
|
||||||
|
assert.Equal(t, ApnsPriorityLow, notification.Priority)
|
||||||
|
assert.Equal(t, message, alertBody)
|
||||||
|
assert.Equal(t, title, alertTitle)
|
||||||
|
assert.NotEqual(t, message, alert)
|
||||||
|
|
||||||
|
// Add alert body
|
||||||
|
messageOverride := "Welcome notification Server overridden"
|
||||||
|
req.Alert.Body = messageOverride
|
||||||
|
|
||||||
|
notification = GetIOSNotification(req)
|
||||||
|
|
||||||
|
dump, _ = json.Marshal(notification.Payload)
|
||||||
|
data = []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
alertBodyOverridden, _ := jsonparser.GetString(data, "aps", "alert", "body")
|
||||||
|
alertTitle, _ = jsonparser.GetString(data, "aps", "alert", "title")
|
||||||
|
assert.Equal(t, messageOverride, alertBodyOverridden)
|
||||||
|
assert.NotEqual(t, message, alertBodyOverridden)
|
||||||
|
assert.Equal(t, title, alertTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIOSAlertNotificationStructure(t *testing.T) {
|
||||||
|
var dat map[string]interface{}
|
||||||
|
|
||||||
|
test := "test"
|
||||||
|
req := &PushNotification{
|
||||||
|
Message: "Welcome",
|
||||||
|
Title: test,
|
||||||
|
Alert: Alert{
|
||||||
|
Action: test,
|
||||||
|
ActionLocKey: test,
|
||||||
|
Body: test,
|
||||||
|
LaunchImage: test,
|
||||||
|
LocArgs: []string{"a", "b"},
|
||||||
|
LocKey: test,
|
||||||
|
Subtitle: test,
|
||||||
|
TitleLocArgs: []string{"a", "b"},
|
||||||
|
TitleLocKey: test,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := GetIOSNotification(req)
|
||||||
|
|
||||||
|
dump, _ := json.Marshal(notification.Payload)
|
||||||
|
data := []byte(string(dump))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &dat); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
action, _ := jsonparser.GetString(data, "aps", "alert", "action")
|
||||||
|
actionLocKey, _ := jsonparser.GetString(data, "aps", "alert", "action-loc-key")
|
||||||
|
body, _ := jsonparser.GetString(data, "aps", "alert", "body")
|
||||||
|
launchImage, _ := jsonparser.GetString(data, "aps", "alert", "launch-image")
|
||||||
|
locKey, _ := jsonparser.GetString(data, "aps", "alert", "loc-key")
|
||||||
|
title, _ := jsonparser.GetString(data, "aps", "alert", "title")
|
||||||
|
subtitle, _ := jsonparser.GetString(data, "aps", "alert", "subtitle")
|
||||||
|
titleLocKey, _ := jsonparser.GetString(data, "aps", "alert", "title-loc-key")
|
||||||
|
aps := dat["aps"].(map[string]interface{})
|
||||||
|
alert := aps["alert"].(map[string]interface{})
|
||||||
|
titleLocArgs := alert["title-loc-args"].([]interface{})
|
||||||
|
locArgs := alert["loc-args"].([]interface{})
|
||||||
|
|
||||||
|
assert.Equal(t, test, action)
|
||||||
|
assert.Equal(t, test, actionLocKey)
|
||||||
|
assert.Equal(t, test, body)
|
||||||
|
assert.Equal(t, test, launchImage)
|
||||||
|
assert.Equal(t, test, locKey)
|
||||||
|
assert.Equal(t, test, title)
|
||||||
|
assert.Equal(t, test, subtitle)
|
||||||
|
assert.Equal(t, test, titleLocKey)
|
||||||
|
assert.Contains(t, titleLocArgs, "a")
|
||||||
|
assert.Contains(t, titleLocArgs, "b")
|
||||||
|
assert.Contains(t, locArgs, "a")
|
||||||
|
assert.Contains(t, locArgs, "b")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWrongIosCertificateExt(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
cfg.Ios.Enabled = true
|
||||||
|
cfg.Ios.KeyPath = "test"
|
||||||
|
err := InitAPNSClient(cfg)
|
||||||
|
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, "wrong certificate key extension", err.Error())
|
||||||
|
|
||||||
|
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) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
cfg.Ios.Enabled = true
|
||||||
|
cfg.Ios.KeyPath = "../certificate/authkey-invalid.p8"
|
||||||
|
err := InitAPNSClient(cfg)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
cfg.Ios.KeyPath = ""
|
||||||
|
cfg.Ios.KeyBase64 = authkeyInvalidP8
|
||||||
|
cfg.Ios.KeyType = "p8"
|
||||||
|
err = InitAPNSClient(cfg)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// empty key-id or team-id
|
||||||
|
cfg.Ios.Enabled = true
|
||||||
|
cfg.Ios.KeyPath = "../certificate/authkey-valid.p8"
|
||||||
|
err = InitAPNSClient(cfg)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
cfg.Ios.KeyID = "key-id"
|
||||||
|
cfg.Ios.TeamID = ""
|
||||||
|
err = InitAPNSClient(cfg)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
cfg.Ios.KeyID = ""
|
||||||
|
cfg.Ios.TeamID = "team-id"
|
||||||
|
err = InitAPNSClient(cfg)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPNSClientVaildToken(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
cfg.Ios.Production = true
|
||||||
|
err = InitAPNSClient(cfg)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, apns2.HostProduction, ApnsClient.Host)
|
||||||
|
|
||||||
|
// test base64
|
||||||
|
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)
|
||||||
|
|
||||||
|
cfg.Ios.Production = true
|
||||||
|
err = InitAPNSClient(cfg)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, apns2.HostProduction, ApnsClient.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPNSClientUseProxy(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("GET", apns2.HostDevelopment, nil)
|
||||||
|
actualProxyURL, err := ApnsClient.HTTPClient.Transport.(*http.Transport).Proxy(req)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
expectedProxyURL, _ := url.ParseRequestURI(cfg.Core.HTTPProxy)
|
||||||
|
assert.Equal(t, expectedProxyURL, actualProxyURL)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
req, _ = http.NewRequest("GET", apns2.HostDevelopment, nil)
|
||||||
|
actualProxyURL, err = ApnsClient.HTTPClient.Transport.(*http.Transport).Proxy(req)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
expectedProxyURL, _ = url.ParseRequestURI(cfg.Core.HTTPProxy)
|
||||||
|
assert.Equal(t, expectedProxyURL, actualProxyURL)
|
||||||
|
|
||||||
|
http.DefaultTransport.(*http.Transport).Proxy = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPushToIOS(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
MaxConcurrentIOSPushes = make(chan struct{}, cfg.Ios.MaxConcurrentPushes)
|
||||||
|
|
||||||
|
cfg.Ios.Enabled = true
|
||||||
|
cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
|
||||||
|
err := InitAPNSClient(cfg)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
err = status.InitAppStatus(cfg)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
req := &PushNotification{
|
||||||
|
// nolint
|
||||||
|
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7", "11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef1"},
|
||||||
|
Platform: 1,
|
||||||
|
Message: "Welcome",
|
||||||
|
}
|
||||||
|
|
||||||
|
// send fail
|
||||||
|
resp, err := PushToIOS(req, cfg)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Len(t, resp.Logs, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApnsHostFromRequest(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
cfg.Ios.Enabled = true
|
||||||
|
cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
|
||||||
|
err := InitAPNSClient(cfg)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
err = status.InitAppStatus(cfg)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
req := &PushNotification{
|
||||||
|
Production: true,
|
||||||
|
}
|
||||||
|
client := getApnsClient(cfg, req)
|
||||||
|
assert.Equal(t, apns2.HostProduction, client.Host)
|
||||||
|
|
||||||
|
req = &PushNotification{
|
||||||
|
Development: true,
|
||||||
|
}
|
||||||
|
client = getApnsClient(cfg, req)
|
||||||
|
assert.Equal(t, apns2.HostDevelopment, client.Host)
|
||||||
|
|
||||||
|
req = &PushNotification{}
|
||||||
|
cfg.Ios.Production = true
|
||||||
|
client = getApnsClient(cfg, req)
|
||||||
|
assert.Equal(t, apns2.HostProduction, client.Host)
|
||||||
|
|
||||||
|
cfg.Ios.Production = false
|
||||||
|
client = getApnsClient(cfg, req)
|
||||||
|
assert.Equal(t, apns2.HostDevelopment, client.Host)
|
||||||
|
}
|
246
push/gorush-with-mipush/src/notify/notification_fcm.go
Normal file
246
push/gorush-with-mipush/src/notify/notification_fcm.go
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InitFCMClient use for initialize FCM Client.
|
||||||
|
func InitFCMClient(cfg *config.ConfYaml, key string) (*fcm.Client, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if key == "" && cfg.Android.APIKey == "" {
|
||||||
|
return nil, errors.New("Missing Android API Key")
|
||||||
|
}
|
||||||
|
|
||||||
|
if key != "" && key != cfg.Android.APIKey {
|
||||||
|
return fcm.NewClient(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if FCMClient == nil {
|
||||||
|
FCMClient, err = fcm.NewClient(cfg.Android.APIKey)
|
||||||
|
return FCMClient, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return FCMClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
notification := &fcm.Message{
|
||||||
|
To: req.To,
|
||||||
|
Condition: req.Condition,
|
||||||
|
CollapseKey: req.CollapseKey,
|
||||||
|
ContentAvailable: req.ContentAvailable,
|
||||||
|
MutableContent: req.MutableContent,
|
||||||
|
DelayWhileIdle: req.DelayWhileIdle,
|
||||||
|
TimeToLive: req.TimeToLive,
|
||||||
|
RestrictedPackageName: req.RestrictedPackageName,
|
||||||
|
DryRun: req.DryRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Tokens) > 0 {
|
||||||
|
notification.RegistrationIDs = req.Tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Priority == "high" || req.Priority == "normal" {
|
||||||
|
notification.Priority = req.Priority
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add another field
|
||||||
|
if len(req.Data) > 0 {
|
||||||
|
notification.Data = make(map[string]interface{})
|
||||||
|
for k, v := range req.Data {
|
||||||
|
notification.Data[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n := &fcm.Notification{}
|
||||||
|
isNotificationSet := false
|
||||||
|
if req.Notification != nil {
|
||||||
|
isNotificationSet = true
|
||||||
|
n = req.Notification
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Message) > 0 {
|
||||||
|
isNotificationSet = true
|
||||||
|
n.Body = req.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Title) > 0 {
|
||||||
|
isNotificationSet = true
|
||||||
|
n.Title = req.Title
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Image) > 0 {
|
||||||
|
isNotificationSet = true
|
||||||
|
n.Image = req.Image
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := req.Sound.(string); ok && len(v) > 0 {
|
||||||
|
isNotificationSet = true
|
||||||
|
n.Sound = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if isNotificationSet {
|
||||||
|
notification.Notification = n
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle iOS apns in fcm
|
||||||
|
|
||||||
|
if len(req.Apns) > 0 {
|
||||||
|
notification.Apns = req.Apns
|
||||||
|
}
|
||||||
|
|
||||||
|
return notification
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushToAndroid provide send notification to Android server.
|
||||||
|
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 = cfg.Android.MaxRetry
|
||||||
|
)
|
||||||
|
|
||||||
|
if req.Retry > 0 && req.Retry < maxRetry {
|
||||||
|
maxRetry = req.Retry
|
||||||
|
}
|
||||||
|
|
||||||
|
// check message
|
||||||
|
err = CheckMessage(req)
|
||||||
|
if err != nil {
|
||||||
|
logx.LogError.Error("request error: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = &ResponsePush{}
|
||||||
|
|
||||||
|
Retry:
|
||||||
|
notification := GetAndroidNotification(req)
|
||||||
|
|
||||||
|
if req.APIKey != "" {
|
||||||
|
client, err = InitFCMClient(cfg, req.APIKey)
|
||||||
|
} else {
|
||||||
|
client, err = InitFCMClient(cfg, cfg.Android.APIKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// FCM server error
|
||||||
|
logx.LogError.Error("FCM server error: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := client.Send(notification)
|
||||||
|
if err != nil {
|
||||||
|
// Send Message error
|
||||||
|
logx.LogError.Error("FCM server send message error: " + err.Error())
|
||||||
|
|
||||||
|
if req.IsTopic() {
|
||||||
|
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 {
|
||||||
|
errLog := logPush(cfg, core.FailedPush, token, req, err)
|
||||||
|
resp.Logs = append(resp.Logs, errLog)
|
||||||
|
}
|
||||||
|
status.StatStorage.AddAndroidError(int64(len(req.Tokens)))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !req.IsTopic() {
|
||||||
|
logx.LogAccess.Debug(fmt.Sprintf("Android Success count: %d, Failure count: %d", res.Success, res.Failure))
|
||||||
|
}
|
||||||
|
|
||||||
|
status.StatStorage.AddAndroidSuccess(int64(res.Success))
|
||||||
|
status.StatStorage.AddAndroidError(int64(res.Failure))
|
||||||
|
|
||||||
|
var newTokens []string
|
||||||
|
// result from Send messages to specific devices
|
||||||
|
for k, result := range res.Results {
|
||||||
|
to := ""
|
||||||
|
if k < len(req.Tokens) {
|
||||||
|
to = req.Tokens[k]
|
||||||
|
} else {
|
||||||
|
to = req.To
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
// We should retry only "retryable" statuses. More info about response:
|
||||||
|
// https://firebase.google.com/docs/cloud-messaging/http-server-ref#downstream-http-messages-plain-text
|
||||||
|
if !result.Unregistered() {
|
||||||
|
newTokens = append(newTokens, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
errLog := logPush(cfg, core.FailedPush, to, req, result.Error)
|
||||||
|
resp.Logs = append(resp.Logs, errLog)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
logPush(cfg, core.SucceededPush, to, req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// result from Send messages to topics
|
||||||
|
if req.IsTopic() {
|
||||||
|
to := ""
|
||||||
|
if req.To != "" {
|
||||||
|
to = req.To
|
||||||
|
} else {
|
||||||
|
to = req.Condition
|
||||||
|
}
|
||||||
|
logx.LogAccess.Debug("Send Topic Message: ", to)
|
||||||
|
// Success
|
||||||
|
if res.MessageID != 0 {
|
||||||
|
logPush(cfg, core.SucceededPush, to, req, nil)
|
||||||
|
} else {
|
||||||
|
// failure
|
||||||
|
errLog := logPush(cfg, core.FailedPush, to, req, res.Error)
|
||||||
|
resp.Logs = append(resp.Logs, errLog)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Device Group HTTP Response
|
||||||
|
if len(res.FailedRegistrationIDs) > 0 {
|
||||||
|
newTokens = append(newTokens, res.FailedRegistrationIDs...)
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
retryCount++
|
||||||
|
|
||||||
|
// resend fail token
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
}
|
272
push/gorush-with-mipush/src/notify/notification_fcm_test.go
Normal file
272
push/gorush-with-mipush/src/notify/notification_fcm_test.go
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/config"
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
|
|
||||||
|
"github.com/appleboy/go-fcm"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMissingAndroidAPIKey(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
cfg.Android.Enabled = true
|
||||||
|
cfg.Android.APIKey = ""
|
||||||
|
|
||||||
|
err := CheckPushConf(cfg)
|
||||||
|
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, "Missing Android API Key", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMissingKeyForInitFCMClient(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
cfg.Android.APIKey = ""
|
||||||
|
client, err := InitFCMClient(cfg, "")
|
||||||
|
|
||||||
|
assert.Nil(t, client)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, "Missing Android API Key", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPushToAndroidWrongToken(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
cfg.Android.Enabled = true
|
||||||
|
cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
|
||||||
|
|
||||||
|
req := &PushNotification{
|
||||||
|
Tokens: []string{"aaaaaa", "bbbbb"},
|
||||||
|
Platform: core.PlatFormAndroid,
|
||||||
|
Message: "Welcome",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android Success count: 0, Failure count: 2
|
||||||
|
resp, err := PushToAndroid(req, cfg)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Len(t, resp.Logs, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPushToAndroidRightTokenForJSONLog(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
cfg.Android.Enabled = true
|
||||||
|
cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
|
||||||
|
// log for json
|
||||||
|
cfg.Log.Format = "json"
|
||||||
|
|
||||||
|
androidToken := os.Getenv("ANDROID_TEST_TOKEN")
|
||||||
|
|
||||||
|
req := &PushNotification{
|
||||||
|
Tokens: []string{androidToken},
|
||||||
|
Platform: core.PlatFormAndroid,
|
||||||
|
Message: "Welcome",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := PushToAndroid(req, cfg)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Len(t, resp.Logs, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPushToAndroidRightTokenForStringLog(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
cfg.Android.Enabled = true
|
||||||
|
cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
|
||||||
|
|
||||||
|
androidToken := os.Getenv("ANDROID_TEST_TOKEN")
|
||||||
|
|
||||||
|
req := &PushNotification{
|
||||||
|
Tokens: []string{androidToken},
|
||||||
|
Platform: core.PlatFormAndroid,
|
||||||
|
Message: "Welcome",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := PushToAndroid(req, cfg)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Len(t, resp.Logs, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOverwriteAndroidAPIKey(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
cfg.Core.Sync = true
|
||||||
|
cfg.Android.Enabled = true
|
||||||
|
cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
|
||||||
|
|
||||||
|
androidToken := os.Getenv("ANDROID_TEST_TOKEN")
|
||||||
|
|
||||||
|
req := &PushNotification{
|
||||||
|
Tokens: []string{androidToken, "bbbbb"},
|
||||||
|
Platform: core.PlatFormAndroid,
|
||||||
|
Message: "Welcome",
|
||||||
|
// overwrite android api key
|
||||||
|
APIKey: "1234",
|
||||||
|
}
|
||||||
|
|
||||||
|
// FCM server error: 401 error: 401 Unauthorized (Wrong API Key)
|
||||||
|
resp, err := PushToAndroid(req, cfg)
|
||||||
|
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Len(t, resp.Logs, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFCMMessage(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// the message must specify at least one registration ID
|
||||||
|
req := &PushNotification{
|
||||||
|
Message: "Test",
|
||||||
|
Tokens: []string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = CheckMessage(req)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// the token must not be empty
|
||||||
|
req = &PushNotification{
|
||||||
|
Message: "Test",
|
||||||
|
Tokens: []string{""},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = CheckMessage(req)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// ignore check token length if send topic message
|
||||||
|
req = &PushNotification{
|
||||||
|
Message: "Test",
|
||||||
|
Platform: core.PlatFormAndroid,
|
||||||
|
To: "/topics/foo-bar",
|
||||||
|
}
|
||||||
|
|
||||||
|
err = CheckMessage(req)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// "condition": "'dogs' in topics || 'cats' in topics",
|
||||||
|
req = &PushNotification{
|
||||||
|
Message: "Test",
|
||||||
|
Platform: core.PlatFormAndroid,
|
||||||
|
Condition: "'dogs' in topics || 'cats' in topics",
|
||||||
|
}
|
||||||
|
|
||||||
|
err = CheckMessage(req)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// the message may specify at most 1000 registration IDs
|
||||||
|
req = &PushNotification{
|
||||||
|
Message: "Test",
|
||||||
|
Platform: core.PlatFormAndroid,
|
||||||
|
Tokens: make([]string, 1001),
|
||||||
|
}
|
||||||
|
|
||||||
|
err = CheckMessage(req)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// the message's TimeToLive field must be an integer
|
||||||
|
// between 0 and 2419200 (4 weeks)
|
||||||
|
timeToLive := uint(2419201)
|
||||||
|
req = &PushNotification{
|
||||||
|
Message: "Test",
|
||||||
|
Platform: core.PlatFormAndroid,
|
||||||
|
Tokens: []string{"XXXXXXXXX"},
|
||||||
|
TimeToLive: &timeToLive,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = CheckMessage(req)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// Pass
|
||||||
|
timeToLive = uint(86400)
|
||||||
|
req = &PushNotification{
|
||||||
|
Message: "Test",
|
||||||
|
Platform: core.PlatFormAndroid,
|
||||||
|
Tokens: []string{"XXXXXXXXX"},
|
||||||
|
TimeToLive: &timeToLive,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = CheckMessage(req)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckAndroidMessage(t *testing.T) {
|
||||||
|
cfg, _ := config.LoadConf()
|
||||||
|
|
||||||
|
cfg.Android.Enabled = true
|
||||||
|
cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
|
||||||
|
|
||||||
|
timeToLive := uint(2419201)
|
||||||
|
req := &PushNotification{
|
||||||
|
Tokens: []string{"aaaaaa", "bbbbb"},
|
||||||
|
Platform: core.PlatFormAndroid,
|
||||||
|
Message: "Welcome",
|
||||||
|
TimeToLive: &timeToLive,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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{
|
||||||
|
Tokens: []string{"a", "b"},
|
||||||
|
Message: "Welcome",
|
||||||
|
To: test,
|
||||||
|
Priority: "high",
|
||||||
|
CollapseKey: "1",
|
||||||
|
ContentAvailable: true,
|
||||||
|
DelayWhileIdle: true,
|
||||||
|
TimeToLive: &timeToLive,
|
||||||
|
RestrictedPackageName: test,
|
||||||
|
DryRun: true,
|
||||||
|
Title: test,
|
||||||
|
Sound: test,
|
||||||
|
Data: D{
|
||||||
|
"a": "1",
|
||||||
|
"b": 2,
|
||||||
|
},
|
||||||
|
Notification: &fcm.Notification{
|
||||||
|
Color: test,
|
||||||
|
Tag: test,
|
||||||
|
Body: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := GetAndroidNotification(req)
|
||||||
|
|
||||||
|
assert.Equal(t, test, notification.To)
|
||||||
|
assert.Equal(t, "high", notification.Priority)
|
||||||
|
assert.Equal(t, "1", notification.CollapseKey)
|
||||||
|
assert.True(t, notification.ContentAvailable)
|
||||||
|
assert.True(t, notification.DelayWhileIdle)
|
||||||
|
assert.Equal(t, uint(100), *notification.TimeToLive)
|
||||||
|
assert.Equal(t, test, notification.RestrictedPackageName)
|
||||||
|
assert.True(t, notification.DryRun)
|
||||||
|
assert.Equal(t, test, notification.Notification.Title)
|
||||||
|
assert.Equal(t, test, notification.Notification.Sound)
|
||||||
|
assert.Equal(t, test, notification.Notification.Color)
|
||||||
|
assert.Equal(t, test, notification.Notification.Tag)
|
||||||
|
assert.Equal(t, "Welcome", notification.Notification.Body)
|
||||||
|
assert.Equal(t, "1", notification.Data["a"])
|
||||||
|
assert.Equal(t, 2, notification.Data["b"])
|
||||||
|
|
||||||
|
// test empty body
|
||||||
|
req = &PushNotification{
|
||||||
|
Tokens: []string{"a", "b"},
|
||||||
|
To: test,
|
||||||
|
Notification: &fcm.Notification{
|
||||||
|
Body: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
notification = GetAndroidNotification(req)
|
||||||
|
|
||||||
|
assert.Equal(t, test, notification.To)
|
||||||
|
assert.Equal(t, "", notification.Notification.Body)
|
||||||
|
}
|
226
push/gorush-with-mipush/src/notify/notification_hms.go
Normal file
226
push/gorush-with-mipush/src/notify/notification_hms.go
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"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 *client.HMSClient
|
||||||
|
once sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetPushClient use for create HMS Push.
|
||||||
|
func GetPushClient(conf *c.Config) (*client.HMSClient, error) {
|
||||||
|
once.Do(func() {
|
||||||
|
client, err := client.NewHttpClient(conf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
pushClient = client
|
||||||
|
pushError = err
|
||||||
|
})
|
||||||
|
|
||||||
|
return pushClient, pushError
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitHMSClient use for initialize HMS Client.
|
||||||
|
func InitHMSClient(cfg *config.ConfYaml, appSecret, appID string) (*client.HMSClient, error) {
|
||||||
|
if appSecret == "" {
|
||||||
|
return nil, errors.New("Missing Huawei App Secret")
|
||||||
|
}
|
||||||
|
|
||||||
|
if appID == "" {
|
||||||
|
return nil, errors.New("Missing Huawei App ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
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 != cfg.Huawei.AppSecret || appID != cfg.Huawei.AppID {
|
||||||
|
return GetPushClient(conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
if HMSClient == nil {
|
||||||
|
return GetPushClient(conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
return HMSClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
msgRequest := model.NewNotificationMsgRequest()
|
||||||
|
|
||||||
|
msgRequest.Message.Android = model.GetDefaultAndroid()
|
||||||
|
|
||||||
|
if len(req.Tokens) > 0 {
|
||||||
|
msgRequest.Message.Token = req.Tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Topic) > 0 {
|
||||||
|
msgRequest.Message.Topic = req.Topic
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.To) > 0 {
|
||||||
|
msgRequest.Message.Topic = req.To
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Condition) > 0 {
|
||||||
|
msgRequest.Message.Condition = req.Condition
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Priority == "high" {
|
||||||
|
msgRequest.Message.Android.Urgency = "HIGH"
|
||||||
|
}
|
||||||
|
|
||||||
|
// if req.HuaweiCollapseKey != nil {
|
||||||
|
msgRequest.Message.Android.CollapseKey = req.HuaweiCollapseKey
|
||||||
|
//}
|
||||||
|
|
||||||
|
if len(req.Category) > 0 {
|
||||||
|
msgRequest.Message.Android.Category = req.Category
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.HuaweiTTL) > 0 {
|
||||||
|
msgRequest.Message.Android.TTL = req.HuaweiTTL
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.BiTag) > 0 {
|
||||||
|
msgRequest.Message.Android.BiTag = req.BiTag
|
||||||
|
}
|
||||||
|
|
||||||
|
msgRequest.Message.Android.FastAppTarget = req.FastAppTarget
|
||||||
|
|
||||||
|
// Add data fields
|
||||||
|
if len(req.HuaweiData) > 0 {
|
||||||
|
msgRequest.Message.Data = req.HuaweiData
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notification Message
|
||||||
|
if req.HuaweiNotification != nil {
|
||||||
|
msgRequest.Message.Android.Notification = req.HuaweiNotification
|
||||||
|
|
||||||
|
if msgRequest.Message.Android.Notification.ClickAction == nil {
|
||||||
|
msgRequest.Message.Android.Notification.ClickAction = model.GetDefaultClickAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setDefaultAndroidNotification := func() {
|
||||||
|
if msgRequest.Message.Android == nil {
|
||||||
|
msgRequest.Message.Android.Notification = model.GetDefaultAndroidNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Message) > 0 {
|
||||||
|
setDefaultAndroidNotification()
|
||||||
|
msgRequest.Message.Android.Notification.Body = req.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Title) > 0 {
|
||||||
|
setDefaultAndroidNotification()
|
||||||
|
msgRequest.Message.Android.Notification.Title = req.Title
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Image) > 0 {
|
||||||
|
setDefaultAndroidNotification()
|
||||||
|
msgRequest.Message.Android.Notification.Image = req.Image
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := req.Sound.(string); ok && len(v) > 0 {
|
||||||
|
setDefaultAndroidNotification()
|
||||||
|
msgRequest.Message.Android.Notification.Sound = v
|
||||||
|
} else if msgRequest.Message.Android.Notification != nil {
|
||||||
|
msgRequest.Message.Android.Notification.DefaultSound = true
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(msgRequest)
|
||||||
|
if err != nil {
|
||||||
|
logx.LogError.Error("Failed to marshal the default message! Error is " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logx.LogAccess.Debugf("Default message is %s", string(b))
|
||||||
|
return msgRequest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushToHuawei provide send notification to Android server.
|
||||||
|
func PushToHuawei(req *PushNotification, cfg *config.ConfYaml) (resp *ResponsePush, err error) {
|
||||||
|
logx.LogAccess.Debug("Start push notification for Huawei")
|
||||||
|
|
||||||
|
var (
|
||||||
|
client *client.HMSClient
|
||||||
|
retryCount = 0
|
||||||
|
maxRetry = cfg.Huawei.MaxRetry
|
||||||
|
)
|
||||||
|
|
||||||
|
if req.Retry > 0 && req.Retry < maxRetry {
|
||||||
|
maxRetry = req.Retry
|
||||||
|
}
|
||||||
|
|
||||||
|
// check message
|
||||||
|
err = CheckMessage(req)
|
||||||
|
if err != nil {
|
||||||
|
logx.LogError.Error("request error: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err = InitHMSClient(cfg, cfg.Huawei.AppSecret, cfg.Huawei.AppID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// HMS server error
|
||||||
|
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
|
||||||
|
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" {
|
||||||
|
status.StatStorage.AddHuaweiSuccess(int64(1))
|
||||||
|
logx.LogAccess.Debug("Huwaei Send Notification is completed successfully!")
|
||||||
|
} else {
|
||||||
|
isError = true
|
||||||
|
status.StatStorage.AddHuaweiError(int64(1))
|
||||||
|
logx.LogAccess.Debug("Huawei Send Notification is failed! Code: " + res.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isError && retryCount < maxRetry {
|
||||||
|
retryCount++
|
||||||
|
|
||||||
|
// resend all tokens
|
||||||
|
goto Retry
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
50
push/gorush-with-mipush/src/notify/notification_hms_test.go
Normal file
50
push/gorush-with-mipush/src/notify/notification_hms_test.go
Normal file
@ -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())
|
||||||
|
}
|
311
push/gorush-with-mipush/src/notify/notification_mipush.go
Normal file
311
push/gorush-with-mipush/src/notify/notification_mipush.go
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/appleboy/gorush/config"
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
|
"github.com/appleboy/gorush/status"
|
||||||
|
"github.com/geek-go/xmpush"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mipushError error
|
||||||
|
mipushClient *XMPush
|
||||||
|
mipushOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetMIPushClient use for create HMS Push.
|
||||||
|
func GetMIPushClient(conf *XmpushConfig) (*XMPush, error) {
|
||||||
|
once.Do(func() {
|
||||||
|
client := &XMPush{
|
||||||
|
Config: &XmpushConfig{
|
||||||
|
AppSecret: conf.AppSecret,
|
||||||
|
Package: conf.Package,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mipushClient = client
|
||||||
|
pushError = nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return mipushClient, pushError
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitMIPUSHClient(cfg *config.ConfYaml, appSecret, pkg string) (*XMPush, error) {
|
||||||
|
if appSecret == "" {
|
||||||
|
return nil, errors.New("Missing MI App Secret")
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkg == "" {
|
||||||
|
return nil, errors.New("Missing MI App Package")
|
||||||
|
}
|
||||||
|
conf := &XmpushConfig{
|
||||||
|
AppSecret: appSecret,
|
||||||
|
Package: pkg,
|
||||||
|
}
|
||||||
|
if appSecret != cfg.MI.AppSecret || pkg != cfg.MI.Package {
|
||||||
|
return GetMIPushClient(conf)
|
||||||
|
}
|
||||||
|
if MIPUSHClient == nil {
|
||||||
|
return GetMIPushClient(conf)
|
||||||
|
}
|
||||||
|
return MIPUSHClient, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMINotification(req *PushNotification, pkg string) (*xmpush.Message, error) {
|
||||||
|
payload := &Payload{
|
||||||
|
PushTitle: req.Title,
|
||||||
|
PushBody: req.Message,
|
||||||
|
IsShowNotify: "1",
|
||||||
|
}
|
||||||
|
payloadStr, err := json.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//是否透传
|
||||||
|
passThrough := 1
|
||||||
|
if payload.IsShowNotify == "1" {
|
||||||
|
passThrough = 0 //通知栏消息
|
||||||
|
}
|
||||||
|
|
||||||
|
message := &xmpush.Message{
|
||||||
|
Payload: string(payloadStr),
|
||||||
|
Title: payload.PushTitle,
|
||||||
|
Description: payload.PushBody,
|
||||||
|
PassThrough: int32(passThrough),
|
||||||
|
NotifyType: 1,
|
||||||
|
RestrictedPackageName: pkg,
|
||||||
|
Extra: map[string]string{
|
||||||
|
"notify_foreground": "1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if len(req.Tokens) > 0 {
|
||||||
|
for i, token := range req.Tokens {
|
||||||
|
if i == 0 {
|
||||||
|
message.RegistrationId = token
|
||||||
|
} else {
|
||||||
|
message.RegistrationId = message.RegistrationId + "," + token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return message, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func PushToMI(req *PushNotification, cfg *config.ConfYaml) (resp *ResponsePush, err error) {
|
||||||
|
logx.LogAccess.Debug("Start push notification for MI")
|
||||||
|
|
||||||
|
var (
|
||||||
|
client *XMPush
|
||||||
|
retryCount = 0
|
||||||
|
maxRetry = cfg.MI.MaxRetry
|
||||||
|
)
|
||||||
|
|
||||||
|
if req.Retry > 0 && req.Retry < maxRetry {
|
||||||
|
maxRetry = req.Retry
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err = InitMIPUSHClient(cfg, cfg.MI.AppSecret, cfg.MI.Package)
|
||||||
|
if err != nil {
|
||||||
|
// MI server error
|
||||||
|
logx.LogError.Error("MI server error: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = &ResponsePush{}
|
||||||
|
|
||||||
|
Retry:
|
||||||
|
isError := false
|
||||||
|
notification, err1 := GetMINotification(req, client.Config.Package)
|
||||||
|
if err1 != nil {
|
||||||
|
return nil, err1
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := client.SendMessage(context.Background(), notification)
|
||||||
|
if err != nil {
|
||||||
|
// Send Message error
|
||||||
|
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 == 0 {
|
||||||
|
status.StatStorage.AddMISuccess(int64(1))
|
||||||
|
logx.LogAccess.Debug("MI Send Notification is completed successfully!")
|
||||||
|
} else {
|
||||||
|
isError = true
|
||||||
|
status.StatStorage.AddMIError(int64(1))
|
||||||
|
logx.LogAccess.Debug("MI Send Notification is failed! Code: " + strconv.Itoa(int(res.Code)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if isError && retryCount < maxRetry {
|
||||||
|
retryCount++
|
||||||
|
|
||||||
|
// resend all tokens
|
||||||
|
goto Retry
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var Cfg = &XmpushConfig{
|
||||||
|
AppSecret: "",
|
||||||
|
Package: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
// XmpushConfig ...
|
||||||
|
type XmpushConfig struct {
|
||||||
|
AppSecret string `toml:"app_secret"`
|
||||||
|
Package string `toml:"package"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//Payload 消息payload,根据业务自定义
|
||||||
|
type Payload struct {
|
||||||
|
PushTitle string `json:"push_title"`
|
||||||
|
PushBody string `json:"push_body"`
|
||||||
|
IsShowNotify string `json:"is_show_notify"`
|
||||||
|
Ext string `json:"ext"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type XMPush struct {
|
||||||
|
Config *XmpushConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewXmPush 获取实例
|
||||||
|
func NewXmPush(config *XmpushConfig) (*XMPush, error) {
|
||||||
|
|
||||||
|
if config.Package == "" || config.AppSecret == "" {
|
||||||
|
return nil, errors.New("please check config")
|
||||||
|
}
|
||||||
|
|
||||||
|
xm := &XMPush{
|
||||||
|
Config: config,
|
||||||
|
}
|
||||||
|
|
||||||
|
return xm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *XMPush) SendMessage(ctx context.Context, notification *xmpush.Message) (*xmpush.Result, error) {
|
||||||
|
// 通过 regID 推送
|
||||||
|
if notification.RegistrationId != "" {
|
||||||
|
return xmpush.SendMessageByRegIds(m.Config.AppSecret, notification)
|
||||||
|
}
|
||||||
|
// 群推
|
||||||
|
return xmpush.SendMessageAll(m.Config.AppSecret, notification)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//SendByCid 根据用户cid推送
|
||||||
|
func (m *XMPush) SendByCid(cid string, payload *Payload) error {
|
||||||
|
return m.SendByCids([]string{cid}, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
//SendByCids 根据用户cids批量推送
|
||||||
|
func (m *XMPush) SendByCids(cids []string, payload *Payload) error {
|
||||||
|
|
||||||
|
payloadStr, _ := json.Marshal(payload)
|
||||||
|
|
||||||
|
//是否透传
|
||||||
|
passThrough := 1
|
||||||
|
if payload.IsShowNotify == "1" {
|
||||||
|
passThrough = 0 //通知栏消息
|
||||||
|
}
|
||||||
|
|
||||||
|
message := &xmpush.Message{
|
||||||
|
Payload: string(payloadStr),
|
||||||
|
Title: payload.PushTitle,
|
||||||
|
Description: payload.PushBody,
|
||||||
|
PassThrough: int32(passThrough),
|
||||||
|
NotifyType: 1,
|
||||||
|
RestrictedPackageName: m.Config.Package,
|
||||||
|
Extra: map[string]string{
|
||||||
|
"notify_foreground": "1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
message.RegistrationId = strings.Join(cids, ",")
|
||||||
|
|
||||||
|
result, err := xmpush.SendMessageByRegIds(m.Config.AppSecret, message)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendByAliases 根据别名推送批量推送
|
||||||
|
func (m *XMPush) SendByAliases(aliases []string, payload *Payload) error {
|
||||||
|
|
||||||
|
payloadStr, _ := json.Marshal(payload)
|
||||||
|
|
||||||
|
//是否透传
|
||||||
|
passThrough := 1
|
||||||
|
if payload.IsShowNotify == "1" {
|
||||||
|
passThrough = 0 //通知栏消息
|
||||||
|
}
|
||||||
|
|
||||||
|
message := &xmpush.Message{
|
||||||
|
Payload: string(payloadStr),
|
||||||
|
Title: payload.PushTitle,
|
||||||
|
Description: payload.PushBody,
|
||||||
|
PassThrough: int32(passThrough),
|
||||||
|
NotifyType: 1,
|
||||||
|
RestrictedPackageName: m.Config.Package,
|
||||||
|
Extra: map[string]string{
|
||||||
|
"notify_foreground": "1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
message.Alias = strings.Join(aliases, ",")
|
||||||
|
|
||||||
|
result, err := xmpush.SendMessageByRegAliasIds(m.Config.AppSecret, message)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendAll 推送给所有人
|
||||||
|
func (m *XMPush) SendAll(payload *Payload) error {
|
||||||
|
|
||||||
|
payloadStr, _ := json.Marshal(payload)
|
||||||
|
|
||||||
|
//是否透传
|
||||||
|
passThrough := 1
|
||||||
|
if payload.IsShowNotify == "1" {
|
||||||
|
passThrough = 0 //通知栏消息
|
||||||
|
}
|
||||||
|
|
||||||
|
message := &xmpush.Message{
|
||||||
|
Payload: string(payloadStr),
|
||||||
|
Title: payload.PushTitle,
|
||||||
|
Description: payload.PushBody,
|
||||||
|
PassThrough: int32(passThrough),
|
||||||
|
NotifyType: 1,
|
||||||
|
RestrictedPackageName: m.Config.Package,
|
||||||
|
Extra: map[string]string{
|
||||||
|
"notify_foreground": "1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := xmpush.SendMessageAll(m.Config.AppSecret, message)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
//测试单推
|
||||||
|
func TestXmPush_SendByCid(t *testing.T) {
|
||||||
|
iXmPush, err := NewXmPush(Cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cid := "xxx"
|
||||||
|
payLoad := Payload{"这是测试title", "这是测试内容", "1", ""}
|
||||||
|
err = iXmPush.SendByCid(cid, &payLoad)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else {
|
||||||
|
t.Log("ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//测试群推
|
||||||
|
func TestXmPush_SendByCids(t *testing.T) {
|
||||||
|
iXmPush, err := NewXmPush(Cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cids := []string{"xxx"}
|
||||||
|
payLoad := Payload{"这是测试title", "这是测试内容", "1", ""}
|
||||||
|
err = iXmPush.SendByCids(cids, &payLoad)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else {
|
||||||
|
t.Log("ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//测试全推
|
||||||
|
func TestXmPush_SendAll(t *testing.T) {
|
||||||
|
iXmPush, err := NewXmPush(Cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
payLoad := Payload{"这是测试title", "这是测试内容", "1", ""}
|
||||||
|
err = iXmPush.SendAll(&payLoad)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else {
|
||||||
|
t.Log("ok")
|
||||||
|
}
|
||||||
|
}
|
34
push/gorush-with-mipush/src/notify/notification_test.go
Normal file
34
push/gorush-with-mipush/src/notify/notification_test.go
Normal file
@ -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)
|
||||||
|
}
|
273
push/gorush-with-mipush/src/pipeline.libsonnet
Normal file
273
push/gorush-with-mipush/src/pipeline.libsonnet
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
{
|
||||||
|
test:: {
|
||||||
|
kind: 'pipeline',
|
||||||
|
name: 'testing',
|
||||||
|
platform: {
|
||||||
|
os: 'linux',
|
||||||
|
arch: 'amd64',
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
name: 'lint',
|
||||||
|
image: 'golangci/golangci-lint:v1.41.1',
|
||||||
|
pull: 'always',
|
||||||
|
commands: [
|
||||||
|
'golangci-lint run -v',
|
||||||
|
],
|
||||||
|
volumes: [
|
||||||
|
{
|
||||||
|
name: 'gopath',
|
||||||
|
path: '/go',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'embedmd',
|
||||||
|
image: 'golang:1.17',
|
||||||
|
pull: 'always',
|
||||||
|
commands: [
|
||||||
|
'make embedmd',
|
||||||
|
],
|
||||||
|
volumes: [
|
||||||
|
{
|
||||||
|
name: 'gopath',
|
||||||
|
path: '/go',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'hadolint',
|
||||||
|
image: 'hadolint/hadolint:latest-debian',
|
||||||
|
pull: 'always',
|
||||||
|
commands: [
|
||||||
|
'hadolint --version',
|
||||||
|
'hadolint docker/Dockerfile.linux.amd64',
|
||||||
|
'hadolint docker/Dockerfile.linux.arm64',
|
||||||
|
'hadolint docker/Dockerfile.linux.arm',
|
||||||
|
],
|
||||||
|
volumes: [
|
||||||
|
{
|
||||||
|
name: 'gopath',
|
||||||
|
path: '/go',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'test',
|
||||||
|
image: 'golang:1.17',
|
||||||
|
pull: 'always',
|
||||||
|
environment: {
|
||||||
|
ANDROID_API_KEY: { 'from_secret': 'android_api_key' },
|
||||||
|
ANDROID_TEST_TOKEN: { 'from_secret': 'android_test_token' },
|
||||||
|
},
|
||||||
|
commands: [
|
||||||
|
'make test',
|
||||||
|
],
|
||||||
|
volumes: [
|
||||||
|
{
|
||||||
|
name: 'gopath',
|
||||||
|
path: '/go',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'codecov',
|
||||||
|
image: 'robertstettner/drone-codecov',
|
||||||
|
pull: 'always',
|
||||||
|
settings: {
|
||||||
|
token: { 'from_secret': 'codecov_token' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
volumes: [
|
||||||
|
{
|
||||||
|
name: 'gopath',
|
||||||
|
temp: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
services: [
|
||||||
|
{
|
||||||
|
name: 'redis',
|
||||||
|
image: 'redis',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'nsq',
|
||||||
|
image: 'nsqio/nsq',
|
||||||
|
commands: [
|
||||||
|
"/nsqd",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
build(name, os='linux', arch='amd64'):: {
|
||||||
|
kind: 'pipeline',
|
||||||
|
name: os + '-' + arch,
|
||||||
|
platform: {
|
||||||
|
os: os,
|
||||||
|
arch: arch,
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
name: 'build-push',
|
||||||
|
image: 'golang:1.17',
|
||||||
|
pull: 'always',
|
||||||
|
environment: {
|
||||||
|
CGO_ENABLED: '0',
|
||||||
|
},
|
||||||
|
commands: [
|
||||||
|
'go build -v -ldflags \'-X main.build=${DRONE_BUILD_NUMBER}\' -a -o release/' + os + '/' + arch + '/' + name,
|
||||||
|
],
|
||||||
|
when: {
|
||||||
|
event: {
|
||||||
|
exclude: [ 'tag' ],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// name: 'build-push-lambda',
|
||||||
|
// image: 'golang:1.17',
|
||||||
|
// pull: 'always',
|
||||||
|
// environment: {
|
||||||
|
// CGO_ENABLED: '0',
|
||||||
|
// },
|
||||||
|
// commands: [
|
||||||
|
// 'go build -v -tags \'lambda\' -ldflags \'-X main.build=${DRONE_BUILD_NUMBER}\' -a -o release/' + os + '/' + arch + '/lambda/' + name,
|
||||||
|
// ],
|
||||||
|
// when: {
|
||||||
|
// event: {
|
||||||
|
// exclude: [ 'tag' ],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
name: 'build-tag',
|
||||||
|
image: 'golang:1.17',
|
||||||
|
pull: 'always',
|
||||||
|
environment: {
|
||||||
|
CGO_ENABLED: '0',
|
||||||
|
},
|
||||||
|
commands: [
|
||||||
|
'go build -v -ldflags \'-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}\' -a -o release/' + os + '/' + arch + '/' + name,
|
||||||
|
],
|
||||||
|
when: {
|
||||||
|
event: [ 'tag' ],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'executable',
|
||||||
|
image: 'golang:1.17',
|
||||||
|
pull: 'always',
|
||||||
|
commands: [
|
||||||
|
'./release/' + os + '/' + arch + '/' + name + ' --help',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'publish',
|
||||||
|
image: 'plugins/docker:' + os + '-' + arch,
|
||||||
|
pull: 'always',
|
||||||
|
settings: {
|
||||||
|
daemon_off: 'false',
|
||||||
|
auto_tag: true,
|
||||||
|
auto_tag_suffix: os + '-' + arch,
|
||||||
|
dockerfile: 'docker/Dockerfile.' + os + '.' + arch,
|
||||||
|
repo: 'appleboy/' + name,
|
||||||
|
cache_from: 'appleboy/' + name,
|
||||||
|
username: { 'from_secret': 'docker_username' },
|
||||||
|
password: { 'from_secret': 'docker_password' },
|
||||||
|
},
|
||||||
|
when: {
|
||||||
|
event: {
|
||||||
|
exclude: [ 'pull_request' ],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
depends_on: [
|
||||||
|
'testing',
|
||||||
|
],
|
||||||
|
trigger: {
|
||||||
|
ref: [
|
||||||
|
'refs/heads/master',
|
||||||
|
'refs/pull/**',
|
||||||
|
'refs/tags/**',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
release:: {
|
||||||
|
kind: 'pipeline',
|
||||||
|
name: 'release-binary',
|
||||||
|
platform: {
|
||||||
|
os: 'linux',
|
||||||
|
arch: 'amd64',
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
name: 'build-all-binary',
|
||||||
|
image: 'golang:1.17',
|
||||||
|
pull: 'always',
|
||||||
|
commands: [
|
||||||
|
'make release'
|
||||||
|
],
|
||||||
|
when: {
|
||||||
|
event: [ 'tag' ],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'deploy-all-binary',
|
||||||
|
image: 'plugins/github-release',
|
||||||
|
pull: 'always',
|
||||||
|
settings: {
|
||||||
|
files: [ 'dist/release/*' ],
|
||||||
|
api_key: { 'from_secret': 'github_release_api_key' },
|
||||||
|
},
|
||||||
|
when: {
|
||||||
|
event: [ 'tag' ],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
depends_on: [
|
||||||
|
'testing',
|
||||||
|
],
|
||||||
|
trigger: {
|
||||||
|
ref: [
|
||||||
|
'refs/tags/**',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
notifications(os='linux', arch='amd64', depends_on=[]):: {
|
||||||
|
kind: 'pipeline',
|
||||||
|
name: 'notifications',
|
||||||
|
platform: {
|
||||||
|
os: os,
|
||||||
|
arch: arch,
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
name: 'manifest',
|
||||||
|
image: 'plugins/manifest',
|
||||||
|
pull: 'always',
|
||||||
|
settings: {
|
||||||
|
username: { from_secret: 'docker_username' },
|
||||||
|
password: { from_secret: 'docker_password' },
|
||||||
|
spec: 'docker/manifest.tmpl',
|
||||||
|
ignore_missing: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
depends_on: depends_on,
|
||||||
|
trigger: {
|
||||||
|
ref: [
|
||||||
|
'refs/heads/master',
|
||||||
|
'refs/tags/**',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
signature(key):: {
|
||||||
|
kind: 'signature',
|
||||||
|
hmac: key,
|
||||||
|
},
|
||||||
|
}
|
322
push/gorush-with-mipush/src/router/server.go
Normal file
322
push/gorush-with-mipush/src/router/server.go
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
case core.PlaFormMI:
|
||||||
|
if !cfg.MI.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
|
||||||
|
}
|
27
push/gorush-with-mipush/src/router/server_lambda.go
Normal file
27
push/gorush-with-mipush/src/router/server_lambda.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//go:build lambda
|
||||||
|
// +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))
|
||||||
|
}
|
125
push/gorush-with-mipush/src/router/server_normal.go
Normal file
125
push/gorush-with-mipush/src/router/server_normal.go
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
//go:build !lambda
|
||||||
|
// +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)
|
||||||
|
}
|
679
push/gorush-with-mipush/src/router/server_test.go
Normal file
679
push/gorush-with-mipush/src/router/server_test.go
Normal file
@ -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))
|
||||||
|
}
|
38
push/gorush-with-mipush/src/router/version.go
Normal file
38
push/gorush-with-mipush/src/router/version.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
var version string
|
||||||
|
|
||||||
|
// SetVersion for setup version string.
|
||||||
|
func SetVersion(ver string) {
|
||||||
|
version = ver
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVersion for get current version.
|
||||||
|
func GetVersion() string {
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintGoRushVersion provide print server engine
|
||||||
|
func PrintGoRushVersion() {
|
||||||
|
fmt.Printf(`GoRush %s, Compiler: %s %s, Copyright (C) 2019 Bo-Yi Wu, Inc.`,
|
||||||
|
version,
|
||||||
|
runtime.Compiler,
|
||||||
|
runtime.Version())
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
// VersionMiddleware : add version on header.
|
||||||
|
func VersionMiddleware() gin.HandlerFunc {
|
||||||
|
// Set out header value for each response
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
c.Header("X-GORUSH-VERSION", version)
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
58
push/gorush-with-mipush/src/rpc/client_grpc_health.go
Normal file
58
push/gorush-with-mipush/src/rpc/client_grpc_health.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/rpc/proto"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// generate protobuffs
|
||||||
|
// protoc --go_out=plugins=grpc,import_path=proto:. *.proto
|
||||||
|
|
||||||
|
type healthClient struct {
|
||||||
|
client proto.HealthClient
|
||||||
|
conn *grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGrpcHealthClient returns a new grpc Client.
|
||||||
|
func NewGrpcHealthClient(conn *grpc.ClientConn) Health {
|
||||||
|
client := new(healthClient)
|
||||||
|
client.client = proto.NewHealthClient(conn)
|
||||||
|
client.conn = conn
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *healthClient) Close() error {
|
||||||
|
return c.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *healthClient) Check(ctx context.Context) (bool, error) {
|
||||||
|
var res *proto.HealthCheckResponse
|
||||||
|
var err error
|
||||||
|
req := new(proto.HealthCheckRequest)
|
||||||
|
|
||||||
|
res, err = c.client.Check(ctx, req)
|
||||||
|
if err == nil {
|
||||||
|
if res.GetStatus() == proto.HealthCheckResponse_SERVING {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
switch status.Code(err) {
|
||||||
|
case
|
||||||
|
codes.Aborted,
|
||||||
|
codes.DataLoss,
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Internal,
|
||||||
|
codes.Unavailable:
|
||||||
|
// non-fatal errors
|
||||||
|
default:
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, err
|
||||||
|
}
|
1
push/gorush-with-mipush/src/rpc/client_test.go
Normal file
1
push/gorush-with-mipush/src/rpc/client_test.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package rpc
|
38
push/gorush-with-mipush/src/rpc/example/go/health/main.go
Normal file
38
push/gorush-with-mipush/src/rpc/example/go/health/main.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/rpc"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
address = "localhost:9000"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Set up a connection to the server.
|
||||||
|
conn, err := grpc.Dial(address, grpc.WithInsecure())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("did not connect: %v", err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
client := rpc.NewGrpcHealthClient(conn)
|
||||||
|
|
||||||
|
for {
|
||||||
|
ok, err := client.Check(context.Background())
|
||||||
|
if !ok || err != nil {
|
||||||
|
log.Printf("can't connect grpc server: %v, code: %v\n", err, status.Code(err))
|
||||||
|
} else {
|
||||||
|
log.Println("connect the grpc server successfully")
|
||||||
|
}
|
||||||
|
|
||||||
|
<-time.After(time.Second)
|
||||||
|
}
|
||||||
|
}
|
60
push/gorush-with-mipush/src/rpc/example/go/send/main.go
Normal file
60
push/gorush-with-mipush/src/rpc/example/go/send/main.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/rpc/proto"
|
||||||
|
|
||||||
|
structpb "github.com/golang/protobuf/ptypes/struct"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
address = "localhost:9000"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Set up a connection to the server.
|
||||||
|
conn, err := grpc.Dial(address, grpc.WithInsecure())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("did not connect: %v", err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
c := proto.NewGorushClient(conn)
|
||||||
|
|
||||||
|
r, err := c.Send(context.Background(), &proto.NotificationRequest{
|
||||||
|
Platform: 2,
|
||||||
|
Tokens: []string{"1234567890"},
|
||||||
|
Message: "test message",
|
||||||
|
Badge: 1,
|
||||||
|
Category: "test",
|
||||||
|
Sound: "test",
|
||||||
|
Priority: proto.NotificationRequest_HIGH,
|
||||||
|
Alert: &proto.Alert{
|
||||||
|
Title: "Test Title",
|
||||||
|
Body: "Test Alert Body",
|
||||||
|
Subtitle: "Test Alert Sub Title",
|
||||||
|
LocKey: "Test loc key",
|
||||||
|
LocArgs: []string{"test", "test"},
|
||||||
|
},
|
||||||
|
Data: &structpb.Struct{
|
||||||
|
Fields: map[string]*structpb.Value{
|
||||||
|
"key1": {
|
||||||
|
Kind: &structpb.Value_StringValue{StringValue: "welcome"},
|
||||||
|
},
|
||||||
|
"key2": {
|
||||||
|
Kind: &structpb.Value_NumberValue{NumberValue: 2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Println("could not greet: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r != nil {
|
||||||
|
log.Printf("Success: %t\n", r.Success)
|
||||||
|
log.Printf("Count: %d\n", r.Counts)
|
||||||
|
}
|
||||||
|
}
|
4
push/gorush-with-mipush/src/rpc/example/node/.gitignore
vendored
Normal file
4
push/gorush-with-mipush/src/rpc/example/node/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*~
|
||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
.yarn-cache
|
19
push/gorush-with-mipush/src/rpc/example/node/README.md
Normal file
19
push/gorush-with-mipush/src/rpc/example/node/README.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# gRPC in 3 minutes (Node.js)
|
||||||
|
|
||||||
|
## PREREQUISITES
|
||||||
|
|
||||||
|
`node`: This requires Node 12.x or greater.
|
||||||
|
|
||||||
|
## INSTALL
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install
|
||||||
|
npm install -g grpc-tools
|
||||||
|
```
|
||||||
|
|
||||||
|
## Node gRPC protoc
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd $GOPATH/src/github.com/appleboy/gorush
|
||||||
|
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=`which grpc_tools_node_protoc_plugin`
|
||||||
|
```
|
33
push/gorush-with-mipush/src/rpc/example/node/client.js
Normal file
33
push/gorush-with-mipush/src/rpc/example/node/client.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
var messages = require('./gorush_pb');
|
||||||
|
var services = require('./gorush_grpc_pb');
|
||||||
|
|
||||||
|
var grpc = require('grpc');
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
var client = new services.GorushClient('localhost:9000',
|
||||||
|
grpc.credentials.createInsecure());
|
||||||
|
var request = new messages.NotificationRequest();
|
||||||
|
var alert = new messages.Alert();
|
||||||
|
request.setPlatform(2);
|
||||||
|
request.setTokensList(["1234567890"]);
|
||||||
|
request.setMessage("Hello!!");
|
||||||
|
request.setTitle("hello2");
|
||||||
|
request.setBadge(2);
|
||||||
|
request.setCategory("mycategory");
|
||||||
|
request.setSound("sound")
|
||||||
|
alert.setTitle("title");
|
||||||
|
request.setAlert(alert);
|
||||||
|
request.setThreadid("threadID");
|
||||||
|
request.setContentavailable(false);
|
||||||
|
request.setMutablecontent(false);
|
||||||
|
client.send(request, function (err, response) {
|
||||||
|
if(err) {
|
||||||
|
console.log(err);
|
||||||
|
} else {
|
||||||
|
console.log("Success:", response.getSuccess());
|
||||||
|
console.log("Counts:", response.getCounts());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
@ -0,0 +1,82 @@
|
|||||||
|
// GENERATED CODE -- DO NOT EDIT!
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
var grpc = require('grpc');
|
||||||
|
var gorush_pb = require('./gorush_pb.js');
|
||||||
|
var google_protobuf_struct_pb = require('google-protobuf/google/protobuf/struct_pb.js');
|
||||||
|
|
||||||
|
function serialize_proto_HealthCheckRequest(arg) {
|
||||||
|
if (!(arg instanceof gorush_pb.HealthCheckRequest)) {
|
||||||
|
throw new Error('Expected argument of type proto.HealthCheckRequest');
|
||||||
|
}
|
||||||
|
return Buffer.from(arg.serializeBinary());
|
||||||
|
}
|
||||||
|
|
||||||
|
function deserialize_proto_HealthCheckRequest(buffer_arg) {
|
||||||
|
return gorush_pb.HealthCheckRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
function serialize_proto_HealthCheckResponse(arg) {
|
||||||
|
if (!(arg instanceof gorush_pb.HealthCheckResponse)) {
|
||||||
|
throw new Error('Expected argument of type proto.HealthCheckResponse');
|
||||||
|
}
|
||||||
|
return Buffer.from(arg.serializeBinary());
|
||||||
|
}
|
||||||
|
|
||||||
|
function deserialize_proto_HealthCheckResponse(buffer_arg) {
|
||||||
|
return gorush_pb.HealthCheckResponse.deserializeBinary(new Uint8Array(buffer_arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
function serialize_proto_NotificationReply(arg) {
|
||||||
|
if (!(arg instanceof gorush_pb.NotificationReply)) {
|
||||||
|
throw new Error('Expected argument of type proto.NotificationReply');
|
||||||
|
}
|
||||||
|
return Buffer.from(arg.serializeBinary());
|
||||||
|
}
|
||||||
|
|
||||||
|
function deserialize_proto_NotificationReply(buffer_arg) {
|
||||||
|
return gorush_pb.NotificationReply.deserializeBinary(new Uint8Array(buffer_arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
function serialize_proto_NotificationRequest(arg) {
|
||||||
|
if (!(arg instanceof gorush_pb.NotificationRequest)) {
|
||||||
|
throw new Error('Expected argument of type proto.NotificationRequest');
|
||||||
|
}
|
||||||
|
return Buffer.from(arg.serializeBinary());
|
||||||
|
}
|
||||||
|
|
||||||
|
function deserialize_proto_NotificationRequest(buffer_arg) {
|
||||||
|
return gorush_pb.NotificationRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var GorushService = exports.GorushService = {
|
||||||
|
send: {
|
||||||
|
path: '/proto.Gorush/Send',
|
||||||
|
requestStream: false,
|
||||||
|
responseStream: false,
|
||||||
|
requestType: gorush_pb.NotificationRequest,
|
||||||
|
responseType: gorush_pb.NotificationReply,
|
||||||
|
requestSerialize: serialize_proto_NotificationRequest,
|
||||||
|
requestDeserialize: deserialize_proto_NotificationRequest,
|
||||||
|
responseSerialize: serialize_proto_NotificationReply,
|
||||||
|
responseDeserialize: deserialize_proto_NotificationReply,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.GorushClient = grpc.makeGenericClientConstructor(GorushService);
|
||||||
|
var HealthService = exports.HealthService = {
|
||||||
|
check: {
|
||||||
|
path: '/proto.Health/Check',
|
||||||
|
requestStream: false,
|
||||||
|
responseStream: false,
|
||||||
|
requestType: gorush_pb.HealthCheckRequest,
|
||||||
|
responseType: gorush_pb.HealthCheckResponse,
|
||||||
|
requestSerialize: serialize_proto_HealthCheckRequest,
|
||||||
|
requestDeserialize: deserialize_proto_HealthCheckRequest,
|
||||||
|
responseSerialize: serialize_proto_HealthCheckResponse,
|
||||||
|
responseDeserialize: deserialize_proto_HealthCheckResponse,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.HealthClient = grpc.makeGenericClientConstructor(HealthService);
|
1661
push/gorush-with-mipush/src/rpc/example/node/gorush_pb.js
Normal file
1661
push/gorush-with-mipush/src/rpc/example/node/gorush_pb.js
Normal file
File diff suppressed because it is too large
Load Diff
623
push/gorush-with-mipush/src/rpc/example/node/package-lock.json
generated
Normal file
623
push/gorush-with-mipush/src/rpc/example/node/package-lock.json
generated
Normal file
@ -0,0 +1,623 @@
|
|||||||
|
{
|
||||||
|
"name": "gorush-examples",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"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.42",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.42.tgz",
|
||||||
|
"integrity": "sha512-lEgKojWUAc/MG2t649oZS5AfYFP2xRNPoDuwDBlBMjHXd8MaGPgFgtCXUK7inZdBOygmVf10qxc1Us8GXC96aw==",
|
||||||
|
"requires": {
|
||||||
|
"@types/long": "*",
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/long": {
|
||||||
|
"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": "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"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"async": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/async/-/async-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-4vx/aaY6j/j3Lw3fbCHNWP0pPaTCew3F6F3hYyl/tHs/ndmV1q7NW9T5yuJ2XAGwdQrP+6Wu20x06U4APo/iQQ=="
|
||||||
|
},
|
||||||
|
"balanced-match": {
|
||||||
|
"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",
|
||||||
|
"concat-map": "0.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bytebuffer": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz",
|
||||||
|
"integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=",
|
||||||
|
"requires": {
|
||||||
|
"long": "~3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"camelcase": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"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.1",
|
||||||
|
"strip-ansi": "^3.0.1",
|
||||||
|
"wrap-ansi": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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="
|
||||||
|
},
|
||||||
|
"colour": {
|
||||||
|
"version": "0.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz",
|
||||||
|
"integrity": "sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g="
|
||||||
|
},
|
||||||
|
"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": "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.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.4",
|
||||||
|
"inherits": "2",
|
||||||
|
"minimatch": "^3.0.4",
|
||||||
|
"once": "^1.3.0",
|
||||||
|
"path-is-absolute": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"global": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
|
||||||
|
"requires": {
|
||||||
|
"min-document": "2.19.0",
|
||||||
|
"process": "0.11.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"google-protobuf": {
|
||||||
|
"version": "3.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.10.0.tgz",
|
||||||
|
"integrity": "sha512-d0cMO8TJ6xtB/WrVHCv5U81L2ulX+aCD58IljyAN6mHwdHHJ2jbcauX5glvivi3s3hx7EYEo7eUA9WftzamMnw=="
|
||||||
|
},
|
||||||
|
"grpc": {
|
||||||
|
"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": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
|
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||||
|
"requires": {
|
||||||
|
"once": "^1.3.0",
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"inherits": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||||
|
},
|
||||||
|
"invert-kv": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
|
||||||
|
},
|
||||||
|
"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.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"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lodash": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
|
},
|
||||||
|
"lodash.camelcase": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||||
|
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
|
||||||
|
},
|
||||||
|
"lodash.clone": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz",
|
||||||
|
"integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y="
|
||||||
|
},
|
||||||
|
"long": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"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",
|
||||||
|
"integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
|
||||||
|
"requires": {
|
||||||
|
"dom-walk": "0.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimist": {
|
||||||
|
"version": "1.2.5",
|
||||||
|
"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.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"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"optjs": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz",
|
||||||
|
"integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4="
|
||||||
|
},
|
||||||
|
"os-locale": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
|
||||||
|
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
|
||||||
|
"requires": {
|
||||||
|
"lcid": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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": {
|
||||||
|
"version": "0.11.10",
|
||||||
|
"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",
|
||||||
|
"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.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": {
|
||||||
|
"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.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": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz",
|
||||||
|
"integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY="
|
||||||
|
},
|
||||||
|
"wrap-ansi": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
||||||
|
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
|
||||||
|
"requires": {
|
||||||
|
"string-width": "^1.0.1",
|
||||||
|
"strip-ansi": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wrappy": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
|
},
|
||||||
|
"y18n": {
|
||||||
|
"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.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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
push/gorush-with-mipush/src/rpc/example/node/package.json
Normal file
12
push/gorush-with-mipush/src/rpc/example/node/package.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "gorush-examples",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"dependencies": {
|
||||||
|
"async": "^3.1.0",
|
||||||
|
"global": "^4.4.0",
|
||||||
|
"google-protobuf": "^3.10.0",
|
||||||
|
"grpc": "^1.24.9",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"minimist": ">=1.2.2"
|
||||||
|
}
|
||||||
|
}
|
11
push/gorush-with-mipush/src/rpc/health.go
Normal file
11
push/gorush-with-mipush/src/rpc/health.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Health defines a health-check connection.
|
||||||
|
type Health interface {
|
||||||
|
// Check returns if server is healthy or not
|
||||||
|
Check(c context.Context) (bool, error)
|
||||||
|
}
|
782
push/gorush-with-mipush/src/rpc/proto/gorush.pb.go
Normal file
782
push/gorush-with-mipush/src/rpc/proto/gorush.pb.go
Normal file
@ -0,0 +1,782 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.27.1
|
||||||
|
// protoc v3.17.3
|
||||||
|
// source: gorush.proto
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type NotificationRequest_Priority int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
NotificationRequest_NORMAL NotificationRequest_Priority = 0
|
||||||
|
NotificationRequest_HIGH NotificationRequest_Priority = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for NotificationRequest_Priority.
|
||||||
|
var (
|
||||||
|
NotificationRequest_Priority_name = map[int32]string{
|
||||||
|
0: "NORMAL",
|
||||||
|
1: "HIGH",
|
||||||
|
}
|
||||||
|
NotificationRequest_Priority_value = map[string]int32{
|
||||||
|
"NORMAL": 0,
|
||||||
|
"HIGH": 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x NotificationRequest_Priority) Enum() *NotificationRequest_Priority {
|
||||||
|
p := new(NotificationRequest_Priority)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x NotificationRequest_Priority) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (NotificationRequest_Priority) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_gorush_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (NotificationRequest_Priority) Type() protoreflect.EnumType {
|
||||||
|
return &file_gorush_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x NotificationRequest_Priority) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use NotificationRequest_Priority.Descriptor instead.
|
||||||
|
func (NotificationRequest_Priority) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_gorush_proto_rawDescGZIP(), []int{1, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
type HealthCheckResponse_ServingStatus int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
HealthCheckResponse_UNKNOWN HealthCheckResponse_ServingStatus = 0
|
||||||
|
HealthCheckResponse_SERVING HealthCheckResponse_ServingStatus = 1
|
||||||
|
HealthCheckResponse_NOT_SERVING HealthCheckResponse_ServingStatus = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for HealthCheckResponse_ServingStatus.
|
||||||
|
var (
|
||||||
|
HealthCheckResponse_ServingStatus_name = map[int32]string{
|
||||||
|
0: "UNKNOWN",
|
||||||
|
1: "SERVING",
|
||||||
|
2: "NOT_SERVING",
|
||||||
|
}
|
||||||
|
HealthCheckResponse_ServingStatus_value = map[string]int32{
|
||||||
|
"UNKNOWN": 0,
|
||||||
|
"SERVING": 1,
|
||||||
|
"NOT_SERVING": 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x HealthCheckResponse_ServingStatus) Enum() *HealthCheckResponse_ServingStatus {
|
||||||
|
p := new(HealthCheckResponse_ServingStatus)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x HealthCheckResponse_ServingStatus) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HealthCheckResponse_ServingStatus) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_gorush_proto_enumTypes[1].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HealthCheckResponse_ServingStatus) Type() protoreflect.EnumType {
|
||||||
|
return &file_gorush_proto_enumTypes[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x HealthCheckResponse_ServingStatus) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use HealthCheckResponse_ServingStatus.Descriptor instead.
|
||||||
|
func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_gorush_proto_rawDescGZIP(), []int{4, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Alert struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
|
||||||
|
Body string `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"`
|
||||||
|
Subtitle string `protobuf:"bytes,3,opt,name=subtitle,proto3" json:"subtitle,omitempty"`
|
||||||
|
Action string `protobuf:"bytes,4,opt,name=action,proto3" json:"action,omitempty"`
|
||||||
|
ActionLocKey string `protobuf:"bytes,5,opt,name=actionLocKey,proto3" json:"actionLocKey,omitempty"`
|
||||||
|
LaunchImage string `protobuf:"bytes,6,opt,name=launchImage,proto3" json:"launchImage,omitempty"`
|
||||||
|
LocKey string `protobuf:"bytes,7,opt,name=locKey,proto3" json:"locKey,omitempty"`
|
||||||
|
TitleLocKey string `protobuf:"bytes,8,opt,name=titleLocKey,proto3" json:"titleLocKey,omitempty"`
|
||||||
|
LocArgs []string `protobuf:"bytes,9,rep,name=locArgs,proto3" json:"locArgs,omitempty"`
|
||||||
|
TitleLocArgs []string `protobuf:"bytes,10,rep,name=titleLocArgs,proto3" json:"titleLocArgs,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) Reset() {
|
||||||
|
*x = Alert{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_gorush_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Alert) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Alert) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_gorush_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Alert.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Alert) Descriptor() ([]byte, []int) {
|
||||||
|
return file_gorush_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetTitle() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Title
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetBody() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Body
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetSubtitle() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Subtitle
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetAction() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Action
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetActionLocKey() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.ActionLocKey
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetLaunchImage() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.LaunchImage
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetLocKey() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.LocKey
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetTitleLocKey() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.TitleLocKey
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetLocArgs() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.LocArgs
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetTitleLocArgs() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.TitleLocArgs
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotificationRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
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 *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"`
|
||||||
|
ID string `protobuf:"bytes,17,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) Reset() {
|
||||||
|
*x = NotificationRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_gorush_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*NotificationRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_gorush_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use NotificationRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*NotificationRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_gorush_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetTokens() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Tokens
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetPlatform() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Platform
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetMessage() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Message
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetTitle() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Title
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetTopic() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Topic
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetKey() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Key
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetBadge() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Badge
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetCategory() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Category
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetAlert() *Alert {
|
||||||
|
if x != nil {
|
||||||
|
return x.Alert
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetSound() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Sound
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetContentAvailable() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.ContentAvailable
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetThreadID() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.ThreadID
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetMutableContent() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.MutableContent
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetData() *structpb.Struct {
|
||||||
|
if x != nil {
|
||||||
|
return x.Data
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetImage() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Image
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetPriority() NotificationRequest_Priority {
|
||||||
|
if x != nil {
|
||||||
|
return x.Priority
|
||||||
|
}
|
||||||
|
return NotificationRequest_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationRequest) GetID() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.ID
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotificationReply struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||||
|
Counts int32 `protobuf:"varint,2,opt,name=counts,proto3" json:"counts,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationReply) Reset() {
|
||||||
|
*x = NotificationReply{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_gorush_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationReply) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*NotificationReply) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *NotificationReply) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_gorush_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use NotificationReply.ProtoReflect.Descriptor instead.
|
||||||
|
func (*NotificationReply) Descriptor() ([]byte, []int) {
|
||||||
|
return file_gorush_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationReply) GetSuccess() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Success
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotificationReply) GetCounts() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Counts
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type HealthCheckRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthCheckRequest) Reset() {
|
||||||
|
*x = HealthCheckRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_gorush_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthCheckRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HealthCheckRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_gorush_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use HealthCheckRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*HealthCheckRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_gorush_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthCheckRequest) GetService() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Service
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type HealthCheckResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Status HealthCheckResponse_ServingStatus `protobuf:"varint,1,opt,name=status,proto3,enum=proto.HealthCheckResponse_ServingStatus" json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthCheckResponse) Reset() {
|
||||||
|
*x = HealthCheckResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_gorush_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthCheckResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HealthCheckResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_gorush_proto_msgTypes[4]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use HealthCheckResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*HealthCheckResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_gorush_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HealthCheckResponse) GetStatus() HealthCheckResponse_ServingStatus {
|
||||||
|
if x != nil {
|
||||||
|
return x.Status
|
||||||
|
}
|
||||||
|
return HealthCheckResponse_UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_gorush_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_gorush_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x0c, 0x67, 0x6f, 0x72, 0x75, 0x73, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05,
|
||||||
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x22, 0xa3, 0x02, 0x0a, 0x05, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x12, 0x14, 0x0a,
|
||||||
|
0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69,
|
||||||
|
0x74, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x74, 0x69,
|
||||||
|
0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x74, 0x69,
|
||||||
|
0x74, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20,
|
||||||
|
0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x61,
|
||||||
|
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63, 0x4b, 0x65, 0x79, 0x12,
|
||||||
|
0x20, 0x0a, 0x0b, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x06,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x49, 0x6d, 0x61, 0x67,
|
||||||
|
0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x06, 0x6c, 0x6f, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x69, 0x74,
|
||||||
|
0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
|
||||||
|
0x74, 0x69, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6c,
|
||||||
|
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, 0xb3, 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,
|
||||||
|
0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61,
|
||||||
|
0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||||
|
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
|
||||||
|
0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
|
||||||
|
0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x05,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x6b,
|
||||||
|
0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
|
||||||
|
0x05, 0x62, 0x61, 0x64, 0x67, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x62, 0x61,
|
||||||
|
0x64, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18,
|
||||||
|
0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12,
|
||||||
|
0x22, 0x0a, 0x05, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c,
|
||||||
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x52, 0x05, 0x61, 0x6c,
|
||||||
|
0x65, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x0a, 0x20, 0x01,
|
||||||
|
0x28, 0x09, 0x52, 0x05, 0x73, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e,
|
||||||
|
0x74, 0x65, 0x6e, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0b, 0x20,
|
||||||
|
0x01, 0x28, 0x08, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x41, 0x76, 0x61, 0x69,
|
||||||
|
0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49,
|
||||||
|
0x44, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49,
|
||||||
|
0x44, 0x12, 0x26, 0x0a, 0x0e, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74,
|
||||||
|
0x65, 0x6e, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x74, 0x61, 0x62,
|
||||||
|
0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74,
|
||||||
|
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, 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, 0x12, 0x0e, 0x0a,
|
||||||
|
0x02, 0x49, 0x44, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 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, 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,
|
||||||
|
0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_gorush_proto_rawDescOnce sync.Once
|
||||||
|
file_gorush_proto_rawDescData = file_gorush_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_gorush_proto_rawDescGZIP() []byte {
|
||||||
|
file_gorush_proto_rawDescOnce.Do(func() {
|
||||||
|
file_gorush_proto_rawDescData = protoimpl.X.CompressGZIP(file_gorush_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_gorush_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_gorush_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||||
|
file_gorush_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||||
|
file_gorush_proto_goTypes = []interface{}{
|
||||||
|
(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
|
||||||
|
(*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.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
|
||||||
|
4, // 6: proto.Gorush.Send:output_type -> proto.NotificationReply
|
||||||
|
6, // 7: proto.Health.Check:output_type -> proto.HealthCheckResponse
|
||||||
|
6, // [6:8] is the sub-list for method output_type
|
||||||
|
4, // [4:6] is the sub-list for method input_type
|
||||||
|
4, // [4:4] is the sub-list for extension type_name
|
||||||
|
4, // [4:4] is the sub-list for extension extendee
|
||||||
|
0, // [0:4] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_gorush_proto_init() }
|
||||||
|
func file_gorush_proto_init() {
|
||||||
|
if File_gorush_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_gorush_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Alert); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_gorush_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*NotificationRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_gorush_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*NotificationReply); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_gorush_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*HealthCheckRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_gorush_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*HealthCheckResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_gorush_proto_rawDesc,
|
||||||
|
NumEnums: 2,
|
||||||
|
NumMessages: 5,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 2,
|
||||||
|
},
|
||||||
|
GoTypes: file_gorush_proto_goTypes,
|
||||||
|
DependencyIndexes: file_gorush_proto_depIdxs,
|
||||||
|
EnumInfos: file_gorush_proto_enumTypes,
|
||||||
|
MessageInfos: file_gorush_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_gorush_proto = out.File
|
||||||
|
file_gorush_proto_rawDesc = nil
|
||||||
|
file_gorush_proto_goTypes = nil
|
||||||
|
file_gorush_proto_depIdxs = nil
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user