Merge pull request #62 from appleboy/redis
Fixed #61 Support redis engine
This commit is contained in:
commit
f14d42d9a8
|
@ -3,14 +3,15 @@ sudo: required
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.6.1
|
||||
- 1.6.2
|
||||
- tip
|
||||
|
||||
services:
|
||||
- docker
|
||||
- redis
|
||||
|
||||
env:
|
||||
global:
|
||||
|
|
|
@ -21,6 +21,7 @@ A push notification server using [Gin](https://github.com/gin-gonic/gin) framewo
|
|||
* Support notification queue and multiple workers.
|
||||
* Support `/api/stat/app` show notification success and failure counts.
|
||||
* Support `/api/config` show your yml config.
|
||||
* Support store app stat to [redis](http://redis.io/) or memory.
|
||||
|
||||
See the [YAML config example](config/config.yml):
|
||||
|
||||
|
@ -57,6 +58,13 @@ log:
|
|||
access_level: "debug"
|
||||
error_log: "stderr" # stderr: output to console, or define log path like "log/error_log"
|
||||
error_level: "error"
|
||||
|
||||
stat:
|
||||
engine: "memory" # support memory or redis
|
||||
redis:
|
||||
addr: "localhost:6379"
|
||||
password: ""
|
||||
db: 0
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
|
|
@ -30,3 +30,10 @@ log:
|
|||
access_level: "debug"
|
||||
error_log: "stderr"
|
||||
error_level: "error"
|
||||
|
||||
stat:
|
||||
engine: "memory"
|
||||
redis:
|
||||
addr: "localhost:6379"
|
||||
password: ""
|
||||
db: 0
|
||||
|
|
|
@ -7,6 +7,6 @@ RUN mkdir -p /tmp/build
|
|||
Add build.tar.gz /tmp/build/
|
||||
WORKDIR /tmp/build
|
||||
RUN go get -v -d
|
||||
RUN GOOS=linux GOARCH=amd64 go build -ldflags="-w" -o bin/gorush gorush.go
|
||||
RUN GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o bin/gorush gorush.go
|
||||
|
||||
CMD tar -C bin -czf - gorush
|
||||
|
|
|
@ -13,6 +13,7 @@ type ConfYaml struct {
|
|||
Android SectionAndroid `yaml:"android"`
|
||||
Ios SectionIos `yaml:"ios"`
|
||||
Log SectionLog `yaml:"log"`
|
||||
Stat SectionStat `yaml:stat`
|
||||
}
|
||||
|
||||
// SectionCore is sub seciont of config.
|
||||
|
@ -58,6 +59,19 @@ type SectionLog struct {
|
|||
ErrorLevel string `yaml:"error_level"`
|
||||
}
|
||||
|
||||
// SectionStat is sub seciont of config.
|
||||
type SectionStat struct {
|
||||
Engine string `yaml:"service"`
|
||||
Redis SectionRedis `yaml:"redis"`
|
||||
}
|
||||
|
||||
// SectionRedis is sub seciont of config.
|
||||
type SectionRedis struct {
|
||||
Addr string `yaml:"addr"`
|
||||
Password string `yaml:"password"`
|
||||
DB int64 `yaml:"db"`
|
||||
}
|
||||
|
||||
// BuildDefaultPushConf is default config setting.
|
||||
func BuildDefaultPushConf() ConfYaml {
|
||||
var conf ConfYaml
|
||||
|
@ -95,6 +109,11 @@ func BuildDefaultPushConf() ConfYaml {
|
|||
conf.Log.ErrorLog = "stderr"
|
||||
conf.Log.ErrorLevel = "error"
|
||||
|
||||
conf.Stat.Engine = "memory"
|
||||
conf.Stat.Redis.Addr = "localhost:6379"
|
||||
conf.Stat.Redis.Password = ""
|
||||
conf.Stat.Redis.DB = 0
|
||||
|
||||
return conf
|
||||
}
|
||||
|
||||
|
|
|
@ -18,3 +18,12 @@ const (
|
|||
// FailedPush is log block
|
||||
FailedPush = "failed-push"
|
||||
)
|
||||
|
||||
// Stat variable for redis
|
||||
const (
|
||||
gorushTotalCount = "gorush-total-count"
|
||||
gorushIosSuccess = "gorush-ios-success-count"
|
||||
gorushIosError = "gorush-ios-error-count"
|
||||
gorushAndroidSuccess = "gorush-android-success-count"
|
||||
gorushAndroidError = "gorush-android-error-count"
|
||||
)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"crypto/tls"
|
||||
"github.com/Sirupsen/logrus"
|
||||
apns "github.com/sideshow/apns2"
|
||||
"gopkg.in/redis.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -21,4 +22,6 @@ var (
|
|||
LogError *logrus.Logger
|
||||
// RushStatus is notification status
|
||||
RushStatus StatusApp
|
||||
// RedisClient is global variable for redis
|
||||
RedisClient *redis.Client
|
||||
)
|
||||
|
|
176
gorush/status.go
176
gorush/status.go
|
@ -2,7 +2,9 @@ package gorush
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"gopkg.in/redis.v3"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
|
@ -27,8 +29,14 @@ type IosStatus struct {
|
|||
PushError int64 `json:"push_error"`
|
||||
}
|
||||
|
||||
// InitAppStatus for initialize app status
|
||||
func InitAppStatus() {
|
||||
func getRedisInt64Result(key string) int64 {
|
||||
val, _ := RedisClient.Get(key).Result()
|
||||
count, _ := strconv.ParseInt(val, 10, 64)
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func initApp() {
|
||||
RushStatus.TotalCount = 0
|
||||
RushStatus.Ios.PushSuccess = 0
|
||||
RushStatus.Ios.PushError = 0
|
||||
|
@ -36,24 +44,168 @@ func InitAppStatus() {
|
|||
RushStatus.Android.PushError = 0
|
||||
}
|
||||
|
||||
func initRedis() error {
|
||||
RedisClient = redis.NewClient(&redis.Options{
|
||||
Addr: PushConf.Stat.Redis.Addr,
|
||||
Password: PushConf.Stat.Redis.Password,
|
||||
DB: PushConf.Stat.Redis.DB,
|
||||
})
|
||||
|
||||
_, err := RedisClient.Ping().Result()
|
||||
|
||||
if err != nil {
|
||||
// redis server error
|
||||
LogError.Error("Can't connect redis server: " + err.Error())
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
RushStatus.TotalCount = getTotalCount()
|
||||
RushStatus.Ios.PushSuccess = getIosSuccess()
|
||||
RushStatus.Ios.PushError = getIosError()
|
||||
RushStatus.Android.PushSuccess = getAndroidSuccess()
|
||||
RushStatus.Android.PushError = getAndroidError()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitAppStatus for initialize app status
|
||||
func InitAppStatus() {
|
||||
switch PushConf.Stat.Engine {
|
||||
case "memory":
|
||||
initApp()
|
||||
case "redis":
|
||||
initRedis()
|
||||
default:
|
||||
initApp()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func addTotalCount(count int64) {
|
||||
atomic.AddInt64(&RushStatus.TotalCount, count)
|
||||
switch PushConf.Stat.Engine {
|
||||
case "memory":
|
||||
atomic.AddInt64(&RushStatus.TotalCount, count)
|
||||
case "redis":
|
||||
RedisClient.Set(gorushTotalCount, strconv.Itoa(int(count)), 0)
|
||||
default:
|
||||
atomic.AddInt64(&RushStatus.TotalCount, count)
|
||||
}
|
||||
}
|
||||
|
||||
func addIosSuccess(count int64) {
|
||||
atomic.AddInt64(&RushStatus.Ios.PushSuccess, count)
|
||||
switch PushConf.Stat.Engine {
|
||||
case "memory":
|
||||
atomic.AddInt64(&RushStatus.Ios.PushSuccess, count)
|
||||
case "redis":
|
||||
RedisClient.Set(gorushIosSuccess, strconv.Itoa(int(count)), 0)
|
||||
default:
|
||||
atomic.AddInt64(&RushStatus.Ios.PushSuccess, count)
|
||||
}
|
||||
}
|
||||
|
||||
func addIosError(count int64) {
|
||||
atomic.AddInt64(&RushStatus.Ios.PushError, count)
|
||||
switch PushConf.Stat.Engine {
|
||||
case "memory":
|
||||
atomic.AddInt64(&RushStatus.Ios.PushError, count)
|
||||
case "redis":
|
||||
RedisClient.Set(gorushIosError, strconv.Itoa(int(count)), 0)
|
||||
default:
|
||||
atomic.AddInt64(&RushStatus.Ios.PushError, count)
|
||||
}
|
||||
}
|
||||
|
||||
func addAndroidSuccess(count int64) {
|
||||
atomic.AddInt64(&RushStatus.Android.PushSuccess, count)
|
||||
switch PushConf.Stat.Engine {
|
||||
case "memory":
|
||||
atomic.AddInt64(&RushStatus.Android.PushSuccess, count)
|
||||
case "redis":
|
||||
|
||||
RedisClient.Set(gorushAndroidSuccess, strconv.Itoa(int(count)), 0)
|
||||
default:
|
||||
atomic.AddInt64(&RushStatus.Android.PushSuccess, count)
|
||||
}
|
||||
}
|
||||
|
||||
func addAndroidError(count int64) {
|
||||
atomic.AddInt64(&RushStatus.Android.PushError, count)
|
||||
switch PushConf.Stat.Engine {
|
||||
case "memory":
|
||||
atomic.AddInt64(&RushStatus.Android.PushError, count)
|
||||
case "redis":
|
||||
RedisClient.Set(gorushAndroidError, strconv.Itoa(int(count)), 0)
|
||||
default:
|
||||
atomic.AddInt64(&RushStatus.Android.PushError, count)
|
||||
}
|
||||
}
|
||||
|
||||
func getTotalCount() int64 {
|
||||
var count int64
|
||||
switch PushConf.Stat.Engine {
|
||||
case "memory":
|
||||
count = atomic.LoadInt64(&RushStatus.TotalCount)
|
||||
case "redis":
|
||||
count = getRedisInt64Result(gorushAndroidError)
|
||||
default:
|
||||
count = atomic.LoadInt64(&RushStatus.TotalCount)
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func getIosSuccess() int64 {
|
||||
var count int64
|
||||
switch PushConf.Stat.Engine {
|
||||
case "memory":
|
||||
count = atomic.LoadInt64(&RushStatus.Ios.PushSuccess)
|
||||
case "redis":
|
||||
count = getRedisInt64Result(gorushAndroidError)
|
||||
default:
|
||||
count = atomic.LoadInt64(&RushStatus.Ios.PushSuccess)
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func getIosError() int64 {
|
||||
var count int64
|
||||
switch PushConf.Stat.Engine {
|
||||
case "memory":
|
||||
count = atomic.LoadInt64(&RushStatus.Ios.PushError)
|
||||
case "redis":
|
||||
count = getRedisInt64Result(gorushAndroidError)
|
||||
default:
|
||||
count = atomic.LoadInt64(&RushStatus.Ios.PushError)
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func getAndroidSuccess() int64 {
|
||||
var count int64
|
||||
switch PushConf.Stat.Engine {
|
||||
case "memory":
|
||||
count = atomic.LoadInt64(&RushStatus.Android.PushSuccess)
|
||||
case "redis":
|
||||
count = getRedisInt64Result(gorushAndroidError)
|
||||
default:
|
||||
count = atomic.LoadInt64(&RushStatus.Android.PushSuccess)
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func getAndroidError() int64 {
|
||||
var count int64
|
||||
switch PushConf.Stat.Engine {
|
||||
case "memory":
|
||||
count = atomic.LoadInt64(&RushStatus.Android.PushError)
|
||||
case "redis":
|
||||
count = getRedisInt64Result(gorushAndroidError)
|
||||
default:
|
||||
count = atomic.LoadInt64(&RushStatus.Android.PushError)
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func appStatusHandler(c *gin.Context) {
|
||||
|
@ -61,11 +213,11 @@ func appStatusHandler(c *gin.Context) {
|
|||
|
||||
result.QueueMax = cap(QueueNotification)
|
||||
result.QueueUsage = len(QueueNotification)
|
||||
result.TotalCount = atomic.LoadInt64(&RushStatus.TotalCount)
|
||||
result.Ios.PushSuccess = atomic.LoadInt64(&RushStatus.Ios.PushSuccess)
|
||||
result.Ios.PushError = atomic.LoadInt64(&RushStatus.Ios.PushError)
|
||||
result.Android.PushSuccess = atomic.LoadInt64(&RushStatus.Android.PushSuccess)
|
||||
result.Android.PushError = atomic.LoadInt64(&RushStatus.Android.PushError)
|
||||
result.TotalCount = getTotalCount()
|
||||
result.Ios.PushSuccess = getIosSuccess()
|
||||
result.Ios.PushError = getIosError()
|
||||
result.Android.PushSuccess = getAndroidSuccess()
|
||||
result.Android.PushError = getAndroidError()
|
||||
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
|
|
@ -50,3 +50,66 @@ func TestAddAndroidError(t *testing.T) {
|
|||
|
||||
assert.Equal(t, int64(1000), val)
|
||||
}
|
||||
|
||||
func TestRedisServerSuccess(t *testing.T) {
|
||||
PushConf.Stat.Redis.Addr = "localhost:6379"
|
||||
|
||||
err := initRedis()
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestRedisServerError(t *testing.T) {
|
||||
PushConf.Stat.Redis.Addr = "localhost:6370"
|
||||
|
||||
err := initRedis()
|
||||
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestStatForRedisEngine(t *testing.T) {
|
||||
var val int64
|
||||
PushConf.Stat.Engine = "redis"
|
||||
PushConf.Stat.Redis.Addr = "localhost:6379"
|
||||
InitAppStatus()
|
||||
|
||||
addTotalCount(1000)
|
||||
addIosSuccess(1000)
|
||||
addIosError(1000)
|
||||
addAndroidSuccess(1000)
|
||||
addAndroidError(1000)
|
||||
|
||||
val = getTotalCount()
|
||||
assert.Equal(t, int64(1000), val)
|
||||
val = getIosSuccess()
|
||||
assert.Equal(t, int64(1000), val)
|
||||
val = getIosError()
|
||||
assert.Equal(t, int64(1000), val)
|
||||
val = getAndroidSuccess()
|
||||
assert.Equal(t, int64(1000), val)
|
||||
val = getAndroidError()
|
||||
assert.Equal(t, int64(1000), val)
|
||||
}
|
||||
|
||||
func TestDefaultEngine(t *testing.T) {
|
||||
var val int64
|
||||
PushConf.Stat.Engine = "test"
|
||||
InitAppStatus()
|
||||
|
||||
addTotalCount(1000)
|
||||
addIosSuccess(1000)
|
||||
addIosError(1000)
|
||||
addAndroidSuccess(1000)
|
||||
addAndroidError(1000)
|
||||
|
||||
val = getTotalCount()
|
||||
assert.Equal(t, int64(1000), val)
|
||||
val = getIosSuccess()
|
||||
assert.Equal(t, int64(1000), val)
|
||||
val = getIosError()
|
||||
assert.Equal(t, int64(1000), val)
|
||||
val = getAndroidSuccess()
|
||||
assert.Equal(t, int64(1000), val)
|
||||
val = getAndroidError()
|
||||
assert.Equal(t, int64(1000), val)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue