APNs and FCM provider server on HTTP/2.
- Gunfish provides the nterface as the APNs / FCM provider server.
$ go get github.com/kayac/Gunfish/cmd/gunfish
$ gunfish -c ./config/gunfish.toml -E production
option | required | description |
---|---|---|
-port | Optional | Port number of Gunfish provider server. Default is 8003 . |
-environment, -E | Optional | Default value is production . |
-conf, -c | Optional | Please specify this option if you want to change toml config file path. (default: /etc/gunfish/config.toml .) |
-log-level | Optional | Set the log level as 'warn', 'info', or 'debug'. |
-log-format | Optional | Supports json or ltsv log formats. |
-enable-pprof | Optional | You can set the flag of pprof debug port open. |
-output-hook-stdout | Optional | Merge stdout of hook command to gunfish's stdout. |
-output-hook-stderr | Optional | Merge stderr of hook command to gunfish's stderr. |
To delivery remote notifications via APNS to user's devices.
param | description |
---|---|
Array | Array of JSON dictionary includes 'token' and 'payload' properties |
payload param | description |
---|---|
token | Published token from APNS to user's remote device |
payload | APNS notification payload |
Post JSON example:
[
{
"payload": {
"aps": {
"alert": "test notification",
"sound": "default"
},
"option1": "foo",
"option2": "bar"
},
"token": "apns device token",
"header": {
"apns-id": "your apns id",
"apns-topic": "your app bundle id",
"apns-push-type": "alert"
}
}
]
Response example:
{"result": "ok"}
To delivery remote notifications via FCM (legacy) API to user's devices.
Post body format is equal to it for FCM legacy origin server.
example:
{
"registration_ids": [
"token1",
"token2"
],
"data": {
"id": "2",
"message": "Test2"
},
"notification": {
"title": "message_title",
"body": "message_body"
}
}
Response example:
{"result": "ok"}
To delivery remote notifications via FCM v1 API to user's devices.
Post body format is equal to it for FCM v1 origin server.
example:
{
"message": {
"notification": {
"title": "message_title",
"body": "message_body",
"image": "https://example.com/notification.png"
},
"data": {
"sample_key": "sample key",
"message": "sample message"
},
"token": "InstanceIDTokenForDevice"
}
}
Response example:
{"result": "ok"}
FCM v1 endpoint allows multiple payloads in a single request body. You can build request body simply concat multiple JSON payloads. Gunfish sends for each that payloads to FCM server. Limitation: Max count of payloads in a request body is 500.
{
"pid": 57843,
"debug_port": 0,
"uptime": 384,
"start_at": 1492476864,
"su_at": 0,
"period": 309,
"retry_after": 10,
"workers": 8,
"queue_size": 0,
"retry_queue_size": 0,
"workers_queue_size": 0,
"cmdq_queue_size": 0,
"retry_count": 0,
"req_count": 0,
"sent_count": 0,
"err_count": 0,
"certificate_not_after": "2027-04-16T00:53:53Z",
"certificate_expire_until": 315359584
}
To get the status of APNS proveder server.
stats type | description |
---|---|
pid | PID |
debug_port | pprof port number |
uptime | uptime |
workers | number of workers |
start_at | The time of started |
queue_size | queue size of requests |
retry_queue_size | queue size for resending notification |
workers_queue_size | summary of worker's queue size |
command_queue_size | error hook command queue size |
retry_count | summary of retry count |
request_count | request count to gunfish |
err_count | count of recieving error response |
sent_count | count of sending notification |
certificate_not_after | certificates minimum expiration date for APNs |
certificate_expire_until | certificates minimum expiration untile (sec) |
To get the status of go application.
See detail properties that url: (https://github.com/fukata/golang-stats-api-handler).
The Gunfish configuration file is a TOML file that Gunfish server uses to configure itself.
That configuration file should be located /etc/gunfish.toml
, and is required to start.
Here is an example configuration:
[provider]
port = 8203
worker_num = 8
queue_size = 2000
max_request_size = 1000
max_connections = 2000
error_hook = "echo -e 'Hello Gunfish at error hook!'"
[apns]
key_file = "/path/to/server.key"
cert_file = "/path/to/server.crt"
kid = "kid"
team_id = "team_id"
[fcm]
api_key = "API key for FCM"
[fcm_v1]
google_application_credentials = "/path/to/credentials.json"
param | status | description |
---|---|---|
port | optional | Listen port number. |
worker_num | optional | Number of Gunfish owns http clients. |
queue_size | optional | Limit number of posted JSON from the developer application. |
max_request_size | optional | Limit size of Posted JSON array. |
max_connections | optional | Max connections |
key_file | required | The key file path. |
cert_file | optional | The cert file path. |
kid | optional | kid for APNs provider authentication token. |
team_id | optional | team id for APNs provider authentication token. |
error_hook | optional | Error hook command. This command runs when Gunfish catches an error response. |
api_key | optional | FCM api key. If you want to delivery notifications to android, it is required. |
Error hook command can get an each error response with JSON format by STDIN.
for example JSON structure: (>= v0.2.x)
// APNs
{
"provider": "apns",
"apns-id": "123e4567-e89b-12d3-a456-42665544000",
"status": 400,
"token": "9fe817acbcef8173fb134d8a80123cba243c8376af83db8caf310daab1f23003",
"reason": "MissingTopic"
}
// FCM
{
"provider": "fcm",
"status": 200,
"registration_id": "8kMSTcfqrca:APA91bEfS-uC1WV374Mg83Lkn43..",
// or "to": "8kMSTcfqrca:APA91bEfS-uC1WV374Mg83Lkn43..",
"error": "InvalidRegistration"
}
// FCM v1
{
"provider": "fcmv1",
"status": 400,
"token": "testToken",
"error": {
"status": "INVALID_ARGUMENT",
"message": "The registration token is not a valid FCM registration token"
}
}
Gunfish supports graceful restarting based on Start Server
. So, you should start on start_server
command if you want graceful to restart.
### install start_server
$ go get github.com/lestrrat/go-server-starter/cmd/start_server
### Starts Gunfish with start_server
$ start_server --port 38003 --pid-file gunfish.pid -- ./gunfish -c conf/gunfish.toml
If you have to handle something on error or on success, you should implement error or success handlers. For example handlers you should implement is given below:
type CustomYourErrorHandler struct {
hookCmd string
}
func (ch CustomYourErrorHandler) OnResponse(result Result){
// ...
}
func (ch CustomYourErrorHandler) HookCmd( ) string {
return ch.hookCmd
}
Then you can use these handlers to set before to start gunfish server ( gunfish.StartServer( Config, Environment ) )
.
InitErrorResponseHandler(CustomYourErrorHandler{hookCmd: "echo 'on error!'"})
You can implement a success custom handler in the same way but a hook command is not executed in the success handler in order not to make cpu resource too tight.
Requires dep for vendoring.
$ make test
The following tools are useful to send requests to gunfish for test the following.
- gunfish-cli (send push notification to Gunfish for test)
- apnsmock (APNs mock server)
$ make tools/gunfish-cli
$ make tools/apnsmock
- send a request example with gunfish-cli
$ ./gunfish-cli -type apns -count 1 -json-file some.json -verbose
$ ./gunfish-cli -type apns -count 1 -token <device token> -apns-topic <your topic> -options key1=val1,key2=val2 -verbose
- start apnsmock server
$ ./apnsmock -cert-file ./test/server.crt -key-file ./test/server.key -verbose
Gunfish repository includes Lua script for the benchmark. You can use wrk command with err_and_success.lua
script.
$ make tools/apnsmock
$ ./apnsmock -cert-file ./test/server.crt -key-file ./test/server.key -verbosea &
$ ./gunfish -c test/gunfish_test.toml -E test
$ wrk2 -t2 -c20 -s bench/scripts/err_and_success.lua -L -R100 http://localhost:38103