Skip to content

Repository files navigation

This Fork Updates

This fork has basic authentication enabled by default. To disable set parameter auth -> Enabled in config.yml to false.

If enabled, set the username and password.

All APIs are under basic auth if enabled.

gorush

A push notification micro server using Gin framework written in Go (Golang) and see the demo app.

GoDocBuild StatusBuild statuscodecovGo Report Cardcodebeat badgeCodacy BadgeDocker PullsRelease

Contents

Buy Me A Coffee

Support Platform

Features

  • Support Firebase Cloud Messaging using go-fcm library for Android.
  • Support HTTP/2 Apple Push Notification Service using apns2 library.
  • Support YAML configuration.
  • Support command line to send single Android or iOS notification.
  • Support Web API to send push notification.
  • Support graceful restart & zero downtime deploy using facebook grace.
  • Support HTTP/2 or HTTP/1.1 protocol.
  • Support notification queue and multiple workers.
  • Support /api/stat/app show notification success and failure counts.
  • Support /api/config show your YAML config.
  • Support store app stat to memory, Redis, BoltDB, BuntDB, LevelDB or BadgerDB.
  • Support p8, p12 or pem format of iOS certificate file.
  • Support /sys/stats show response time, status code count, etc.
  • Support for HTTP proxy to Google server (FCM).
  • Support retry send notification if server response is fail.
  • Support expose prometheus metrics.
  • Support install TLS certificates from Let's Encrypt automatically.
  • Support send notification through RPC protocol, we use gRPC as default framework.
  • Support running in Docker, Kubernetes or AWS Lambda (Native Support in Golang)

See the default YAML config example:

core:
enabled: true # enabale httpd serveraddress: ""# ip address to bind (default: any)port: "8088"# ignore this port number if auto_tls is enabled (listen 443).worker_num: 0# default worker number is runtime.NumCPU()queue_num: 0# default queue number is 8192max_notification: 100sync: false # set true if you need get error message from fail push notification in API response.mode: "release"ssl: falsecert_path: "cert.pem"key_path: "key.pem"cert_base64: ""key_base64: ""http_proxy: ""# only working for FCM serverpid:
enabled: falsepath: "gorush.pid"override: trueauto_tls:
enabled: false # Automatically install TLS certificates from Let's Encrypt.folder: ".cache"# folder for storing TLS certificateshost: ""# which domains the Let's Encrypt will attemptgrpc:
enabled: false # enabale gRPC serverport: 9000api:
push_uri: "/api/push"stat_go_uri: "/api/stat/go"stat_app_uri: "/api/stat/app"config_uri: "/api/config"sys_stat_uri: "/sys/stats"metric_uri: "/metrics"health_uri: "/healthz"android:
enabled: trueapikey: "YOUR_API_KEY"max_retry: 0# resend fail notification, default value zero is disabledios:
enabled: falsekey_path: "key.pem"key_base64: ""# load iOS key from base64 inputkey_type: "pem"# could be pem, p12 or p8 typepassword: ""# certificate password, default as empty string.production: falsemax_retry: 0# resend fail notification, default value zero is disabledkey_id: ""# KeyID from developer account (Certificates, Identifiers & Profiles -> Keys)team_id: ""# TeamID from developer account (View Account -> Membership)log:
format: "string"# string or jsonaccess_log: "stdout"# stdout: output to console, or define log path like "log/access_log"access_level: "debug"error_log: "stderr"# stderr: output to console, or define log path like "log/error_log"error_level: "error"hide_token: truestat:
engine: "memory"# support memory, redis, boltdb, buntdb or leveldbredis:
addr: "localhost:6379"password: ""db: 0boltdb:
path: "bolt.db"bucket: "gorush"buntdb:
path: "bunt.db"leveldb:
path: "level.db"

Memory Usage

Memory average usage: 28Mb (the total bytes of memory obtained from the OS.)

memory usage

Test Command (We use bat as default cli tool.):

