diff --git a/.gitignore b/.gitignore index daf913b..cfb5aef 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ _testmain.go *.exe *.test *.prof + +gin-bin +key.pem diff --git a/const.go b/const.go new file mode 100644 index 0000000..237f852 --- /dev/null +++ b/const.go @@ -0,0 +1,10 @@ +package main + +const ( + Version = "0.0.1" +) + +const ( + PlatFormIos = iota + 1 + PlatFormAndroid +) diff --git a/main.go b/main.go index 8f0d4bf..844e73e 100644 --- a/main.go +++ b/main.go @@ -4,11 +4,38 @@ import ( "net/http" "github.com/gin-gonic/gin" api "github.com/appleboy/gin-status-api" + "github.com/fvbock/endless" + "log" ) -func rootHandler(context *gin.Context) { - context.JSON(http.StatusOK, gin.H{ - "text": "hello world", +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, "Missing some parameters like token or platform or message") + return + } + + // process notification. + pushNotification(form) + + c.JSON(http.StatusOK, gin.H{ + "text": "Welcome to golang push server.", }) } @@ -20,11 +47,12 @@ func GetMainEngine() *gin.Engine { r.Use(gin.Recovery()) r.GET("/api/status", api.StatusHandler) + r.POST("/api/push", pushHandler) r.GET("/", rootHandler) return r } func main() { - GetMainEngine().Run(":8088") + endless.ListenAndServe(":8088", GetMainEngine()) } diff --git a/notification.go b/notification.go new file mode 100644 index 0000000..d2af22b --- /dev/null +++ b/notification.go @@ -0,0 +1,119 @@ +package main + +import( + apns "github.com/sideshow/apns2" + "github.com/sideshow/apns2/payload" + "github.com/sideshow/apns2/certificate" + "log" +) + +type ExtendJSON struct { + Key string `json:"key"` + Value string `json:"val"` +} + +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"` + // Android + CollapseKey string `json:"collapse_key,omitempty"` + DelayWhileIdle bool `json:"delay_while_idle,omitempty"` + TimeToLive int `json:"time_to_live,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"` + Extend []ExtendJSON `json:"extend,omitempty"` + // meta + IDs []uint64 `json:"seq_id,omitempty"` +} + +func pushNotification(notification RequestPushNotification) bool { + var ( + success bool + ) + + cert, err := certificate.FromPemFile("./key.pem", "") + if err != nil { + log.Println("Cert Error:", err) + } + + apnsClient := apns.NewClient(cert).Development() + + switch notification.Platform { + case PlatFormIos: + success = pushNotificationIos(notification, apnsClient) + if !success { + apnsClient = nil + } + case PlatFormAndroid: + success = pushNotificationAndroid(notification) + } + + return success +} + +func pushNotificationIos(req RequestPushNotification, client *apns.Client) 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 == "low" { + 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 len(req.Extend) > 0 { + for _, extend := range req.Extend { + payload.Custom(extend.Key, extend.Value) + } + } + + notification.Payload = payload + + // send ios notification + res, err := client.Push(notification) + + if err != nil { + log.Println("There was an error", err) + return false + } + + if res.Sent() { + log.Println("APNs ID:", res.ApnsID) + } + } + + client = nil + + return true +} + +func pushNotificationAndroid(req RequestPushNotification) bool { + + return true +}