refactor: create logx package (#584)
This commit is contained in:
parent
bcb9a33d43
commit
35e1998cc5
|
@ -0,0 +1,17 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
const (
|
||||||
|
// PlatFormIos constant is 1 for iOS
|
||||||
|
PlatFormIos = iota + 1
|
||||||
|
// PlatFormAndroid constant is 2 for Android
|
||||||
|
PlatFormAndroid
|
||||||
|
// PlatFormHuawei constant is 3 for Huawei
|
||||||
|
PlatFormHuawei
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SucceededPush is log block
|
||||||
|
SucceededPush = "succeeded-push"
|
||||||
|
// FailedPush is log block
|
||||||
|
FailedPush = "failed-push"
|
||||||
|
)
|
|
@ -1,21 +1,5 @@
|
||||||
package gorush
|
package gorush
|
||||||
|
|
||||||
const (
|
|
||||||
// PlatFormIos constant is 1 for iOS
|
|
||||||
PlatFormIos = iota + 1
|
|
||||||
// PlatFormAndroid constant is 2 for Android
|
|
||||||
PlatFormAndroid
|
|
||||||
// PlatFormHuawei constant is 3 for Huawei
|
|
||||||
PlatFormHuawei
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// SucceededPush is log block
|
|
||||||
SucceededPush = "succeeded-push"
|
|
||||||
// FailedPush is log block
|
|
||||||
FailedPush = "failed-push"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Stat variable for redis
|
// Stat variable for redis
|
||||||
const (
|
const (
|
||||||
TotalCountKey = "gorush-total-count"
|
TotalCountKey = "gorush-total-count"
|
||||||
|
|
|
@ -7,10 +7,12 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DispatchFeedback sends a feedback to the configured gateway.
|
// DispatchFeedback sends a feedback to the configured gateway.
|
||||||
func DispatchFeedback(log LogPushEntry, url string, timeout int64) error {
|
func DispatchFeedback(log logx.LogPushEntry, url string, timeout int64) error {
|
||||||
if url == "" {
|
if url == "" {
|
||||||
return errors.New("The url can't be empty")
|
return errors.New("The url can't be empty")
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,14 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/appleboy/gorush/config"
|
"github.com/appleboy/gorush/config"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEmptyFeedbackURL(t *testing.T) {
|
func TestEmptyFeedbackURL(t *testing.T) {
|
||||||
// PushConf, _ = config.LoadConf("")
|
// PushConf, _ = config.LoadConf("")
|
||||||
logEntry := LogPushEntry{
|
logEntry := logx.LogPushEntry{
|
||||||
ID: "",
|
ID: "",
|
||||||
Type: "",
|
Type: "",
|
||||||
Platform: "",
|
Platform: "",
|
||||||
|
@ -29,7 +30,7 @@ func TestEmptyFeedbackURL(t *testing.T) {
|
||||||
func TestHTTPErrorInFeedbackCall(t *testing.T) {
|
func TestHTTPErrorInFeedbackCall(t *testing.T) {
|
||||||
config, _ := config.LoadConf("")
|
config, _ := config.LoadConf("")
|
||||||
config.Core.FeedbackURL = "http://test.example.com/api/"
|
config.Core.FeedbackURL = "http://test.example.com/api/"
|
||||||
logEntry := LogPushEntry{
|
logEntry := logx.LogPushEntry{
|
||||||
ID: "",
|
ID: "",
|
||||||
Type: "",
|
Type: "",
|
||||||
Platform: "",
|
Platform: "",
|
||||||
|
@ -60,7 +61,7 @@ func TestSuccessfulFeedbackCall(t *testing.T) {
|
||||||
|
|
||||||
config, _ := config.LoadConf("")
|
config, _ := config.LoadConf("")
|
||||||
config.Core.FeedbackURL = httpMock.URL
|
config.Core.FeedbackURL = httpMock.URL
|
||||||
logEntry := LogPushEntry{
|
logEntry := logx.LogPushEntry{
|
||||||
ID: "",
|
ID: "",
|
||||||
Type: "",
|
Type: "",
|
||||||
Platform: "",
|
Platform: "",
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"github.com/appleboy/go-fcm"
|
"github.com/appleboy/go-fcm"
|
||||||
"github.com/msalihkarakasli/go-hms-push/push/core"
|
"github.com/msalihkarakasli/go-hms-push/push/core"
|
||||||
"github.com/sideshow/apns2"
|
"github.com/sideshow/apns2"
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -21,10 +20,6 @@ var (
|
||||||
FCMClient *fcm.Client
|
FCMClient *fcm.Client
|
||||||
// HMSClient is Huawei push client
|
// HMSClient is Huawei push client
|
||||||
HMSClient *core.HMSClient
|
HMSClient *core.HMSClient
|
||||||
// LogAccess is log server request log
|
|
||||||
LogAccess *logrus.Logger
|
|
||||||
// LogError is log server error log
|
|
||||||
LogError *logrus.Logger
|
|
||||||
// StatStorage implements the storage interface
|
// StatStorage implements the storage interface
|
||||||
StatStorage storage.Storage
|
StatStorage storage.Storage
|
||||||
// MaxConcurrentIOSPushes pool to limit the number of concurrent iOS pushes
|
// MaxConcurrentIOSPushes pool to limit the number of concurrent iOS pushes
|
||||||
|
|
|
@ -7,11 +7,17 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/appleboy/gorush/config"
|
"github.com/appleboy/gorush/config"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
PushConf, _ = config.LoadConf("")
|
PushConf, _ = config.LoadConf("")
|
||||||
if err := InitLog(); err != nil {
|
if err := logx.InitLog(
|
||||||
|
PushConf.Log.AccessLevel,
|
||||||
|
PushConf.Log.AccessLog,
|
||||||
|
PushConf.Log.ErrorLevel,
|
||||||
|
PushConf.Log.ErrorLog,
|
||||||
|
); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/appleboy/go-fcm"
|
"github.com/appleboy/go-fcm"
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
"github.com/msalihkarakasli/go-hms-push/push/model"
|
"github.com/msalihkarakasli/go-hms-push/push/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -53,7 +55,7 @@ type RequestPush struct {
|
||||||
// PushNotification is single notification request
|
// PushNotification is single notification request
|
||||||
type PushNotification struct {
|
type PushNotification struct {
|
||||||
wg *sync.WaitGroup
|
wg *sync.WaitGroup
|
||||||
log *[]LogPushEntry
|
log *[]logx.LogPushEntry
|
||||||
|
|
||||||
// Common
|
// Common
|
||||||
ID string `json:"notif_id,omitempty"`
|
ID string `json:"notif_id,omitempty"`
|
||||||
|
@ -123,7 +125,7 @@ func (p *PushNotification) AddWaitCount() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddLog record fail log of notification
|
// AddLog record fail log of notification
|
||||||
func (p *PushNotification) AddLog(log LogPushEntry) {
|
func (p *PushNotification) AddLog(log logx.LogPushEntry) {
|
||||||
if p.log != nil {
|
if p.log != nil {
|
||||||
*p.log = append(*p.log, log)
|
*p.log = append(*p.log, log)
|
||||||
}
|
}
|
||||||
|
@ -132,11 +134,11 @@ func (p *PushNotification) AddLog(log LogPushEntry) {
|
||||||
// IsTopic check if message format is topic for FCM
|
// IsTopic check if message format is topic for FCM
|
||||||
// ref: https://firebase.google.com/docs/cloud-messaging/send-message#topic-http-post-request
|
// ref: https://firebase.google.com/docs/cloud-messaging/send-message#topic-http-post-request
|
||||||
func (p *PushNotification) IsTopic() bool {
|
func (p *PushNotification) IsTopic() bool {
|
||||||
if p.Platform == PlatFormAndroid {
|
if p.Platform == core.PlatFormAndroid {
|
||||||
return p.To != "" && strings.HasPrefix(p.To, "/topics/") || p.Condition != ""
|
return p.To != "" && strings.HasPrefix(p.To, "/topics/") || p.Condition != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Platform == PlatFormHuawei {
|
if p.Platform == core.PlatFormHuawei {
|
||||||
return p.Topic != "" || p.Condition != ""
|
return p.Topic != "" || p.Condition != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,33 +152,33 @@ func CheckMessage(req PushNotification) error {
|
||||||
// ignore send topic mesaage from FCM
|
// ignore send topic mesaage from FCM
|
||||||
if !req.IsTopic() && len(req.Tokens) == 0 && req.To == "" {
|
if !req.IsTopic() && len(req.Tokens) == 0 && req.To == "" {
|
||||||
msg = "the message must specify at least one registration ID"
|
msg = "the message must specify at least one registration ID"
|
||||||
LogAccess.Debug(msg)
|
logx.LogAccess.Debug(msg)
|
||||||
return errors.New(msg)
|
return errors.New(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(req.Tokens) == PlatFormIos && req.Tokens[0] == "" {
|
if len(req.Tokens) == core.PlatFormIos && req.Tokens[0] == "" {
|
||||||
msg = "the token must not be empty"
|
msg = "the token must not be empty"
|
||||||
LogAccess.Debug(msg)
|
logx.LogAccess.Debug(msg)
|
||||||
return errors.New(msg)
|
return errors.New(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Platform == PlatFormAndroid && len(req.Tokens) > 1000 {
|
if req.Platform == core.PlatFormAndroid && len(req.Tokens) > 1000 {
|
||||||
msg = "the message may specify at most 1000 registration IDs"
|
msg = "the message may specify at most 1000 registration IDs"
|
||||||
LogAccess.Debug(msg)
|
logx.LogAccess.Debug(msg)
|
||||||
return errors.New(msg)
|
return errors.New(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Platform == PlatFormHuawei && len(req.Tokens) > 500 {
|
if req.Platform == core.PlatFormHuawei && len(req.Tokens) > 500 {
|
||||||
msg = "the message may specify at most 500 registration IDs for Huawei"
|
msg = "the message may specify at most 500 registration IDs for Huawei"
|
||||||
LogAccess.Debug(msg)
|
logx.LogAccess.Debug(msg)
|
||||||
return errors.New(msg)
|
return errors.New(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref
|
// ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref
|
||||||
if req.Platform == PlatFormAndroid && req.TimeToLive != nil && *req.TimeToLive > uint(2419200) {
|
if req.Platform == core.PlatFormAndroid && req.TimeToLive != nil && *req.TimeToLive > uint(2419200) {
|
||||||
msg = "the message's TimeToLive field must be an integer " +
|
msg = "the message's TimeToLive field must be an integer " +
|
||||||
"between 0 and 2419200 (4 weeks)"
|
"between 0 and 2419200 (4 weeks)"
|
||||||
LogAccess.Debug(msg)
|
logx.LogAccess.Debug(msg)
|
||||||
return errors.New(msg)
|
return errors.New(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +193,7 @@ func SetProxy(proxy string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
http.DefaultTransport = &http.Transport{Proxy: http.ProxyURL(proxyURL)}
|
http.DefaultTransport = &http.Transport{Proxy: http.ProxyURL(proxyURL)}
|
||||||
LogAccess.Debug("Set http proxy as " + proxy)
|
logx.LogAccess.Debug("Set http proxy as " + proxy)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"github.com/sideshow/apns2"
|
"github.com/sideshow/apns2"
|
||||||
"github.com/sideshow/apns2/certificate"
|
"github.com/sideshow/apns2/certificate"
|
||||||
|
@ -68,7 +71,7 @@ func InitAPNSClient() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError.Error("Cert Error:", err.Error())
|
logx.LogError.Error("Cert Error:", err.Error())
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -76,7 +79,7 @@ func InitAPNSClient() error {
|
||||||
ext = "." + PushConf.Ios.KeyType
|
ext = "." + PushConf.Ios.KeyType
|
||||||
key, err := base64.StdEncoding.DecodeString(PushConf.Ios.KeyBase64)
|
key, err := base64.StdEncoding.DecodeString(PushConf.Ios.KeyBase64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError.Error("base64 decode error:", err.Error())
|
logx.LogError.Error("base64 decode error:", err.Error())
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -92,7 +95,7 @@ func InitAPNSClient() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError.Error("Cert Error:", err.Error())
|
logx.LogError.Error("Cert Error:", err.Error())
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -101,7 +104,7 @@ func InitAPNSClient() error {
|
||||||
if ext == ".p8" {
|
if ext == ".p8" {
|
||||||
if PushConf.Ios.KeyID == "" || PushConf.Ios.TeamID == "" {
|
if PushConf.Ios.KeyID == "" || PushConf.Ios.TeamID == "" {
|
||||||
msg := "You should provide ios.KeyID and ios.TeamID for P8 token"
|
msg := "You should provide ios.KeyID and ios.TeamID for P8 token"
|
||||||
LogError.Error(msg)
|
logx.LogError.Error(msg)
|
||||||
return errors.New(msg)
|
return errors.New(msg)
|
||||||
}
|
}
|
||||||
token := &token.Token{
|
token := &token.Token{
|
||||||
|
@ -122,7 +125,7 @@ func InitAPNSClient() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError.Error("Transport Error:", err.Error())
|
logx.LogError.Error("Transport Error:", err.Error())
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -378,7 +381,7 @@ func getApnsClient(req PushNotification) (client *apns2.Client) {
|
||||||
|
|
||||||
// PushToIOS provide send notification to APNs server.
|
// PushToIOS provide send notification to APNs server.
|
||||||
func PushToIOS(req PushNotification) {
|
func PushToIOS(req PushNotification) {
|
||||||
LogAccess.Debug("Start push notification for iOS")
|
logx.LogAccess.Debug("Start push notification for iOS")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
retryCount = 0
|
retryCount = 0
|
||||||
|
@ -412,17 +415,17 @@ Retry:
|
||||||
err = errors.New(res.Reason)
|
err = errors.New(res.Reason)
|
||||||
}
|
}
|
||||||
// apns server error
|
// apns server error
|
||||||
LogPush(FailedPush, token, req, err)
|
logPush(core.FailedPush, token, req, err)
|
||||||
|
|
||||||
if PushConf.Core.Sync {
|
if PushConf.Core.Sync {
|
||||||
req.AddLog(getLogPushEntry(FailedPush, token, req, err))
|
req.AddLog(createLogPushEntry(core.FailedPush, token, req, err))
|
||||||
} else if PushConf.Core.FeedbackURL != "" {
|
} else if PushConf.Core.FeedbackURL != "" {
|
||||||
go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) {
|
go func(logger *logrus.Logger, log logx.LogPushEntry, url string, timeout int64) {
|
||||||
err := DispatchFeedback(log, url, timeout)
|
err := DispatchFeedback(log, url, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
}
|
}
|
||||||
}(LogError, getLogPushEntry(FailedPush, token, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
|
}(logx.LogError, createLogPushEntry(core.FailedPush, token, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
StatStorage.AddIosError(1)
|
StatStorage.AddIosError(1)
|
||||||
|
@ -434,7 +437,7 @@ Retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
if res != nil && res.Sent() {
|
if res != nil && res.Sent() {
|
||||||
LogPush(SucceededPush, token, req, nil)
|
logPush(core.SucceededPush, token, req, nil)
|
||||||
StatStorage.AddIosSuccess(1)
|
StatStorage.AddIosSuccess(1)
|
||||||
}
|
}
|
||||||
// free push slot
|
// free push slot
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/appleboy/gorush/config"
|
"github.com/appleboy/gorush/config"
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
"github.com/buger/jsonparser"
|
"github.com/buger/jsonparser"
|
||||||
"github.com/sideshow/apns2"
|
"github.com/sideshow/apns2"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -583,13 +584,13 @@ func TestDisabledIosNotifications(t *testing.T) {
|
||||||
// ios
|
// ios
|
||||||
{
|
{
|
||||||
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
|
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
|
||||||
Platform: PlatFormIos,
|
Platform: core.PlatFormIos,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
},
|
},
|
||||||
// android
|
// android
|
||||||
{
|
{
|
||||||
Tokens: []string{androidToken, androidToken + "_"},
|
Tokens: []string{androidToken, androidToken + "_"},
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/appleboy/go-fcm"
|
"github.com/appleboy/go-fcm"
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -102,7 +104,7 @@ func GetAndroidNotification(req PushNotification) *fcm.Message {
|
||||||
|
|
||||||
// PushToAndroid provide send notification to Android server.
|
// PushToAndroid provide send notification to Android server.
|
||||||
func PushToAndroid(req PushNotification) {
|
func PushToAndroid(req PushNotification) {
|
||||||
LogAccess.Debug("Start push notification for Android")
|
logx.LogAccess.Debug("Start push notification for Android")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
client *fcm.Client
|
client *fcm.Client
|
||||||
|
@ -117,7 +119,7 @@ func PushToAndroid(req PushNotification) {
|
||||||
// check message
|
// check message
|
||||||
err := CheckMessage(req)
|
err := CheckMessage(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError.Error("request error: " + err.Error())
|
logx.LogError.Error("request error: " + err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,38 +134,38 @@ Retry:
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// FCM server error
|
// FCM server error
|
||||||
LogError.Error("FCM server error: " + err.Error())
|
logx.LogError.Error("FCM server error: " + err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := client.Send(notification)
|
res, err := client.Send(notification)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Send Message error
|
// Send Message error
|
||||||
LogError.Error("FCM server send message error: " + err.Error())
|
logx.LogError.Error("FCM server send message error: " + err.Error())
|
||||||
|
|
||||||
if req.IsTopic() {
|
if req.IsTopic() {
|
||||||
if PushConf.Core.Sync {
|
if PushConf.Core.Sync {
|
||||||
req.AddLog(getLogPushEntry(FailedPush, req.To, req, err))
|
req.AddLog(createLogPushEntry(core.FailedPush, req.To, req, err))
|
||||||
} else if PushConf.Core.FeedbackURL != "" {
|
} else if PushConf.Core.FeedbackURL != "" {
|
||||||
go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) {
|
go func(logger *logrus.Logger, log logx.LogPushEntry, url string, timeout int64) {
|
||||||
err := DispatchFeedback(log, url, timeout)
|
err := DispatchFeedback(log, url, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
}
|
}
|
||||||
}(LogError, getLogPushEntry(FailedPush, req.To, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
|
}(logx.LogError, createLogPushEntry(core.FailedPush, req.To, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
|
||||||
}
|
}
|
||||||
StatStorage.AddAndroidError(1)
|
StatStorage.AddAndroidError(1)
|
||||||
} else {
|
} else {
|
||||||
for _, token := range req.Tokens {
|
for _, token := range req.Tokens {
|
||||||
if PushConf.Core.Sync {
|
if PushConf.Core.Sync {
|
||||||
req.AddLog(getLogPushEntry(FailedPush, token, req, err))
|
req.AddLog(createLogPushEntry(core.FailedPush, token, req, err))
|
||||||
} else if PushConf.Core.FeedbackURL != "" {
|
} else if PushConf.Core.FeedbackURL != "" {
|
||||||
go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) {
|
go func(logger *logrus.Logger, log logx.LogPushEntry, url string, timeout int64) {
|
||||||
err := DispatchFeedback(log, url, timeout)
|
err := DispatchFeedback(log, url, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
}
|
}
|
||||||
}(LogError, getLogPushEntry(FailedPush, token, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
|
}(logx.LogError, createLogPushEntry(core.FailedPush, token, req, err), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatStorage.AddAndroidError(int64(len(req.Tokens)))
|
StatStorage.AddAndroidError(int64(len(req.Tokens)))
|
||||||
|
@ -172,7 +174,7 @@ Retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
if !req.IsTopic() {
|
if !req.IsTopic() {
|
||||||
LogAccess.Debug(fmt.Sprintf("Android Success count: %d, Failure count: %d", res.Success, res.Failure))
|
logx.LogAccess.Debug(fmt.Sprintf("Android Success count: %d, Failure count: %d", res.Success, res.Failure))
|
||||||
}
|
}
|
||||||
|
|
||||||
StatStorage.AddAndroidSuccess(int64(res.Success))
|
StatStorage.AddAndroidSuccess(int64(res.Success))
|
||||||
|
@ -195,21 +197,21 @@ Retry:
|
||||||
newTokens = append(newTokens, to)
|
newTokens = append(newTokens, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
LogPush(FailedPush, to, req, result.Error)
|
logPush(core.FailedPush, to, req, result.Error)
|
||||||
if PushConf.Core.Sync {
|
if PushConf.Core.Sync {
|
||||||
req.AddLog(getLogPushEntry(FailedPush, to, req, result.Error))
|
req.AddLog(createLogPushEntry(core.FailedPush, to, req, result.Error))
|
||||||
} else if PushConf.Core.FeedbackURL != "" {
|
} else if PushConf.Core.FeedbackURL != "" {
|
||||||
go func(logger *logrus.Logger, log LogPushEntry, url string, timeout int64) {
|
go func(logger *logrus.Logger, log logx.LogPushEntry, url string, timeout int64) {
|
||||||
err := DispatchFeedback(log, url, timeout)
|
err := DispatchFeedback(log, url, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
}
|
}
|
||||||
}(LogError, getLogPushEntry(FailedPush, to, req, result.Error), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
|
}(logx.LogError, createLogPushEntry(core.FailedPush, to, req, result.Error), PushConf.Core.FeedbackURL, PushConf.Core.FeedbackTimeout)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
LogPush(SucceededPush, to, req, nil)
|
logPush(core.SucceededPush, to, req, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// result from Send messages to topics
|
// result from Send messages to topics
|
||||||
|
@ -220,15 +222,15 @@ Retry:
|
||||||
} else {
|
} else {
|
||||||
to = req.Condition
|
to = req.Condition
|
||||||
}
|
}
|
||||||
LogAccess.Debug("Send Topic Message: ", to)
|
logx.LogAccess.Debug("Send Topic Message: ", to)
|
||||||
// Success
|
// Success
|
||||||
if res.MessageID != 0 {
|
if res.MessageID != 0 {
|
||||||
LogPush(SucceededPush, to, req, nil)
|
logPush(core.SucceededPush, to, req, nil)
|
||||||
} else {
|
} else {
|
||||||
// failure
|
// failure
|
||||||
LogPush(FailedPush, to, req, res.Error)
|
logPush(core.FailedPush, to, req, res.Error)
|
||||||
if PushConf.Core.Sync {
|
if PushConf.Core.Sync {
|
||||||
req.AddLog(getLogPushEntry(FailedPush, to, req, res.Error))
|
req.AddLog(createLogPushEntry(core.FailedPush, to, req, res.Error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,9 +239,9 @@ Retry:
|
||||||
if len(res.FailedRegistrationIDs) > 0 {
|
if len(res.FailedRegistrationIDs) > 0 {
|
||||||
newTokens = append(newTokens, res.FailedRegistrationIDs...)
|
newTokens = append(newTokens, res.FailedRegistrationIDs...)
|
||||||
|
|
||||||
LogPush(FailedPush, notification.To, req, errors.New("device group: partial success or all fails"))
|
logPush(core.FailedPush, notification.To, req, errors.New("device group: partial success or all fails"))
|
||||||
if PushConf.Core.Sync {
|
if PushConf.Core.Sync {
|
||||||
req.AddLog(getLogPushEntry(FailedPush, notification.To, req, errors.New("device group: partial success or all fails")))
|
req.AddLog(createLogPushEntry(core.FailedPush, notification.To, req, errors.New("device group: partial success or all fails")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,3 +253,29 @@ Retry:
|
||||||
goto Retry
|
goto Retry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createLogPushEntry(status, token string, req PushNotification, err error) logx.LogPushEntry {
|
||||||
|
return logx.GetLogPushEntry(&logx.InputLog{
|
||||||
|
ID: req.ID,
|
||||||
|
Status: status,
|
||||||
|
Token: token,
|
||||||
|
Message: req.Message,
|
||||||
|
Platform: req.Platform,
|
||||||
|
Error: err,
|
||||||
|
HideToken: PushConf.Log.HideToken,
|
||||||
|
Format: PushConf.Log.Format,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func logPush(status, token string, req PushNotification, err error) {
|
||||||
|
logx.LogPush(&logx.InputLog{
|
||||||
|
ID: req.ID,
|
||||||
|
Status: status,
|
||||||
|
Token: token,
|
||||||
|
Message: req.Message,
|
||||||
|
Platform: req.Platform,
|
||||||
|
Error: err,
|
||||||
|
HideToken: PushConf.Log.HideToken,
|
||||||
|
Format: PushConf.Log.Format,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -4,8 +4,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/appleboy/go-fcm"
|
|
||||||
"github.com/appleboy/gorush/config"
|
"github.com/appleboy/gorush/config"
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
|
|
||||||
|
"github.com/appleboy/go-fcm"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,7 +40,7 @@ func TestPushToAndroidWrongToken(t *testing.T) {
|
||||||
|
|
||||||
req := PushNotification{
|
req := PushNotification{
|
||||||
Tokens: []string{"aaaaaa", "bbbbb"},
|
Tokens: []string{"aaaaaa", "bbbbb"},
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +60,7 @@ func TestPushToAndroidRightTokenForJSONLog(t *testing.T) {
|
||||||
|
|
||||||
req := PushNotification{
|
req := PushNotification{
|
||||||
Tokens: []string{androidToken},
|
Tokens: []string{androidToken},
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +77,7 @@ func TestPushToAndroidRightTokenForStringLog(t *testing.T) {
|
||||||
|
|
||||||
req := PushNotification{
|
req := PushNotification{
|
||||||
Tokens: []string{androidToken},
|
Tokens: []string{androidToken},
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,12 +95,12 @@ func TestOverwriteAndroidAPIKey(t *testing.T) {
|
||||||
|
|
||||||
req := PushNotification{
|
req := PushNotification{
|
||||||
Tokens: []string{androidToken, "bbbbb"},
|
Tokens: []string{androidToken, "bbbbb"},
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
// overwrite android api key
|
// overwrite android api key
|
||||||
APIKey: "1234",
|
APIKey: "1234",
|
||||||
|
|
||||||
log: &[]LogPushEntry{},
|
log: &[]logx.LogPushEntry{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// FCM server error: 401 error: 401 Unauthorized (Wrong API Key)
|
// FCM server error: 401 error: 401 Unauthorized (Wrong API Key)
|
||||||
|
@ -131,7 +134,7 @@ func TestFCMMessage(t *testing.T) {
|
||||||
// ignore check token length if send topic message
|
// ignore check token length if send topic message
|
||||||
req = PushNotification{
|
req = PushNotification{
|
||||||
Message: "Test",
|
Message: "Test",
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
To: "/topics/foo-bar",
|
To: "/topics/foo-bar",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +144,7 @@ func TestFCMMessage(t *testing.T) {
|
||||||
// "condition": "'dogs' in topics || 'cats' in topics",
|
// "condition": "'dogs' in topics || 'cats' in topics",
|
||||||
req = PushNotification{
|
req = PushNotification{
|
||||||
Message: "Test",
|
Message: "Test",
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Condition: "'dogs' in topics || 'cats' in topics",
|
Condition: "'dogs' in topics || 'cats' in topics",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +154,7 @@ func TestFCMMessage(t *testing.T) {
|
||||||
// the message may specify at most 1000 registration IDs
|
// the message may specify at most 1000 registration IDs
|
||||||
req = PushNotification{
|
req = PushNotification{
|
||||||
Message: "Test",
|
Message: "Test",
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Tokens: make([]string, 1001),
|
Tokens: make([]string, 1001),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +166,7 @@ func TestFCMMessage(t *testing.T) {
|
||||||
timeToLive := uint(2419201)
|
timeToLive := uint(2419201)
|
||||||
req = PushNotification{
|
req = PushNotification{
|
||||||
Message: "Test",
|
Message: "Test",
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Tokens: []string{"XXXXXXXXX"},
|
Tokens: []string{"XXXXXXXXX"},
|
||||||
TimeToLive: &timeToLive,
|
TimeToLive: &timeToLive,
|
||||||
}
|
}
|
||||||
|
@ -175,7 +178,7 @@ func TestFCMMessage(t *testing.T) {
|
||||||
timeToLive = uint(86400)
|
timeToLive = uint(86400)
|
||||||
req = PushNotification{
|
req = PushNotification{
|
||||||
Message: "Test",
|
Message: "Test",
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Tokens: []string{"XXXXXXXXX"},
|
Tokens: []string{"XXXXXXXXX"},
|
||||||
TimeToLive: &timeToLive,
|
TimeToLive: &timeToLive,
|
||||||
}
|
}
|
||||||
|
@ -193,7 +196,7 @@ func TestCheckAndroidMessage(t *testing.T) {
|
||||||
timeToLive := uint(2419201)
|
timeToLive := uint(2419201)
|
||||||
req := PushNotification{
|
req := PushNotification{
|
||||||
Tokens: []string{"aaaaaa", "bbbbb"},
|
Tokens: []string{"aaaaaa", "bbbbb"},
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
TimeToLive: &timeToLive,
|
TimeToLive: &timeToLive,
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
|
|
||||||
"github.com/msalihkarakasli/go-hms-push/push/config"
|
"github.com/msalihkarakasli/go-hms-push/push/config"
|
||||||
"github.com/msalihkarakasli/go-hms-push/push/core"
|
"github.com/msalihkarakasli/go-hms-push/push/core"
|
||||||
"github.com/msalihkarakasli/go-hms-push/push/model"
|
"github.com/msalihkarakasli/go-hms-push/push/model"
|
||||||
|
@ -153,17 +155,17 @@ func GetHuaweiNotification(req PushNotification) (*model.MessageRequest, error)
|
||||||
|
|
||||||
b, err := json.Marshal(msgRequest)
|
b, err := json.Marshal(msgRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError.Error("Failed to marshal the default message! Error is " + err.Error())
|
logx.LogError.Error("Failed to marshal the default message! Error is " + err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
LogAccess.Debugf("Default message is %s", string(b))
|
logx.LogAccess.Debugf("Default message is %s", string(b))
|
||||||
return msgRequest, nil
|
return msgRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PushToHuawei provide send notification to Android server.
|
// PushToHuawei provide send notification to Android server.
|
||||||
func PushToHuawei(req PushNotification) bool {
|
func PushToHuawei(req PushNotification) bool {
|
||||||
LogAccess.Debug("Start push notification for Huawei")
|
logx.LogAccess.Debug("Start push notification for Huawei")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
client *core.HMSClient
|
client *core.HMSClient
|
||||||
|
@ -178,7 +180,7 @@ func PushToHuawei(req PushNotification) bool {
|
||||||
// check message
|
// check message
|
||||||
err := CheckMessage(req)
|
err := CheckMessage(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError.Error("request error: " + err.Error())
|
logx.LogError.Error("request error: " + err.Error())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,25 +193,25 @@ Retry:
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// HMS server error
|
// HMS server error
|
||||||
LogError.Error("HMS server error: " + err.Error())
|
logx.LogError.Error("HMS server error: " + err.Error())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := client.SendMessage(context.Background(), notification)
|
res, err := client.SendMessage(context.Background(), notification)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Send Message error
|
// Send Message error
|
||||||
LogError.Error("HMS server send message error: " + err.Error())
|
logx.LogError.Error("HMS server send message error: " + err.Error())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Huawei Push Send API does not support exact results for each token
|
// Huawei Push Send API does not support exact results for each token
|
||||||
if res.Code == "80000000" {
|
if res.Code == "80000000" {
|
||||||
StatStorage.AddHuaweiSuccess(int64(1))
|
StatStorage.AddHuaweiSuccess(int64(1))
|
||||||
LogAccess.Debug("Huwaei Send Notification is completed successfully!")
|
logx.LogAccess.Debug("Huwaei Send Notification is completed successfully!")
|
||||||
} else {
|
} else {
|
||||||
isError = true
|
isError = true
|
||||||
StatStorage.AddHuaweiError(int64(1))
|
StatStorage.AddHuaweiError(int64(1))
|
||||||
LogAccess.Debug("Huawei Send Notification is failed! Code: " + res.Code)
|
logx.LogAccess.Debug("Huawei Send Notification is failed! Code: " + res.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isError && retryCount < maxRetry {
|
if isError && retryCount < maxRetry {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/appleboy/gorush/config"
|
"github.com/appleboy/gorush/config"
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,13 +43,13 @@ func TestSenMultipleNotifications(t *testing.T) {
|
||||||
// ios
|
// ios
|
||||||
{
|
{
|
||||||
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
|
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
|
||||||
Platform: PlatFormIos,
|
Platform: core.PlatFormIos,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
},
|
},
|
||||||
// android
|
// android
|
||||||
{
|
{
|
||||||
Tokens: []string{androidToken, "bbbbb"},
|
Tokens: []string{androidToken, "bbbbb"},
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -78,13 +79,13 @@ func TestDisabledAndroidNotifications(t *testing.T) {
|
||||||
// ios
|
// ios
|
||||||
{
|
{
|
||||||
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
|
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
|
||||||
Platform: PlatFormIos,
|
Platform: core.PlatFormIos,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
},
|
},
|
||||||
// android
|
// android
|
||||||
{
|
{
|
||||||
Tokens: []string{androidToken, "bbbbb"},
|
Tokens: []string{androidToken, "bbbbb"},
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -117,13 +118,13 @@ func TestSyncModeForNotifications(t *testing.T) {
|
||||||
// ios
|
// ios
|
||||||
{
|
{
|
||||||
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
|
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
|
||||||
Platform: PlatFormIos,
|
Platform: core.PlatFormIos,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
},
|
},
|
||||||
// android
|
// android
|
||||||
{
|
{
|
||||||
Tokens: []string{androidToken, "bbbbb"},
|
Tokens: []string{androidToken, "bbbbb"},
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "Welcome",
|
Message: "Welcome",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -152,21 +153,21 @@ func TestSyncModeForTopicNotification(t *testing.T) {
|
||||||
// error:InvalidParameters
|
// error:InvalidParameters
|
||||||
// Check that the provided parameters have the right name and type.
|
// Check that the provided parameters have the right name and type.
|
||||||
To: "/topics/foo-bar@@@##",
|
To: "/topics/foo-bar@@@##",
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "This is a Firebase Cloud Messaging Topic Message!",
|
Message: "This is a Firebase Cloud Messaging Topic Message!",
|
||||||
},
|
},
|
||||||
// android
|
// android
|
||||||
{
|
{
|
||||||
// success
|
// success
|
||||||
To: "/topics/foo-bar",
|
To: "/topics/foo-bar",
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "This is a Firebase Cloud Messaging Topic Message!",
|
Message: "This is a Firebase Cloud Messaging Topic Message!",
|
||||||
},
|
},
|
||||||
// android
|
// android
|
||||||
{
|
{
|
||||||
// success
|
// success
|
||||||
Condition: "'dogs' in topics || 'cats' in topics",
|
Condition: "'dogs' in topics || 'cats' in topics",
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "This is a Firebase Cloud Messaging Topic Message!",
|
Message: "This is a Firebase Cloud Messaging Topic Message!",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -193,7 +194,7 @@ func TestSyncModeForDeviceGroupNotification(t *testing.T) {
|
||||||
// android
|
// android
|
||||||
{
|
{
|
||||||
To: "aUniqueKey",
|
To: "aUniqueKey",
|
||||||
Platform: PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: "This is a Firebase Cloud Messaging Device Group Message!",
|
Message: "This is a Firebase Cloud Messaging Device Group Message!",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,9 +8,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
api "github.com/appleboy/gin-status-api"
|
api "github.com/appleboy/gin-status-api"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
"github.com/gin-contrib/logger"
|
"github.com/gin-contrib/logger"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding"
|
||||||
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
@ -18,10 +20,13 @@ import (
|
||||||
"golang.org/x/crypto/acme/autocert"
|
"golang.org/x/crypto/acme/autocert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var isTerm bool
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Support metrics
|
// Support metrics
|
||||||
m := NewMetrics()
|
m := NewMetrics()
|
||||||
prometheus.MustRegister(m)
|
prometheus.MustRegister(m)
|
||||||
|
isTerm = isatty.IsTerminal(os.Stdout.Fd())
|
||||||
}
|
}
|
||||||
|
|
||||||
func abortWithError(c *gin.Context, code int, message string) {
|
func abortWithError(c *gin.Context, code int, message string) {
|
||||||
|
@ -54,21 +59,21 @@ func pushHandler(c *gin.Context) {
|
||||||
|
|
||||||
if err := c.ShouldBindWith(&form, binding.JSON); err != nil {
|
if err := c.ShouldBindWith(&form, binding.JSON); err != nil {
|
||||||
msg = "Missing notifications field."
|
msg = "Missing notifications field."
|
||||||
LogAccess.Debug(err)
|
logx.LogAccess.Debug(err)
|
||||||
abortWithError(c, http.StatusBadRequest, msg)
|
abortWithError(c, http.StatusBadRequest, msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(form.Notifications) == 0 {
|
if len(form.Notifications) == 0 {
|
||||||
msg = "Notifications field is empty."
|
msg = "Notifications field is empty."
|
||||||
LogAccess.Debug(msg)
|
logx.LogAccess.Debug(msg)
|
||||||
abortWithError(c, http.StatusBadRequest, msg)
|
abortWithError(c, http.StatusBadRequest, msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if int64(len(form.Notifications)) > PushConf.Core.MaxNotification {
|
if int64(len(form.Notifications)) > PushConf.Core.MaxNotification {
|
||||||
msg = fmt.Sprintf("Number of notifications(%d) over limit(%d)", len(form.Notifications), PushConf.Core.MaxNotification)
|
msg = fmt.Sprintf("Number of notifications(%d) over limit(%d)", len(form.Notifications), PushConf.Core.MaxNotification)
|
||||||
LogAccess.Debug(msg)
|
logx.LogAccess.Debug(msg)
|
||||||
abortWithError(c, http.StatusBadRequest, msg)
|
abortWithError(c, http.StatusBadRequest, msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,7 +20,7 @@ func RunHTTPServer(ctx context.Context, s ...*http.Server) (err error) {
|
||||||
var server *http.Server
|
var server *http.Server
|
||||||
|
|
||||||
if !PushConf.Core.Enabled {
|
if !PushConf.Core.Enabled {
|
||||||
LogAccess.Info("httpd server is disabled.")
|
logx.LogAccess.Info("httpd server is disabled.")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +33,7 @@ func RunHTTPServer(ctx context.Context, s ...*http.Server) (err error) {
|
||||||
server = s[0]
|
server = s[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
LogAccess.Info("HTTPD server is running on " + PushConf.Core.Port + " port.")
|
logx.LogAccess.Info("HTTPD server is running on " + PushConf.Core.Port + " port.")
|
||||||
if PushConf.Core.AutoTLS.Enabled {
|
if PushConf.Core.AutoTLS.Enabled {
|
||||||
return startServer(ctx, autoTLSServer())
|
return startServer(ctx, autoTLSServer())
|
||||||
} else if PushConf.Core.SSL {
|
} else if PushConf.Core.SSL {
|
||||||
|
@ -47,22 +49,22 @@ func RunHTTPServer(ctx context.Context, s ...*http.Server) (err error) {
|
||||||
if PushConf.Core.CertPath != "" && PushConf.Core.KeyPath != "" {
|
if PushConf.Core.CertPath != "" && PushConf.Core.KeyPath != "" {
|
||||||
config.Certificates[0], err = tls.LoadX509KeyPair(PushConf.Core.CertPath, PushConf.Core.KeyPath)
|
config.Certificates[0], err = tls.LoadX509KeyPair(PushConf.Core.CertPath, PushConf.Core.KeyPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError.Error("Failed to load https cert file: ", err)
|
logx.LogError.Error("Failed to load https cert file: ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if PushConf.Core.CertBase64 != "" && PushConf.Core.KeyBase64 != "" {
|
} else if PushConf.Core.CertBase64 != "" && PushConf.Core.KeyBase64 != "" {
|
||||||
cert, err := base64.StdEncoding.DecodeString(PushConf.Core.CertBase64)
|
cert, err := base64.StdEncoding.DecodeString(PushConf.Core.CertBase64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError.Error("base64 decode error:", err.Error())
|
logx.LogError.Error("base64 decode error:", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
key, err := base64.StdEncoding.DecodeString(PushConf.Core.KeyBase64)
|
key, err := base64.StdEncoding.DecodeString(PushConf.Core.KeyBase64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError.Error("base64 decode error:", err.Error())
|
logx.LogError.Error("base64 decode error:", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if config.Certificates[0], err = tls.X509KeyPair(cert, key); err != nil {
|
if config.Certificates[0], err = tls.X509KeyPair(cert, key); err != nil {
|
||||||
LogError.Error("tls key pair error:", err.Error())
|
logx.LogError.Error("tls key pair error:", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/appleboy/gorush/config"
|
"github.com/appleboy/gorush/config"
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
|
|
||||||
"github.com/appleboy/gofight/v2"
|
"github.com/appleboy/gofight/v2"
|
||||||
"github.com/buger/jsonparser"
|
"github.com/buger/jsonparser"
|
||||||
|
@ -279,7 +280,7 @@ func TestMutableContent(t *testing.T) {
|
||||||
"notifications": []gofight.D{
|
"notifications": []gofight.D{
|
||||||
{
|
{
|
||||||
"tokens": []string{"aaaaa", "bbbbb"},
|
"tokens": []string{"aaaaa", "bbbbb"},
|
||||||
"platform": PlatFormAndroid,
|
"platform": core.PlatFormAndroid,
|
||||||
"message": "Welcome",
|
"message": "Welcome",
|
||||||
"mutable_content": 1,
|
"mutable_content": 1,
|
||||||
"topic": "test",
|
"topic": "test",
|
||||||
|
@ -310,12 +311,12 @@ func TestOutOfRangeMaxNotifications(t *testing.T) {
|
||||||
"notifications": []gofight.D{
|
"notifications": []gofight.D{
|
||||||
{
|
{
|
||||||
"tokens": []string{"aaaaa", "bbbbb"},
|
"tokens": []string{"aaaaa", "bbbbb"},
|
||||||
"platform": PlatFormAndroid,
|
"platform": core.PlatFormAndroid,
|
||||||
"message": "Welcome",
|
"message": "Welcome",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tokens": []string{"aaaaa", "bbbbb"},
|
"tokens": []string{"aaaaa", "bbbbb"},
|
||||||
"platform": PlatFormAndroid,
|
"platform": core.PlatFormAndroid,
|
||||||
"message": "Welcome",
|
"message": "Welcome",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -341,7 +342,7 @@ func TestSuccessPushHandler(t *testing.T) {
|
||||||
"notifications": []gofight.D{
|
"notifications": []gofight.D{
|
||||||
{
|
{
|
||||||
"tokens": []string{androidToken, "bbbbb"},
|
"tokens": []string{androidToken, "bbbbb"},
|
||||||
"platform": PlatFormAndroid,
|
"platform": core.PlatFormAndroid,
|
||||||
"message": "Welcome",
|
"message": "Welcome",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
"github.com/appleboy/gorush/storage/badger"
|
"github.com/appleboy/gorush/storage/badger"
|
||||||
"github.com/appleboy/gorush/storage/boltdb"
|
"github.com/appleboy/gorush/storage/boltdb"
|
||||||
"github.com/appleboy/gorush/storage/buntdb"
|
"github.com/appleboy/gorush/storage/buntdb"
|
||||||
|
@ -49,7 +50,7 @@ type HuaweiStatus struct {
|
||||||
|
|
||||||
// InitAppStatus for initialize app status
|
// InitAppStatus for initialize app status
|
||||||
func InitAppStatus() error {
|
func InitAppStatus() error {
|
||||||
LogAccess.Info("Init App Status Engine as ", PushConf.Stat.Engine)
|
logx.LogAccess.Info("Init App Status Engine as ", PushConf.Stat.Engine)
|
||||||
switch PushConf.Stat.Engine {
|
switch PushConf.Stat.Engine {
|
||||||
case "memory":
|
case "memory":
|
||||||
StatStorage = memory.New()
|
StatStorage = memory.New()
|
||||||
|
@ -64,12 +65,12 @@ func InitAppStatus() error {
|
||||||
case "badger":
|
case "badger":
|
||||||
StatStorage = badger.New(PushConf)
|
StatStorage = badger.New(PushConf)
|
||||||
default:
|
default:
|
||||||
LogError.Error("storage error: can't find storage driver")
|
logx.LogError.Error("storage error: can't find storage driver")
|
||||||
return errors.New("can't find storage driver")
|
return errors.New("can't find storage driver")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := StatStorage.Init(); err != nil {
|
if err := StatStorage.Init(); err != nil {
|
||||||
LogError.Error("storage error: " + err.Error())
|
logx.LogError.Error("storage error: " + err.Error())
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,14 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitWorkers for initialize all workers.
|
// InitWorkers for initialize all workers.
|
||||||
func InitWorkers(ctx context.Context, wg *sync.WaitGroup, workerNum, queueNum int64) {
|
func InitWorkers(ctx context.Context, wg *sync.WaitGroup, workerNum, queueNum int64) {
|
||||||
LogAccess.Info("worker number is ", workerNum, ", queue number is ", queueNum)
|
logx.LogAccess.Info("worker number is ", workerNum, ", queue number is ", queueNum)
|
||||||
QueueNotification = make(chan PushNotification, queueNum)
|
QueueNotification = make(chan PushNotification, queueNum)
|
||||||
for i := int64(0); i < workerNum; i++ {
|
for i := int64(0); i < workerNum; i++ {
|
||||||
go startWorker(ctx, wg, i)
|
go startWorker(ctx, wg, i)
|
||||||
|
@ -22,11 +25,11 @@ func SendNotification(ctx context.Context, req PushNotification) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch req.Platform {
|
switch req.Platform {
|
||||||
case PlatFormIos:
|
case core.PlatFormIos:
|
||||||
PushToIOS(req)
|
PushToIOS(req)
|
||||||
case PlatFormAndroid:
|
case core.PlatFormAndroid:
|
||||||
PushToAndroid(req)
|
PushToAndroid(req)
|
||||||
case PlatFormHuawei:
|
case core.PlatFormHuawei:
|
||||||
PushToHuawei(req)
|
PushToHuawei(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,35 +39,44 @@ func startWorker(ctx context.Context, wg *sync.WaitGroup, num int64) {
|
||||||
for notification := range QueueNotification {
|
for notification := range QueueNotification {
|
||||||
SendNotification(ctx, notification)
|
SendNotification(ctx, notification)
|
||||||
}
|
}
|
||||||
LogAccess.Info("closed the worker num ", num)
|
logx.LogAccess.Info("closed the worker num ", num)
|
||||||
}
|
}
|
||||||
|
|
||||||
// markFailedNotification adds failure logs for all tokens in push notification
|
// markFailedNotification adds failure logs for all tokens in push notification
|
||||||
func markFailedNotification(notification *PushNotification, reason string) {
|
func markFailedNotification(notification *PushNotification, reason string) {
|
||||||
LogError.Error(reason)
|
logx.LogError.Error(reason)
|
||||||
for _, token := range notification.Tokens {
|
for _, token := range notification.Tokens {
|
||||||
notification.AddLog(getLogPushEntry(FailedPush, token, *notification, errors.New(reason)))
|
notification.AddLog(logx.GetLogPushEntry(&logx.InputLog{
|
||||||
|
ID: notification.ID,
|
||||||
|
Status: core.FailedPush,
|
||||||
|
Token: token,
|
||||||
|
Message: notification.Message,
|
||||||
|
Platform: notification.Platform,
|
||||||
|
Error: errors.New(reason),
|
||||||
|
HideToken: PushConf.Log.HideToken,
|
||||||
|
Format: PushConf.Log.Format,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
notification.WaitDone()
|
notification.WaitDone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// queueNotification add notification to queue list.
|
// queueNotification add notification to queue list.
|
||||||
func queueNotification(ctx context.Context, req RequestPush) (int, []LogPushEntry) {
|
func queueNotification(ctx context.Context, req RequestPush) (int, []logx.LogPushEntry) {
|
||||||
var count int
|
var count int
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
newNotification := []*PushNotification{}
|
newNotification := []*PushNotification{}
|
||||||
for i := range req.Notifications {
|
for i := range req.Notifications {
|
||||||
notification := &req.Notifications[i]
|
notification := &req.Notifications[i]
|
||||||
switch notification.Platform {
|
switch notification.Platform {
|
||||||
case PlatFormIos:
|
case core.PlatFormIos:
|
||||||
if !PushConf.Ios.Enabled {
|
if !PushConf.Ios.Enabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case PlatFormAndroid:
|
case core.PlatFormAndroid:
|
||||||
if !PushConf.Android.Enabled {
|
if !PushConf.Android.Enabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case PlatFormHuawei:
|
case core.PlatFormHuawei:
|
||||||
if !PushConf.Huawei.Enabled {
|
if !PushConf.Huawei.Enabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -72,7 +84,7 @@ func queueNotification(ctx context.Context, req RequestPush) (int, []LogPushEntr
|
||||||
newNotification = append(newNotification, notification)
|
newNotification = append(newNotification, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
log := make([]LogPushEntry, 0, count)
|
log := make([]logx.LogPushEntry, 0, count)
|
||||||
for _, notification := range newNotification {
|
for _, notification := range newNotification {
|
||||||
if PushConf.Core.Sync {
|
if PushConf.Core.Sync {
|
||||||
notification.wg = &wg
|
notification.wg = &wg
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package gorush
|
package logx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -7,6 +7,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
|
|
||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -38,8 +40,15 @@ func init() {
|
||||||
isTerm = isatty.IsTerminal(os.Stdout.Fd())
|
isTerm = isatty.IsTerminal(os.Stdout.Fd())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// LogAccess is log server request log
|
||||||
|
LogAccess *logrus.Logger
|
||||||
|
// LogError is log server error log
|
||||||
|
LogError *logrus.Logger
|
||||||
|
)
|
||||||
|
|
||||||
// InitLog use for initial log module
|
// InitLog use for initial log module
|
||||||
func InitLog() error {
|
func InitLog(accessLevel, accessLog, errorLevel, errorLog string) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// init logger
|
// init logger
|
||||||
|
@ -62,19 +71,19 @@ func InitLog() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set logger
|
// set logger
|
||||||
if err = SetLogLevel(LogAccess, PushConf.Log.AccessLevel); err != nil {
|
if err = SetLogLevel(LogAccess, accessLevel); err != nil {
|
||||||
return errors.New("Set access log level error: " + err.Error())
|
return errors.New("Set access log level error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = SetLogLevel(LogError, PushConf.Log.ErrorLevel); err != nil {
|
if err = SetLogLevel(LogError, errorLevel); err != nil {
|
||||||
return errors.New("Set error log level error: " + err.Error())
|
return errors.New("Set error log level error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = SetLogOut(LogAccess, PushConf.Log.AccessLog); err != nil {
|
if err = SetLogOut(LogAccess, accessLog); err != nil {
|
||||||
return errors.New("Set access log path error: " + err.Error())
|
return errors.New("Set access log path error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = SetLogOut(LogError, PushConf.Log.ErrorLog); err != nil {
|
if err = SetLogOut(LogError, errorLog); err != nil {
|
||||||
return errors.New("Set error log path error: " + err.Error())
|
return errors.New("Set error log path error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,11 +124,11 @@ func SetLogLevel(log *logrus.Logger, levelString string) error {
|
||||||
|
|
||||||
func colorForPlatForm(platform int) string {
|
func colorForPlatForm(platform int) string {
|
||||||
switch platform {
|
switch platform {
|
||||||
case PlatFormIos:
|
case core.PlatFormIos:
|
||||||
return blue
|
return blue
|
||||||
case PlatFormAndroid:
|
case core.PlatFormAndroid:
|
||||||
return yellow
|
return yellow
|
||||||
case PlatFormHuawei:
|
case core.PlatFormHuawei:
|
||||||
return green
|
return green
|
||||||
default:
|
default:
|
||||||
return reset
|
return reset
|
||||||
|
@ -128,11 +137,11 @@ func colorForPlatForm(platform int) string {
|
||||||
|
|
||||||
func typeForPlatForm(platform int) string {
|
func typeForPlatForm(platform int) string {
|
||||||
switch platform {
|
switch platform {
|
||||||
case PlatFormIos:
|
case core.PlatFormIos:
|
||||||
return "ios"
|
return "ios"
|
||||||
case PlatFormAndroid:
|
case core.PlatFormAndroid:
|
||||||
return "android"
|
return "android"
|
||||||
case PlatFormHuawei:
|
case core.PlatFormHuawei:
|
||||||
return "huawei"
|
return "huawei"
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
|
@ -157,48 +166,62 @@ func hideToken(token string, markLen int) string {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLogPushEntry(status, token string, req PushNotification, errPush error) LogPushEntry {
|
// GetLogPushEntry get push data into log structure
|
||||||
|
func GetLogPushEntry(input *InputLog) LogPushEntry {
|
||||||
var errMsg string
|
var errMsg string
|
||||||
|
var token string
|
||||||
|
|
||||||
plat := typeForPlatForm(req.Platform)
|
plat := typeForPlatForm(input.Platform)
|
||||||
|
|
||||||
if errPush != nil {
|
if input.Error != nil {
|
||||||
errMsg = errPush.Error()
|
errMsg = input.Error.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
if PushConf.Log.HideToken {
|
if input.HideToken {
|
||||||
token = hideToken(token, 10)
|
token = hideToken(input.Token, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
return LogPushEntry{
|
return LogPushEntry{
|
||||||
ID: req.ID,
|
ID: input.ID,
|
||||||
Type: status,
|
Type: input.Status,
|
||||||
Platform: plat,
|
Platform: plat,
|
||||||
Token: token,
|
Token: token,
|
||||||
Message: req.Message,
|
Message: input.Message,
|
||||||
Error: errMsg,
|
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.
|
// LogPush record user push request and server response.
|
||||||
func LogPush(status, token string, req PushNotification, errPush error) {
|
func LogPush(input *InputLog) {
|
||||||
var platColor, resetColor, output string
|
var platColor, resetColor, output string
|
||||||
|
|
||||||
if isTerm {
|
if isTerm {
|
||||||
platColor = colorForPlatForm(req.Platform)
|
platColor = colorForPlatForm(input.Platform)
|
||||||
resetColor = reset
|
resetColor = reset
|
||||||
}
|
}
|
||||||
|
|
||||||
log := getLogPushEntry(status, token, req, errPush)
|
log := GetLogPushEntry(input)
|
||||||
|
|
||||||
if PushConf.Log.Format == "json" {
|
if input.Format == "json" {
|
||||||
logJSON, _ := json.Marshal(log)
|
logJSON, _ := json.Marshal(log)
|
||||||
|
|
||||||
output = string(logJSON)
|
output = string(logJSON)
|
||||||
} else {
|
} else {
|
||||||
var typeColor string
|
var typeColor string
|
||||||
switch status {
|
switch input.Status {
|
||||||
case SucceededPush:
|
case core.SucceededPush:
|
||||||
if isTerm {
|
if isTerm {
|
||||||
typeColor = green
|
typeColor = green
|
||||||
}
|
}
|
||||||
|
@ -209,7 +232,7 @@ func LogPush(status, token string, req PushNotification, errPush error) {
|
||||||
log.Token,
|
log.Token,
|
||||||
log.Message,
|
log.Message,
|
||||||
)
|
)
|
||||||
case FailedPush:
|
case core.FailedPush:
|
||||||
if isTerm {
|
if isTerm {
|
||||||
typeColor = red
|
typeColor = red
|
||||||
}
|
}
|
||||||
|
@ -224,10 +247,10 @@ func LogPush(status, token string, req PushNotification, errPush error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch status {
|
switch input.Status {
|
||||||
case SucceededPush:
|
case core.SucceededPush:
|
||||||
LogAccess.Info(output)
|
LogAccess.Info(output)
|
||||||
case FailedPush:
|
case core.FailedPush:
|
||||||
LogError.Error(output)
|
LogError.Error(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
package gorush
|
package logx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/appleboy/gorush/config"
|
"github.com/appleboy/gorush/config"
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -36,57 +38,87 @@ func TestSetLogOut(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInitDefaultLog(t *testing.T) {
|
func TestInitDefaultLog(t *testing.T) {
|
||||||
PushConf, _ = config.LoadConf("")
|
PushConf, _ := config.LoadConf("")
|
||||||
|
|
||||||
// no errors on default config
|
// no errors on default config
|
||||||
assert.Nil(t, InitLog())
|
assert.Nil(t, InitLog(
|
||||||
|
PushConf.Log.AccessLevel,
|
||||||
|
PushConf.Log.AccessLog,
|
||||||
|
PushConf.Log.ErrorLevel,
|
||||||
|
PushConf.Log.ErrorLog,
|
||||||
|
))
|
||||||
|
|
||||||
PushConf.Log.AccessLevel = "invalid"
|
PushConf.Log.AccessLevel = "invalid"
|
||||||
|
|
||||||
assert.NotNil(t, InitLog())
|
assert.NotNil(t, InitLog(
|
||||||
|
PushConf.Log.AccessLevel,
|
||||||
|
PushConf.Log.AccessLog,
|
||||||
|
PushConf.Log.ErrorLevel,
|
||||||
|
PushConf.Log.ErrorLog,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessLevel(t *testing.T) {
|
func TestAccessLevel(t *testing.T) {
|
||||||
PushConf, _ = config.LoadConf("")
|
PushConf, _ := config.LoadConf("")
|
||||||
|
|
||||||
PushConf.Log.AccessLevel = "invalid"
|
PushConf.Log.AccessLevel = "invalid"
|
||||||
|
|
||||||
assert.NotNil(t, InitLog())
|
assert.NotNil(t, InitLog(
|
||||||
|
PushConf.Log.AccessLevel,
|
||||||
|
PushConf.Log.AccessLog,
|
||||||
|
PushConf.Log.ErrorLevel,
|
||||||
|
PushConf.Log.ErrorLog,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestErrorLevel(t *testing.T) {
|
func TestErrorLevel(t *testing.T) {
|
||||||
PushConf, _ = config.LoadConf("")
|
PushConf, _ := config.LoadConf("")
|
||||||
|
|
||||||
PushConf.Log.ErrorLevel = "invalid"
|
PushConf.Log.ErrorLevel = "invalid"
|
||||||
|
|
||||||
assert.NotNil(t, InitLog())
|
assert.NotNil(t, InitLog(
|
||||||
|
PushConf.Log.AccessLevel,
|
||||||
|
PushConf.Log.AccessLog,
|
||||||
|
PushConf.Log.ErrorLevel,
|
||||||
|
PushConf.Log.ErrorLog,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessLogPath(t *testing.T) {
|
func TestAccessLogPath(t *testing.T) {
|
||||||
PushConf, _ = config.LoadConf("")
|
PushConf, _ := config.LoadConf("")
|
||||||
|
|
||||||
PushConf.Log.AccessLog = "logs/access.log"
|
PushConf.Log.AccessLog = "logs/access.log"
|
||||||
|
|
||||||
assert.NotNil(t, InitLog())
|
assert.NotNil(t, InitLog(
|
||||||
|
PushConf.Log.AccessLevel,
|
||||||
|
PushConf.Log.AccessLog,
|
||||||
|
PushConf.Log.ErrorLevel,
|
||||||
|
PushConf.Log.ErrorLog,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestErrorLogPath(t *testing.T) {
|
func TestErrorLogPath(t *testing.T) {
|
||||||
PushConf, _ = config.LoadConf("")
|
PushConf, _ := config.LoadConf("")
|
||||||
|
|
||||||
PushConf.Log.ErrorLog = "logs/error.log"
|
PushConf.Log.ErrorLog = "logs/error.log"
|
||||||
|
|
||||||
assert.NotNil(t, InitLog())
|
assert.NotNil(t, InitLog(
|
||||||
|
PushConf.Log.AccessLevel,
|
||||||
|
PushConf.Log.AccessLog,
|
||||||
|
PushConf.Log.ErrorLevel,
|
||||||
|
PushConf.Log.ErrorLog,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPlatFormType(t *testing.T) {
|
func TestPlatFormType(t *testing.T) {
|
||||||
assert.Equal(t, "ios", typeForPlatForm(PlatFormIos))
|
assert.Equal(t, "ios", typeForPlatForm(core.PlatFormIos))
|
||||||
assert.Equal(t, "android", typeForPlatForm(PlatFormAndroid))
|
assert.Equal(t, "android", typeForPlatForm(core.PlatFormAndroid))
|
||||||
assert.Equal(t, "", typeForPlatForm(10000))
|
assert.Equal(t, "", typeForPlatForm(10000))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPlatFormColor(t *testing.T) {
|
func TestPlatFormColor(t *testing.T) {
|
||||||
assert.Equal(t, blue, colorForPlatForm(PlatFormIos))
|
assert.Equal(t, blue, colorForPlatForm(core.PlatFormIos))
|
||||||
assert.Equal(t, yellow, colorForPlatForm(PlatFormAndroid))
|
assert.Equal(t, yellow, colorForPlatForm(core.PlatFormAndroid))
|
||||||
assert.Equal(t, reset, colorForPlatForm(1000000))
|
assert.Equal(t, reset, colorForPlatForm(1000000))
|
||||||
}
|
}
|
||||||
|
|
47
main.go
47
main.go
|
@ -16,7 +16,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/appleboy/gorush/config"
|
"github.com/appleboy/gorush/config"
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
"github.com/appleboy/gorush/gorush"
|
"github.com/appleboy/gorush/gorush"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
"github.com/appleboy/gorush/rpc"
|
"github.com/appleboy/gorush/rpc"
|
||||||
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
@ -158,7 +160,12 @@ func main() {
|
||||||
gorush.PushConf.Core.Address = opts.Core.Address
|
gorush.PushConf.Core.Address = opts.Core.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = gorush.InitLog(); err != nil {
|
if err = logx.InitLog(
|
||||||
|
gorush.PushConf.Log.AccessLevel,
|
||||||
|
gorush.PushConf.Log.AccessLog,
|
||||||
|
gorush.PushConf.Log.ErrorLevel,
|
||||||
|
gorush.PushConf.Log.ErrorLog,
|
||||||
|
); err != nil {
|
||||||
log.Fatalf("Can't load log module, error: %v", err)
|
log.Fatalf("Can't load log module, error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,13 +177,13 @@ func main() {
|
||||||
err = gorush.SetProxy(gorush.PushConf.Core.HTTPProxy)
|
err = gorush.SetProxy(gorush.PushConf.Core.HTTPProxy)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gorush.LogError.Fatalf("Set Proxy error: %v", err)
|
logx.LogError.Fatalf("Set Proxy error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ping {
|
if ping {
|
||||||
if err := pinger(); err != nil {
|
if err := pinger(); err != nil {
|
||||||
gorush.LogError.Warnf("ping server error: %v", err)
|
logx.LogError.Warnf("ping server error: %v", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -185,7 +192,7 @@ func main() {
|
||||||
if opts.Android.Enabled {
|
if opts.Android.Enabled {
|
||||||
gorush.PushConf.Android.Enabled = opts.Android.Enabled
|
gorush.PushConf.Android.Enabled = opts.Android.Enabled
|
||||||
req := gorush.PushNotification{
|
req := gorush.PushNotification{
|
||||||
Platform: gorush.PlatFormAndroid,
|
Platform: core.PlatFormAndroid,
|
||||||
Message: message,
|
Message: message,
|
||||||
Title: title,
|
Title: title,
|
||||||
}
|
}
|
||||||
|
@ -202,7 +209,7 @@ func main() {
|
||||||
|
|
||||||
err := gorush.CheckMessage(req)
|
err := gorush.CheckMessage(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gorush.LogError.Fatal(err)
|
logx.LogError.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gorush.InitAppStatus(); err != nil {
|
if err := gorush.InitAppStatus(); err != nil {
|
||||||
|
@ -218,7 +225,7 @@ func main() {
|
||||||
if opts.Huawei.Enabled {
|
if opts.Huawei.Enabled {
|
||||||
gorush.PushConf.Huawei.Enabled = opts.Huawei.Enabled
|
gorush.PushConf.Huawei.Enabled = opts.Huawei.Enabled
|
||||||
req := gorush.PushNotification{
|
req := gorush.PushNotification{
|
||||||
Platform: gorush.PlatFormHuawei,
|
Platform: core.PlatFormHuawei,
|
||||||
Message: message,
|
Message: message,
|
||||||
Title: title,
|
Title: title,
|
||||||
}
|
}
|
||||||
|
@ -235,7 +242,7 @@ func main() {
|
||||||
|
|
||||||
err := gorush.CheckMessage(req)
|
err := gorush.CheckMessage(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gorush.LogError.Fatal(err)
|
logx.LogError.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gorush.InitAppStatus(); err != nil {
|
if err := gorush.InitAppStatus(); err != nil {
|
||||||
|
@ -255,7 +262,7 @@ func main() {
|
||||||
|
|
||||||
gorush.PushConf.Ios.Enabled = opts.Ios.Enabled
|
gorush.PushConf.Ios.Enabled = opts.Ios.Enabled
|
||||||
req := gorush.PushNotification{
|
req := gorush.PushNotification{
|
||||||
Platform: gorush.PlatFormIos,
|
Platform: core.PlatFormIos,
|
||||||
Message: message,
|
Message: message,
|
||||||
Title: title,
|
Title: title,
|
||||||
}
|
}
|
||||||
|
@ -272,7 +279,7 @@ func main() {
|
||||||
|
|
||||||
err := gorush.CheckMessage(req)
|
err := gorush.CheckMessage(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gorush.LogError.Fatal(err)
|
logx.LogError.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gorush.InitAppStatus(); err != nil {
|
if err := gorush.InitAppStatus(); err != nil {
|
||||||
|
@ -288,7 +295,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = gorush.CheckPushConf(); err != nil {
|
if err = gorush.CheckPushConf(); err != nil {
|
||||||
gorush.LogError.Fatal(err)
|
logx.LogError.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Core.PID.Path != "" {
|
if opts.Core.PID.Path != "" {
|
||||||
|
@ -298,26 +305,26 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = createPIDFile(); err != nil {
|
if err = createPIDFile(); err != nil {
|
||||||
gorush.LogError.Fatal(err)
|
logx.LogError.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = gorush.InitAppStatus(); err != nil {
|
if err = gorush.InitAppStatus(); err != nil {
|
||||||
gorush.LogError.Fatal(err)
|
logx.LogError.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
finished := make(chan struct{})
|
finished := make(chan struct{})
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
wg.Add(int(gorush.PushConf.Core.WorkerNum))
|
wg.Add(int(gorush.PushConf.Core.WorkerNum))
|
||||||
ctx := withContextFunc(context.Background(), func() {
|
ctx := withContextFunc(context.Background(), func() {
|
||||||
gorush.LogAccess.Info("close the notification queue channel, current queue len: ", len(gorush.QueueNotification))
|
logx.LogAccess.Info("close the notification queue channel, current queue len: ", len(gorush.QueueNotification))
|
||||||
close(gorush.QueueNotification)
|
close(gorush.QueueNotification)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
gorush.LogAccess.Info("the notification queue has been clear")
|
logx.LogAccess.Info("the notification queue has been clear")
|
||||||
close(finished)
|
close(finished)
|
||||||
// close the connection with storage
|
// close the connection with storage
|
||||||
gorush.LogAccess.Info("close the storage connection: ", gorush.PushConf.Stat.Engine)
|
logx.LogAccess.Info("close the storage connection: ", gorush.PushConf.Stat.Engine)
|
||||||
if err := gorush.StatStorage.Close(); err != nil {
|
if err := gorush.StatStorage.Close(); err != nil {
|
||||||
gorush.LogError.Fatal("can't close the storage connection: ", err.Error())
|
logx.LogError.Fatal("can't close the storage connection: ", err.Error())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -325,19 +332,19 @@ func main() {
|
||||||
|
|
||||||
if gorush.PushConf.Ios.Enabled {
|
if gorush.PushConf.Ios.Enabled {
|
||||||
if err = gorush.InitAPNSClient(); err != nil {
|
if err = gorush.InitAPNSClient(); err != nil {
|
||||||
gorush.LogError.Fatal(err)
|
logx.LogError.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if gorush.PushConf.Android.Enabled {
|
if gorush.PushConf.Android.Enabled {
|
||||||
if _, err = gorush.InitFCMClient(gorush.PushConf.Android.APIKey); err != nil {
|
if _, err = gorush.InitFCMClient(gorush.PushConf.Android.APIKey); err != nil {
|
||||||
gorush.LogError.Fatal(err)
|
logx.LogError.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if gorush.PushConf.Huawei.Enabled {
|
if gorush.PushConf.Huawei.Enabled {
|
||||||
if _, err = gorush.InitHMSClient(gorush.PushConf.Huawei.AppSecret, gorush.PushConf.Huawei.AppID); err != nil {
|
if _, err = gorush.InitHMSClient(gorush.PushConf.Huawei.AppSecret, gorush.PushConf.Huawei.AppID); err != nil {
|
||||||
gorush.LogError.Fatal(err)
|
logx.LogError.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,7 +369,7 @@ func main() {
|
||||||
})
|
})
|
||||||
|
|
||||||
if err = g.Wait(); err != nil {
|
if err = g.Wait(); err != nil {
|
||||||
gorush.LogError.Fatal(err)
|
logx.LogError.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/appleboy/gorush/core"
|
||||||
"github.com/appleboy/gorush/gorush"
|
"github.com/appleboy/gorush/gorush"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
"github.com/appleboy/gorush/rpc/proto"
|
"github.com/appleboy/gorush/rpc/proto"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
@ -70,7 +72,7 @@ func (s *Server) Send(ctx context.Context, in *proto.NotificationRequest) (*prot
|
||||||
notification.Badge = &badge
|
notification.Badge = &badge
|
||||||
}
|
}
|
||||||
|
|
||||||
if in.Topic != "" && in.Platform == gorush.PlatFormAndroid {
|
if in.Topic != "" && in.Platform == core.PlatFormAndroid {
|
||||||
notification.To = in.Topic
|
notification.To = in.Topic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +109,7 @@ func (s *Server) Send(ctx context.Context, in *proto.NotificationRequest) (*prot
|
||||||
// RunGRPCServer run gorush grpc server
|
// RunGRPCServer run gorush grpc server
|
||||||
func RunGRPCServer(ctx context.Context) error {
|
func RunGRPCServer(ctx context.Context) error {
|
||||||
if !gorush.PushConf.GRPC.Enabled {
|
if !gorush.PushConf.GRPC.Enabled {
|
||||||
gorush.LogAccess.Info("gRPC server is disabled.")
|
logx.LogAccess.Info("gRPC server is disabled.")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,19 +123,19 @@ func RunGRPCServer(ctx context.Context) error {
|
||||||
|
|
||||||
lis, err := net.Listen("tcp", ":"+gorush.PushConf.GRPC.Port)
|
lis, err := net.Listen("tcp", ":"+gorush.PushConf.GRPC.Port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gorush.LogError.Fatalln(err)
|
logx.LogError.Fatalln(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
gorush.LogAccess.Info("gRPC server is running on " + gorush.PushConf.GRPC.Port + " port.")
|
logx.LogAccess.Info("gRPC server is running on " + gorush.PushConf.GRPC.Port + " port.")
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
s.GracefulStop() // graceful shutdown
|
s.GracefulStop() // graceful shutdown
|
||||||
gorush.LogAccess.Info("shutdown the gRPC server")
|
logx.LogAccess.Info("shutdown the gRPC server")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err = s.Serve(lis); err != nil {
|
if err = s.Serve(lis); err != nil {
|
||||||
gorush.LogError.Fatalln(err)
|
logx.LogError.Fatalln(err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/appleboy/gorush/gorush"
|
"github.com/appleboy/gorush/gorush"
|
||||||
|
"github.com/appleboy/gorush/logx"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
|
@ -14,7 +15,12 @@ const gRPCAddr = "localhost:9000"
|
||||||
|
|
||||||
func TestGracefulShutDownGRPCServer(t *testing.T) {
|
func TestGracefulShutDownGRPCServer(t *testing.T) {
|
||||||
// server configs
|
// server configs
|
||||||
gorush.InitLog()
|
logx.InitLog(
|
||||||
|
gorush.PushConf.Log.AccessLevel,
|
||||||
|
gorush.PushConf.Log.AccessLog,
|
||||||
|
gorush.PushConf.Log.ErrorLevel,
|
||||||
|
gorush.PushConf.Log.ErrorLog,
|
||||||
|
)
|
||||||
gorush.PushConf.GRPC.Enabled = true
|
gorush.PushConf.GRPC.Enabled = true
|
||||||
gorush.PushConf.GRPC.Port = "9000"
|
gorush.PushConf.GRPC.Port = "9000"
|
||||||
gorush.PushConf.Log.Format = "json"
|
gorush.PushConf.Log.Format = "json"
|
||||||
|
|
Loading…
Reference in New Issue