creat gopush folder and move all go file from root folder.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
This commit is contained in:
Bo-Yi Wu
2016-03-27 00:09:43 +08:00
parent 0fe1c4cec3
commit 81826ac10c
6 changed files with 0 additions and 0 deletions

81
gorush/config.go Normal file
View File

@@ -0,0 +1,81 @@
package main
import (
"gopkg.in/yaml.v2"
"io/ioutil"
"log"
)
type ConfYaml struct {
Core SectionCore `yaml:"core"`
Api SectionApi `yaml:"api"`
Android SectionAndroid `yaml:"android"`
Ios SectionIos `yaml:"ios"`
}
type SectionCore struct {
Port string `yaml:"port"`
NotificationMax int `yaml:"notification_max"`
}
type SectionApi struct {
PushUri string `yaml:"push_uri"`
StatGoUri string `yaml:"stat_go_uri"`
}
type SectionAndroid struct {
Enabled bool `yaml:"enabled"`
ApiKey string `yaml:"apikey"`
}
type SectionIos struct {
Enabled bool `yaml:"enabled"`
PemCertPath string `yaml:"pem_cert_path"`
PemKeyPath string `yaml:"pem_key_path"`
Production bool `yaml:"production"`
}
func BuildDefaultPushConf() ConfYaml {
var conf ConfYaml
// Core
conf.Core.Port = "8088"
conf.Core.NotificationMax = 100
// Api
conf.Api.PushUri = "/api/push"
conf.Api.StatGoUri = "/api/status"
// Android
conf.Android.ApiKey = ""
conf.Android.Enabled = true
// iOS
conf.Ios.Enabled = true
conf.Ios.PemCertPath = ""
conf.Ios.PemKeyPath = ""
conf.Ios.Production = false
return conf
}
func LoadConfYaml(confPath string) (ConfYaml, error) {
var config ConfYaml
configFile, err := ioutil.ReadFile(confPath)
if err != nil {
log.Printf("Unable to read config file '%s'", confPath)
return config, err
}
err = yaml.Unmarshal([]byte(configFile), &config)
if err != nil {
log.Printf("Unable to read config file '%v'", err)
return config, err
}
return config, nil
}

10
gorush/const.go Normal file
View File

@@ -0,0 +1,10 @@
package main
const (
Version = "0.0.1"
)
const (
PlatFormIos = iota + 1
PlatFormAndroid
)

12
gorush/global.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import (
"crypto/tls"
apns "github.com/sideshow/apns2"
)
var (
PushConf ConfYaml
CertificatePemIos tls.Certificate
ApnsClient *apns.Client
)

248
gorush/notification.go Normal file
View File

@@ -0,0 +1,248 @@
package main
import (
"github.com/google/go-gcm"
apns "github.com/sideshow/apns2"
"github.com/sideshow/apns2/payload"
"log"
)
type ExtendJSON struct {
Key string `json:"key"`
Value string `json:"val"`
}
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"`
TitleLocArgs []string `json:"title-loc-args,omitempty"`
TitleLocKey string `json:"title-loc-key,omitempty"`
}
type RequestPushNotification struct {
// Common
Tokens []string `json:"tokens" binding:"required"`
Platform int `json:"platform" binding:"required"`
Message string `json:"message" binding:"required"`
Priority string `json:"priority,omitempty"`
ContentAvailable bool `json:"content_available,omitempty"`
// Android
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"`
Data gcm.Data `json:"data,omitempty"`
Notification gcm.Notification `json:"notification,omitempty"`
// iOS
ApnsID string `json:"apns_id,omitempty"`
Topic string `json:"topic,omitempty"`
Badge int `json:"badge,omitempty"`
Sound string `json:"sound,omitempty"`
Expiry int `json:"expiry,omitempty"`
Retry int `json:"retry,omitempty"`
Category string `json:"category,omitempty"`
URLArgs []string `json:"url-args,omitempty"`
Extend []ExtendJSON `json:"extend,omitempty"`
Alert alert `json:"alert,omitempty"`
// meta
IDs []uint64 `json:"seq_id,omitempty"`
}
func pushNotification(notification RequestPushNotification) bool {
var (
success bool
)
switch notification.Platform {
case PlatFormIos:
success = pushNotificationIos(notification)
case PlatFormAndroid:
success = pushNotificationAndroid(notification)
}
return success
}
func pushNotificationIos(req RequestPushNotification) bool {
for _, token := range req.Tokens {
notification := &apns.Notification{}
notification.DeviceToken = token
if len(req.ApnsID) > 0 {
notification.ApnsID = req.ApnsID
}
if len(req.Topic) > 0 {
notification.Topic = req.Topic
}
if len(req.Priority) > 0 && req.Priority == "normal" {
notification.Priority = apns.PriorityLow
}
payload := payload.NewPayload().Alert(req.Message)
if req.Badge > 0 {
payload.Badge(req.Badge)
}
if len(req.Sound) > 0 {
payload.Sound(req.Sound)
}
if req.ContentAvailable {
payload.ContentAvailable()
}
if len(req.Extend) > 0 {
for _, extend := range req.Extend {
payload.Custom(extend.Key, extend.Value)
}
}
// Alert dictionary
if len(req.Alert.Title) > 0 {
payload.AlertTitle(req.Alert.Title)
}
if len(req.Alert.TitleLocKey) > 0 {
payload.AlertTitleLocKey(req.Alert.TitleLocKey)
}
if len(req.Alert.LocArgs) > 0 {
payload.AlertTitleLocArgs(req.Alert.LocArgs)
}
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.URLArgs) > 0 {
payload.URLArgs(req.URLArgs)
}
notification.Payload = payload
// send ios notification
res, err := ApnsClient.Push(notification)
if err != nil {
log.Println("There was an error: ", err)
return false
}
if res.Sent() {
log.Println("APNs ID:", res.ApnsID)
return true
}
}
return true
}
func pushNotificationAndroid(req RequestPushNotification) bool {
// HTTP Connection Server Reference for Android
// https://developers.google.com/cloud-messaging/http-server-ref
notification := gcm.HttpMessage{}
notification.RegistrationIds = req.Tokens
if len(req.To) > 0 {
notification.To = req.To
}
if len(req.Priority) > 0 && req.Priority == "high" {
notification.Priority = "high"
}
if len(req.CollapseKey) > 0 {
notification.CollapseKey = req.CollapseKey
}
if req.ContentAvailable {
notification.ContentAvailable = true
}
if req.DelayWhileIdle {
notification.DelayWhileIdle = true
}
if req.TimeToLive > 0 {
notification.TimeToLive = req.TimeToLive
}
if len(req.RestrictedPackageName) > 0 {
notification.RestrictedPackageName = req.RestrictedPackageName
}
if req.DryRun {
notification.DryRun = true
}
if len(req.Data) > 0 {
notification.Data = req.Data
}
notification.Notification = &req.Notification
// Set request message if body is empty
if len(notification.Notification.Body) == 0 {
notification.Notification.Body = req.Message
}
res, err := gcm.SendHttp(PushConf.Android.ApiKey, notification)
if err != nil {
log.Println(err)
return false
}
if res.Error != "" {
log.Println("GCM Error Message: " + res.Error)
}
if res.Success > 0 {
log.Printf("Success count: %d, Failure count: %d", res.Success, res.Failure)
return true
}
return true
}

91
gorush/server.go Normal file
View File

@@ -0,0 +1,91 @@
package main
import (
api "github.com/appleboy/gin-status-api"
"github.com/fvbock/endless"
"github.com/gin-gonic/gin"
apns "github.com/sideshow/apns2"
"github.com/sideshow/apns2/certificate"
"log"
"net/http"
)
func AbortWithError(c *gin.Context, code int, message string) {
c.JSON(code, gin.H{
"code": code,
"message": message,
})
c.Abort()
}
func rootHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"text": "Welcome to golang push server.",
})
}
func pushHandler(c *gin.Context) {
var form RequestPushNotification
if err := c.BindJSON(&form); err != nil {
log.Println(err)
AbortWithError(c, http.StatusBadRequest, "Bad input request, please refer to README guide.")
return
}
// process notification.
pushNotification(form)
c.JSON(http.StatusOK, gin.H{
"text": "Welcome to golang push server.",
})
}
func GetMainEngine() *gin.Engine {
r := gin.New()
// Global middleware
r.Use(gin.Logger())
r.Use(gin.Recovery())
r.Use(VersionMiddleware())
r.GET(PushConf.Api.StatGoUri, api.StatusHandler)
r.POST(PushConf.Api.PushUri, pushHandler)
r.GET("/", rootHandler)
return r
}
func main() {
var err error
// set default parameters.
PushConf = BuildDefaultPushConf()
// load user define config.
PushConf, err = LoadConfYaml("config.yaml")
if err != nil {
log.Printf("Unable to load config file: '%v'", err)
return
}
if PushConf.Ios.Enabled {
CertificatePemIos, err = certificate.FromPemFile(PushConf.Ios.PemKeyPath, "")
if err != nil {
log.Println("Cert Error:", err)
return
}
if PushConf.Ios.Production {
ApnsClient = apns.NewClient(CertificatePemIos).Production()
} else {
ApnsClient = apns.NewClient(CertificatePemIos).Development()
}
}
endless.ListenAndServe(":"+PushConf.Core.Port, GetMainEngine())
}

22
gorush/version.go Normal file
View File

@@ -0,0 +1,22 @@
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"runtime"
)
func PrintGoPushVersion() {
fmt.Printf(`GoPush %s Compiler: %s %s Copyright (C) 2016 Bo-Yi Wu, Inc.`,
Version,
runtime.Compiler,
runtime.Version())
}
func VersionMiddleware() gin.HandlerFunc {
// Set out header value for each response
return func(c *gin.Context) {
c.Writer.Header().Set("Server-Version", "GoPush "+Version)
c.Next()
}
}