$ foriin {1..9999999};do bat -b.N=1000 -b.C=100 POST localhost:8088/api/push notifications:=@notification.json; sleep 1;done

Basic Usage

How to send push notification using gorush command? (Android or iOS)

Download a binary

The pre-compiled binaries can be downloaded from release page.

With Go installed

$ go get -u -v github.com/appleboy/gorush

On linux

$ wget https://github.com/appleboy/gorush/releases/download/1.10.0/gorush-1.10.0-linux-amd64 -O gorush

On OS X

$ wget https://github.com/appleboy/gorush/releases/download/1.10.0/gorush-1.10.0-darwin-amd64 -O gorush

On Windows

$ wget https://github.com/appleboy/gorush/releases/download/1.10.0/gorush-1.10.0-windows-amd64.exe -O gorush.exe

On macOS, use Homebrew.

$ brew install --HEAD https://github.com/appleboy/gorush/raw/master/HomebrewFormula/gorush.rb

Install from source

Prerequisite Tools

Fetch from GitHub

Gorush uses the Go Modules support built into Go 1.11 to build. The easiest way to get started is to clone Gorush in a directory outside of the GOPATH, as in the following example:

$ mkdir $HOME/src
$ cd $HOME/src
$ git clone https://github.com/appleboy/gorush.git
$ cd gorush
$ go install

Command Usage

 ________ .__
/ _____/ ____ _______ __ __ ______| |__
/ \ ___ / _ \\_ __ \| | \/ ___/| | \
\ \_\ \( <_> )| | \/| | /\___ \ | Y \
\______ / \____/ |__| |____//____ >|___| /
\/ \/ \/
Usage: gorush [options]
Server Options:
-A, --address <address> Address to bind (default: any)
-p, --port <port> Use port for clients (default: 8088)
-c, --config <file> Configuration file path
-m, --message <message> Notification message
-t, --token <token> Notification token
-e, --engine <engine> Storage engine (memory, redis ...)
--title <title> Notification title
--proxy <proxy> Proxy URL (only for GCM)
--pid <pid path> Process identifier path
--redis-addr <redis addr> Redis addr (default: localhost:6379)
iOS Options:
-i, --key <file> certificate key file path
-P, --password <password> certificate key password
--ios enabled iOS (default: false)
--production iOS production mode (default: false)
Android Options:
-k, --apikey <api_key> Android API Key
--android enabled android (default: false)
Common Options:
--topic <topic> iOS or Android topic message
-h, --help Show this message
-v, --version Show version

Send Android notification

Send single notification with the following command.

$ gorush -android -m "your message" -k "API Key" -t "Device token"

Send messages to topics.

$ gorush --android --topic "/topics/foo-bar" \
-m "This is a Firebase Cloud Messaging Topic Message" \
-k your_api_key
  • -m: Notification message.
  • -k: Firebase Cloud Messaging api key
  • -t: Device token.
  • --title: Notification title.
  • --topic: Send messages to topics. note: don't add device token.
  • --proxy: Set http proxy url. (only working for FCM)

Send iOS notification

Send single notification with the following command.

$ gorush -ios -m "your message" -i "your certificate path" \
-t "device token" --topic "apns topic"
  • -m: Notification message.
  • -i: Apple Push Notification Certificate path (pem or p12 file).
  • -t: Device token.
  • --title: Notification title.
  • --topic: The topic of the remote notification.
  • --password: The certificate password.

The default endpoint is APNs development. Please add -production flag for APNs production push endpoint.

$ gorush -ios -m "your message" -i "your certificate path" \
-t "device token" \
-production

Send Android or iOS notifications using Firebase

Send single notification with the following command:

$ gorush -android -m "your message" -k "API key" -t "Device token"

Run gorush web server

Please make sure your config.yml exist. Default port is 8088.

# for default config
$ gorush
# for custom config file
$ gorush -c config.yml

Get go status of api server using httpie tool:

$ http -v --verify=no --json GET http://localhost:8088/api/stat/go

Web API

Gorush support the following API.

  • GET/api/stat/go Golang cpu, memory, gc, etc information. Thanks for golang-stats-api-handler.
  • GET/api/stat/app show notification success and failure counts.
  • GET/api/config show server yml config file.
  • POST/api/push push ios and android notifications.

GET /api/stat/go

Golang cpu, memory, gc, etc information. Response with 200 http status code.

{
"time": 1460686815848046600,
"go_version": "go1.6.1",
"go_os": "darwin",
"go_arch": "amd64",
"cpu_num": 4,
"goroutine_num": 15,
"gomaxprocs": 4,
"cgo_call_num": 1,
"memory_alloc": 7455192,
"memory_total_alloc": 8935464,
"memory_sys": 12560632,
"memory_lookups": 17,
"memory_mallocs": 31426,
"memory_frees": 11772,
"memory_stack": 524288,
"heap_alloc": 7455192,
"heap_sys": 8912896,
"heap_idle": 909312,
"heap_inuse": 8003584,
"heap_released": 0,
"heap_objects": 19654,
"gc_next": 9754725,
"gc_last": 1460686815762559700,
"gc_num": 2,
"gc_per_second": 0,
"gc_pause_per_second": 0,
"gc_pause": [
0.326576,
0.227096
]
}

GET /api/stat/app

Show success or failure counts information of notification.

{
"version": "v1.6.2",
"queue_max": 8192,
"queue_usage": 0,
"total_count": 77,
"ios": {
"push_success": 19,
"push_error": 38
},
"android": {
"push_success": 10,
"push_error": 10
}
}

GET /sys/stats

Show response time, status code count, etc.

{
"pid": 80332,
"uptime": "1m42.428010614s",
"uptime_sec": 102.428010614,
"time": "2016-06-26 12:27:11.675973571 +0800 CST",
"unixtime": 1466915231,
"status_code_count": { },
"total_status_code_count": {
"200": 5
},
"count": 0,
"total_count": 5,
"total_response_time": "10.422441ms",
"total_response_time_sec": 0.010422441000000001,
"average_response_time": "2.084488ms",
"average_response_time_sec": 0.0020844880000000002
}

GET /metrics

Support expose prometheus metrics.

metrics screenshot

POST /api/push

Simple send iOS notification example, the platform value is 1:

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 1,
"message": "Hello World iOS!"
}
]
}

Simple send Android notification example, the platform value is 2:

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 2,
"message": "Hello World Android!"
}
]
}

Simple send notification on Android and iOS devices using Firebase, the platform value is 2:

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 2,
"message": "This notification will go to iOS and Android platform via Firebase!"
}
]
}

Send multiple notifications as below:

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 1,
"message": "Hello World iOS!"
},
{
"tokens": ["token_a", "token_b"],
"platform": 2,
"message": "Hello World Android!"
},
{
"tokens": ["token_a", "token_b"],
"platform": 2,
"message": "Hello World!"
},
.....
]
}

See more example about iOS or Android.

Request body

Request body must has a notifications array. The following is a parameter table for each notification.

nametypedescriptionrequirednote
tokensstring arraydevice tokenso
platformintplatform(iOS,Android)o1=iOS, 2=Android (Firebase)
messagestringmessage for notification-
titlestringnotification title-
prioritystringSets the priority of the message.-normal or high
content_availablebooldata messages wake the app by default.-
soundinterface{}sound type-
datastring arrayextensible partition-
legacyboolsupport for legacy or custom payload (uses as payload whatever format is in data as notification payload)-only iOS
retryintretry send notification if fail response from server. Value must be small than max_retry field.-
topicstringsend messages to topics
api_keystringapi key for firebase cloud message-only Android
tostringThe value must be a registration token, notification key, or topic.-only Android
collapse_keystringa key for collapsing notifications-only Android
delay_while_idleboola flag for device idling-only Android
time_to_liveuintexpiration of message kept on FCM storage-only Android
restricted_package_namestringthe package name of the application-only Android
dry_runboolallows developers to test a request without actually sending a message-only Android
notificationstring arraypayload of a FCM message-only Android. See the detail
expirationintexpiration for notification-only iOS
apns_idstringA canonical UUID that identifies the notification-only iOS
badgeintbadge count-only iOS
categorystringthe UIMutableUserNotificationCategory object-only iOS
alertstring arraypayload of a iOS message-only iOS. See the detail
mutable_contentboolenable Notification Service app extension.-only iOS(10.0+).
namestringsets the name value on the aps sound dictionary.-only iOS
volumefloat32sets the volume value on the aps sound dictionary.-only iOS

iOS alert payload

nametypedescriptionrequirednote
titlestringApple Watch & Safari display this string as part of the notification interface.-
bodystringThe text of the alert message.-
subtitlestringApple Watch & Safari display this string as part of the notification interface.-
actionstringThe label of the action button. This one is required for Safari Push Notifications.-
action-loc-keystringIf a string is specified, the system displays an alert that includes the Close and View buttons.-
launch-imagestringThe filename of an image file in the app bundle, with or without the filename extension.-
loc-argsarray of stringsVariable string values to appear in place of the format specifiers in loc-key.-
loc-keystringA key to an alert-message string in a Localizable.strings file for the current localization.-
title-loc-argsarray of stringsVariable string values to appear in place of the format specifiers in title-loc-key.-
title-loc-keystringThe key to a title string in the Localizable.strings file for the current localization.-

See more detail about APNs Remote Notification Payload.

iOS sound payload

nametypedescriptionrequirednote
namestringsets the name value on the aps sound dictionary.-
volumefloat32sets the volume value on the aps sound dictionary.-
criticalintsets the critical value on the aps sound dictionary.-

request format:

{
"sound": {
"critical": 1,
"name": "default",
"volume": 2.0
}
}

Android notification payload

nametypedescriptionrequirednote
iconstringIndicates notification icon.-
tagstringIndicates whether each notification message results in a new entry on the notification center on Android.-
colorstringIndicates color of the icon, expressed in #rrggbb format-
click_actionstringThe action associated with a user click on the notification.-
body_loc_keystringIndicates the key to the body string for localization.-
body_loc_argsstringIndicates the string value to replace format specifiers in body string for localization.-
title_loc_keystringIndicates the key to the title string for localization.-
title_loc_argsstringIndicates the string value to replace format specifiers in title string for localization.-

See more detail about Firebase Cloud Messaging HTTP Protocol reference.

iOS Example

Send normal notification.

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 1,
"message": "Hello World iOS!"
}
]
}

The following payload asks the system to display an alert with a Close button and a single action button.The title and body keys provide the contents of the alert. The “PLAY” string is used to retrieve a localized string from the appropriate Localizable.strings file of the app. The resulting string is used by the alert as the title of an action button. This payload also asks the system to badge the app’s icon with the number 5.

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 1,
"badge": 5,
"alert": {
"title" : "Game Request",
"body" : "Bob wants to play poker",
"action-loc-key" : "PLAY"
}
}
]
}

The following payload specifies that the device should display an alert message, plays a sound, and badges the app’s icon.

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 1,
"message": "You got your emails.",
"badge": 9,
"sound": {
"critical": 1,
"name": "default",
"volume": 1.0
}
}
]
}

Add other fields which user defined via data field.

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 1,
"message": "Hello World iOS!",
"data": {
"key1": "welcome",
"key2": 2
}
}
]
}

Support send notification from different environment. See the detail of issue.

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 1,
+ "production": true,
"message": "Hello World iOS Production!"
},
{
"tokens": ["token_a", "token_b"],
"platform": 1,
+ "development": true,
"message": "Hello World iOS Sandbox!"
}
]
}

Android Example

Send normal notification.

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 2,
"message": "Hello World Android!",
"title": "You got message"
}
]
}

Add notification payload.

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 2,
"message": "Hello World Android!",
"title": "You got message",
"notification" : {
"icon": "myicon",
"color": "#112244"
}
}
]
}

Add other fields which user defined via data field.

{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 2,
"message": "Hello World Android!",
"title": "You got message",
"data": {
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
}
}
]
}

Send messages to topics

{
"notifications": [
{
"to": "/topics/foo-bar",
"platform": 2,
"message": "This is a Firebase Cloud Messaging Topic Message"
}
]
}

Response body

Error response message table:

status codemessage
400Missing notifications field.
400Notifications field is empty.
400Number of notifications(50) over limit(10)

Success response:

{
"counts": 60,
"logs": [],
"success": "ok"
}

If you need error logs from sending fail notifications, please set sync as true on yaml config.

core:
port: "8088" # ignore this port number if auto_tls is enabled (listen 443).
worker_num: 0 # default worker number is runtime.NumCPU()
queue_num: 0 # default queue number is 8192
max_notification: 100
- sync: false + sync: true

See the following error format.

{
"counts": 60,
"logs": [
{
"type": "failed-push",
"platform": "android",
"token": "*******",
"message": "Hello World Android!",
"error": "InvalidRegistration"
},
{
"type": "failed-push",
"platform": "ios",
"token": "*****",
"message": "Hello World iOS1111!",
"error": "Post https://api.push.apple.com/3/device/bbbbb: remote error: tls: revoked certificate"
},
{
"type": "failed-push",
"platform": "ios",
"token": "*******",
"message": "Hello World iOS222!",
"error": "Post https://api.push.apple.com/3/device/token_b: remote error: tls: revoked certificate"
}
],
"success": "ok"
}

Run gRPC service

Gorush support gRPC service. You can enable the gRPC in config.yml, default as disabled. Enable the gRPC server:

$ GORUSH_GRPC_ENABLED=true GORUSH_GRPC_PORT=3000 gorush

The following example code to send single notification in Go.

package main
import (
"context""log""github.com/appleboy/gorush/rpc/proto"
structpb "github.com/golang/protobuf/ptypes/struct""google.golang.org/grpc"
)
const (
address="localhost:9000"
)
funcmain() {
// Set up a connection to the server.conn, err:=grpc.Dial(address, grpc.WithInsecure())
iferr!=nil {
log.Fatalf("did not connect: %v", err)
}
deferconn.Close()
c:=proto.NewGorushClient(conn)
r, err:=c.Send(context.Background(), &proto.NotificationRequest{
Platform: 2,
Tokens: []string{"1234567890"},
Message: "test message",
Badge: 1,
Category: "test",
Sound: "test",
Alert: &proto.Alert{
Title: "Test Title",
Body: "Test Alert Body",
Subtitle: "Test Alert Sub Title",
LocKey: "Test loc key",
LocArgs: []string{"test", "test"},
},
Data: &structpb.Struct{
Fields: map[string]*structpb.Value{
"key1": {
Kind: &structpb.Value_StringValue{StringValue: "welcome"},
},
"key2": {
Kind: &structpb.Value_NumberValue{NumberValue: 2},
},
},
},
})
iferr!=nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Success: %t\n", r.Success)
log.Printf("Count: %d\n", r.Counts)
}

See the Node.js example and see more detail frome README:

varmessages=require('./gorush_pb');varservices=require('./gorush_grpc_pb');vargrpc=require('grpc');functionmain(){varclient=newservices.GorushClient('localhost:9000',grpc.credentials.createInsecure());varrequest=newmessages.NotificationRequest();varalert=newmessages.Alert();request.setPlatform(2);request.setTokensList(["1234567890"]);request.setMessage("Hello!!");request.setTitle("hello2");request.setBadge(2);request.setCategory("mycategory");request.setSound("sound")alert.setTitle("title");request.setAlert(alert);request.setThreadid("threadID");request.setContentavailable(false);request.setMutablecontent(false);client.send(request,function(err,response){if(err){console.log(err);}else{console.log("Success:",response.getSuccess());console.log("Counts:",response.getCounts());}});}main();

GRPC Health Checking example: See document.

package main
import (
"context""log""github.com/appleboy/gorush/rpc/proto"
structpb "github.com/golang/protobuf/ptypes/struct""google.golang.org/grpc"
)
const (
address="localhost:9000"
)
funcmain() {
// Set up a connection to the server.conn, err:=grpc.Dial(address, grpc.WithInsecure())
iferr!=nil {
log.Fatalf("did not connect: %v", err)
}
deferconn.Close()
c:=proto.NewGorushClient(conn)
r, err:=c.Send(context.Background(), &proto.NotificationRequest{
Platform: 2,
Tokens: []string{"1234567890"},
Message: "test message",
Badge: 1,
Category: "test",
Sound: "test",
Alert: &proto.Alert{
Title: "Test Title",
Body: "Test Alert Body",
Subtitle: "Test Alert Sub Title",
LocKey: "Test loc key",
LocArgs: []string{"test", "test"},
},
Data: &structpb.Struct{
Fields: map[string]*structpb.Value{
"key1": {
Kind: &structpb.Value_StringValue{StringValue: "welcome"},
},
"key2": {
Kind: &structpb.Value_NumberValue{NumberValue: 2},
},
},
},
})
iferr!=nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Success: %t\n", r.Success)
log.Printf("Count: %d\n", r.Counts)
}

Run gorush in Docker

Set up gorush in the cloud in under 5 minutes with zero knowledge of Golang or Linux shell using our gorush Docker image.

$ docker pull appleboy/gorush
$ docker run --name gorush -p 80:8088 appleboy/gorush

Run gorush with your own config file.

$ docker pull appleboy/gorush
$ docker run --name gorush -v ${PWD}/config.yml:/config.yml -p 80:8088 appleboy/gorush

Testing your gorush server using httpie command.

$ http -v --verify=no --json GET http://your.docker.host/api/stat/go

statue screenshot

Run gorush in Kubernetes

Quick Start

Create namespace as gorush as gorush and then your configuration map:

$ kubectl create -f k8s/gorush-namespace.yaml
$ kubectl create -f k8s/gorush-configmap.yaml

Create redis service:

$ kubectl create -f k8s/gorush-redis-deployment.yaml
$ kubectl create -f k8s/gorush-redis-service.yaml

Create gorush deployment controller provides declarative updates for Pods and ReplicaSets:

$ kubectl create -f k8s/gorush-deployment.yaml

Create the Service Controller for AWS ELB

$ kubectl create -f k8s/gorush-service.yaml

Ingress Controller for AWS ALB

Update the following in k8s/gorush-service.yaml

- type: LoadBalancer- # type: NodePort+ # type: LoadBalancer+ type: NodePort

Then start the AWS ALB by the follwong command.

$ kubectl create -f k8s/gorush-service.yaml
$ kubectl create -f k8s/gorush-aws-alb-ingress.yaml

Clean up the gorush:

$ kubectl delete -f k8s

Run gorush in AWS Lambda

AWS excited to announce Go as a supported language for AWS Lambda. You’re going to create an application that uses an API Gateway event source to create a simple Hello World RESTful API.

Build gorush binary

Download source code first.

$ git clone https://github.com/appleboy/gorush.git
$ cd gorush && make build_linux_lambda

you can see the binary file in release/linux/lambda/ folder

Deploy gorush application

we need to build a binary that will run on Linux, and ZIP it up into a deployment package.

$ zip deployment.zip release/linux/lambda/gorush

Upload the deployment.zip via web UI or you can try the drone-lambda as the following command. it will zip your binary file and upload to AWS Lambda automatically.

$ AWS_ACCESS_KEY_ID=YOUR_AWS_ACCESS_KEY_ID \
AWS_SECRET_ACCESS_KEY=YOUR_AWS_SECRET_ACCESS_KEY \
drone-lambda --region ap-southeast-1 \
--function-name gorush \
--source release/linux/lambda/gorush

Stargazers over time

Stargazers over time

License

Copyright 2018 Bo-Yi Wu @appleboy.

Licensed under the MIT License.

About

A push notification server written in Go (Golang).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages