Introduction

There is reference for PC Pusher, version 6.0

The PC Pusher is a fast microservice application with the ability to work under high load. It allows sending pushes to all device types like iOS, Android, Huawei.
PC Pusher supports secure uploading data to mobile device and can send a notification delivery report to the application system.

PC Pusher uses

  • Redis as external cache-service
  • STOMP protocol for interchange between PC Pusher components. So, any message broker (like RabbitMQ, ActiveMQ, ArtemisMQ, HornetMQ and others) with STOMP-protocol support can be used.

PC Pusher can be deployed as single-application as well. In this case, in-memmory STOMP message broker built-in will be used.

PC Pusher contains two API interfaces to interact with:

  • PC Pusher 5.2 API
  • PC Inform 2.0 API

PC Pusher contains following microservices:

  • PushReceiver
  • StompBrokerRelay
  • Senders: AppleSender, HuaweiSender, GoogleSender
  • Payloader
  • Callbacker
  • StatusChanger

General flow description

Principles

PC Pusher process in general looks like following:

  1. An Application sends via HTTP-POST request with push-task to PushReceiver
  2. PushReceiver processes task and sends it to a proper Sender
  3. Sender sends message to a mobile device through cloud-service
  4. The mobile device receives the push-message and sends HTTP-POST request to Payloader to recieve push-task-payload
  5. Payloader provides push-task-payload to the mobile devices and sends notification to Callbacker
  6. Callbacker sends infromation about push-task-status to the Application via HTTP-POST request

Workflow

PC Pusher process work flow is shown in Figure-1 bellow (clickable).

pusher-flow.gif

Workflow steps

Prerequisites

  1. In case of external message broker StompBrokerRelay service connects to a message broker
  2. Other services connects to the message broker queues via StompBrokerRelay:
    • /queue/android
    • /queue/apple
    • /queue/huawei
    • /queue/notification
    • /queue/callbacks

Steps description

  1. An Application sends push-task via HTTP-POST request to PushReceiver. The task can contain base64-encoded payload
  2. PushReceiver processes task:
    • creates notification object
    • adds randomly generated pcinform_uuid to push-message
    • stores it to Redis
    • chooses proper sender queue
    • sends prepared task to choosen queue
  3. Sender
    • chooses proper credentials to communicate with cloud-service (APNS/Firebase/HMS)
    • sends push-message to the cloud service
    • sends notification object with renewed status to StatusChanger via /notification/queue
  4. StatusChanger receives notification and renews notification status in Redis

Following steps are optional and it used to control push-delivery and/or provide additinal payload via authenticated channel

  1. Mobile device
    • receives push-message from cloud sevice
    • calculates authentication code = HMAC-SHA256(sha256(device_token), pcinform_uuid), hex-string representation
    • requests Payloader for notification payload, request is authenticated by authentication code
  2. Payloader
    • receives request from mobile devices
    • calculates and verifies authentication code, returns HTTP 401 ('Not Authorized') in case of fail
    • gets payload from Redis
    • returns HTTP 204 ('No Content') or HTTP 200 ('OK')
    • sends callback-task to /queue/callbacks to send callback about push delivered successfuly status
    • sends notification object with renewed status to StatusChanger via /notification/queue
  3. Callbacker sends HTTP-POST callback to the Application

API Description

PC Pusher 5.2 API

Send templated push

endpoint: {{pc-pusher-host}}/pc-pusher-api/send_push
method: POST

Request Sample

{
    "system_id":"ba44ac5f-04fc-4f67-be3a-89aa91e1cb67",
    "user_id":"rest-api-test-8b395013-b24b-447e-8c18-cc99cab84bee",
    "transaction_id":"sa119c5f-7fsc-3f63-h63h-91aa91e1cb67",
    "device_id":"e32f85ebb55556aab154fef6eaf884c4a5b3c3ba0c8de06156df90d7c25ba98c",
    "device_type":"iOS",
    "appId":"org.paycontrol.app"
}

Response Sample

{
    "answer_type": "notification_info",
    "answer": {
        "result": {
            "error_message": "Success",
            "error_code": 0
        },
        "notification_info": {
            "notification_id": "2f03cda8-06aa-4b9e-961d-bf68a7a867a1",
            "status": "NEW"
        }
    },
    "answer_version": 3
}

This request is to send templated push-notification. Usually used by PC Server to notify mobile app about new transaction.

Request params:

Field name Mandatory Description Type
system_id yes PC System Id String
user_id no PC User Id String
transaction_id no PC Transaction Id String
device_id yes Device push token String
device_type yes Device Type (iOS, Android, Huawei) String
appId yes bundle/package name String

Response contains notification_info object:

Field Description Type
notification_id UUID of notification object String
status notification status String

Send custom push (-es)

endpoint: {{pc-pusher-host}}/pc-pusher-api/send_push_message
method: POST

Request Sample

{
    "system_id":"ba44ac5f-04fc-4f67-be3a-89aa91e1cb67",
    "user_id":"rest-api-test-8b395013-b24b-447e-8c18-cc99cab84bee",
    "transaction_id": "ad88d1b6-e611-42d9-834f-b9c4a31aabcc",
    "device_id": "etrWwLT7nOG2nDC1F_e-9traJqQtxDDHFbQiyCZGQnAwqj82E1sNGJiDyZCa7g2hfk56B_7XHwqKk25Vi5zBgYtime1p1TpcFoRjxsq34s",
    "device_type": "Android",
    "app_id": "org.paycontrol.app",
    "content": {
        "messages": [
            {
                "to": "%DEVICE_TOKEN%",
                "notification": {
                    "tag": "%USER_ID%",
                    "title": "There is a new transaction",
                    "body": "You have transactions to confirm",
                    "icon": "paycontrol_push",
                    "sound": "default"
                },
                "data": {
                    "type": "PayControl_v2"
                }
            }
        ]
    }
}

Response Sample

{
    "answer_type": "notification_info",
    "answer": {
        "result": {
            "error_message": "Success",
            "error_code": 0
        },
        "notification_info": {
            "notification_id": "2f03cda8-06aa-4b9e-961d-bf68a7a867a1",
            "status": "NEW"
        }
    },
    "answer_version": 3
}

The request is used to send custom push or set of pushes to specified mobile app.

Request params:

Field name Mandatory Description Type
system_id yes PC System Id String
user_id no PC User Id String
transaction_id no PC Transaction Id String
device_id yes Device push token String
device_type yes Device Type (iOS, Android, Huawei) String
appId yes bundle/package name String
messages yes push-messages with specific for cloud-service (APNS/Firebase/Huawei) structure JSON-Array

Response is the same as for Send templated push.

Get notification status

endpoint: {{pc-pusher-host}}/pc-pusher-api/notification/{{notification_id}}
method: GET

Response Sample

{
    "answer_type": "notification_info",
    "answer": {
        "result": {
            "error_message": "Success",
            "error_code": 0
        },
        "notification_info": {
            "notification_id": "2f03cda8-06aa-4b9e-961d-bf68a7a867a1",
            "status": "NOTIFICATION_SENT"
        }
    },
    "answer_version": 3
}

Response contains notification_info object:

Field Description Type
notification_id UUID of notification object String
status notification status String

PC Inform 2.0 API

Create push sending task

endpoint: {{pc-pusher-host}}/pc-inform/api/notification
method: POST

Request Sample

{
    "device_token": "72d4cc0ec709b2605914fe45e3605f2fc7735369e3d5e3fcdde14da9cdbaa9e6",
    "device_type": "ios",
    "time_to_live": 120,
    "priority": "HIGH",
    "collapse_key": "1222",
    "payload": "VGVzdCBQQyBQdXNoZXI=",
    "callback_url": "http://app.example.com/approve_delivery",
    "payloader_url": "http://pusher.example.com/api/payload",
    "message": { "aps": {
            "alert": "There is notification",
            "sound": "default",
            "badge": 1,
            "mutable-content": 1,
            "category": "PUSH_CATCHER"
          }

    }
}

Response Sample

{
    "uuid": "6229a35e-eb74-4341-94ec-fc6335346c03"
}

The request creates push-task with optional payload to be delivered and processed as shown in Workflow chapter.

Request params:

Field name Mandatory Description Type
device_token yes Device push token String
time_to_live no time to live for cloud-service Number
priority no Priority cloud-service parameter (HIGH or NORMAL) String
collapse_key no Collapse key for cloud-service String
device_type yes Type of the device (iOS/apple, Android/google, Huawei) String
payload no base64 encoded payload Base64 String
callback_url no url for status callbacks to an Application String
payloader_url no url of Payloader service to get push payload String
message yes push notification with specific for cloud-service structure JSON-Object

Response object:

Field Description Type
uuid UUID of notification object String

Get push task status

endpoint: {{pc-pusher-host}}/pc-inform/api/notification/{{notification_uuid}}
method: GET

Response sample

{
    "uuid": "6229a35e-eb74-4341-94ec-fc6335346c03",
    "status": "NOTIFICATION_SENT",
    "push_type": "Apple",
    "device_token": "72d4cc0ec709b2605914fe45e3605f2fc7735369e3d5e3fcdde14da9cdbaa9e6",
    "callback_url": "http://app.example.com/approve_delivery",
    "payloader_url": "http://pusher.example.com/api/payload",
    "payload": "VGVzdCBQQyBQdXNoZXI="
}

The request is used to get notification status by uuid.

Response:

Field Description Type
uuid UUID of notification object String
status Notification status String
push_type Device type String
device_token Push token of device String
callback_url Callback url String
payloader_url Payloader url String
payload Push payload Base64 String

Payload request

endpoint: {{pc-pusher-host}}/pc-inform/api/payload
method: POST

Request sample

{
    "auth_token": "4f84bc0f9fffc793aa6a2e6b010737c3a5294fd2853111bcef4728af486f8263", 
    "uuid": "6229a35e-eb74-4341-94ec-fc6335346c03"
}

Response sample

{
    "uuid": "6229a35e-eb74-4341-94ec-fc6335346c03",
    "payload": "VGVzdCBQQyBQdXNoZXI="
}

The request is used by mobile device to get push payload and to notify PC Pusher about delivery status.

E.g. if a mobile device has successfuly requested (with success authentication) payload, then push notification has been delivered.

To process the request a mobile device has to calculate authentication code.

HMAC calculating example

For uuid = c03a6d7f-5b5c-49af-be5c-6ea380080cb7 and device_token = fu37vBAcNxY:APA91bGMpZIh7zcksU2cjNVE8ZRhFyo6Xxac-K8Gp3ZOgVkZdanH5xHHpGkaFN1o2khW86pkU2nrC4EUmSaxRKpAYCA9v5h3YtMm-KaWbMUNHn3IWdzn3lFQRFWOtzD9GTl2qlQMezYS

Hex-String for HMAC-SHA256(sha256(device_token), uuid) will be: 4f84bc0f9fffc793aa6a2e6b010737c3a5294fd2853111bcef4728af486f8263

Request params:

Field Description Type
auth_token authentication code Hex-String
uuid Notification UUID String

Response contains following fields:

Field Description Type
uuid UUID of notification object String
payload Push payload Base64 String

Callback

Callback Sample

{
    "task_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",
    "status": 3
}

Callback will be sent by Callbacker at the end of the workflow.

Callbacker sends callbacks with current status in case of following statuses:

  • NOTIFICATION_SENDING_ERROR
  • PAYLOAD_SENT

With receiving the callback the Application can control push delivery status

Push Task Statuses

Status Num value Description
NEW 0 Notification has been created
NOTIFICATION_SENT 1 Notification has been sent to cloud-service
NOTIFICATION_SENDING_ERROR 2 An Error occured during notification sending
PAYLOAD_SENT 3 Payload has been sent to a mobile device
PAYLOAD_SENDING_ERROR 4 An Error occured during payload sending
CALLBACK_DONE 5 Callback is done
CALLBACK_ERROR 6 An Error occured during sending callback to an Application

Configuration

Microservices configuration params

Variable Description Default
StompBrokerRelay
server.portWeb server port for StompBrokerRelay8081
broker.hostHostname of External message broker (Rabbit, Apache MQ, etc.)localhost
broker.usernameClient login for STOMP-acceptor of message brokerguest
broker.passwordClient password for STOMP-acceptor of message brokerguest
broker.destination.prefixqueue prefix for message broker/queue
broker.embedded.enabledEnabling embedded in-memmory message broker or use externaltrue
PushReceiver
server.portWeb server port for PushReceiver8080
stomp.broker.relay.addressStompBrokerRelay addresslocalhost:8081
pusher.statistic.enabledEnables statistic of sent pushesfalse
pusher.statistic.delayDelay between statistic frames in msec300000
receiver.cache.pushsettings.capacitypush templates cache initial size100
receiver.cache.pushsettings.ttlTTL for push templates cache in minutes1
receiver.stomp.reconnect.delayTime between reconnect attempts to StompBrokerRelay in msec5000
spring.redis.hostRedis hostlocalhost
spring.redis.portRedis port49153
redis.ttlTTL for Redis cache in days1
AndroidSender
sender.config.proxy.hostproxy-server host for outgoing connectionsnull
sender.config.proxy.portproxy-server port for outgoing connections0
sender.config.proxy.usernameproxy-server usernamenull
sender.config.proxy.passswordproxy-server passwordnull
stomp.broker.relay.addressStompBrokerRelay addresslocalhost:8081
android.cache.credentials.capacitycredential settings cache initial size10
android.cache.credentials.ttlTTL for credential settings cache in minutes1
android.poolexecutor.poolsizeInitial outgoing connections count10
android.poolexecutor.maxpoolsizeMax outgoing connections count30
android.stomp.reconnect.delayTime between reconnect attempts to StompBrokerRelay in msec5000
AppleSender
sender.config.proxy.hostproxy-server host for outgoing connectionsnull
sender.config.proxy.portproxy-server port for outgoing connections0
sender.config.proxy.usernameproxy-server usernamenull
sender.config.proxy.passswordproxy-server passwordnull
stomp.broker.relay.addressStompBrokerRelay addresslocalhost:8081
apple.cache.credentials.capacitycredential settings cache initial size10
apple.cache.credentials.ttlTTL for credential settings cache in minutes1
apple.poolexecutor.poolsizeInitial outgoing connections count10
apple.poolexecutor.maxpoolsizeMax outgoing connections count30
apple.stomp.reconnect.delayTime between reconnect attempts to StompBrokerRelay in msec5000
HuaweiSender
sender.config.proxy.hostproxy-server host for outgoing connectionsnull
sender.config.proxy.portproxy-server port for outgoing connections0
sender.config.proxy.usernameproxy-server usernamenull
sender.config.proxy.passswordproxy-server passwordnull
stomp.broker.relay.addressStompBrokerRelay addresslocalhost:8081
huawei.cache.credentials.capacitycredential settings cache initial size10
huawei.cache.credentials.ttlTTL for credential settings cache in minutes1
huawei.poolexecutor.poolsizeInitial outgoing connections count10
huawei.poolexecutor.maxpoolsizeMax outgoing connections count30
huawei.stomp.reconnect.delayTime between reconnect attempts to StompBrokerRelay in msec5000
Payloader
server.portWeb server port for Payloader8080
spring.redis.hostRedis hostlocalhost
spring.redis.portRedis port49153
redis.ttlTTL for Redis cache in days1
stomp.broker.relay.addressStompBrokerRelay addresslocalhost:8081
payloader.stomp.reconnect.delayTime between reconnect attempts to StompBrokerRelay in msec5000
Callbacker
stomp.broker.relay.addressStompBrokerRelay addresslocalhost:8081
callbacker.stomp.reconnect.delayTime between reconnect attempts to StompBrokerRelay in msec5000
callbacker.poolexecutor.poolsizeInitial outgoing connections count10
callbacker.poolexecutor.maxpoolsizeMax outgoing connections count30

Config directory

PC Pusher tries to find config files on following directories in provided order:

  • /opt/wildfly/pc_pusher,
  • /opt/pc/pc_pusher,
  • C:\pc\pc_pusher,
  • C:\wildfly\pc_pusher

In case config is found - directory with config will be path_to_config

Mobile Apps Credentials

Credentials for PC Pusher 5.2 API

Credential File Sample

{
  "android": {
    "google_api_key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  },
  "ios": {
    "apns_p8": {
      "use_dev_gate": false,
      "apns_key_id": "xxxxxxxxxxx",
      "apns_team_id": "xxxxxxxxxx",
      "apns_key": "-----BEGIN PRIVATE KEY-----\nxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxx\nxxxxxxxxxxx\nxxxxxxxxxx\n-----END PRIVATE KEY-----"
    }
  },
  "huawei": {
    "client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "client_id": "xxxxxxxxx"
  }
}

PC Pusher has to know cloud-services credentials to send push.

PC Pusher has built-in credentials to work with PayControl and PayConfirm mobile apps via PC Pusher 5.2 API.

Credentials are managed by AppleSender, AndroidSender and HuaweiSender microservices.

To specify app credentials for you app, do the following:

  1. Create file with credentials: {{app_id}}.json, where app_id is bundle-id/package-id of your mobile app
  2. Fullfill credentials with structure like in the sample in code area
  3. Place credentials file to credentials config directory {{path_to_config}}/apps/{{app_id}}.json

Credentials for PC Inform 2.0 API

Credential File Sample

{
  "android": {
    "google_api_key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  },
  "ios": {
    "apns_p8": {
      "use_dev_gate": false,
      "apns_key_id": "xxxxxxxxxxx",
      "apns_team_id": "xxxxxxxxxx",
      "apns_key": "-----BEGIN PRIVATE KEY-----\nxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxx\nxxxxxxxxxxx\nxxxxxxxxxx\n-----END PRIVATE KEY-----",
      "bundle":"**.********.**********"
    }
  },
  "huawei": {
    "client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "client_id": "xxxxxxxxx"
  }
}

PC Inform 2.0 API doesn't specify mobile app id (bundle-id or package-id) to send push.
That's why in case you use PC Inform 2.0 API credentials has to comply following:

  • credentials MUST be specified in {{path_to_config}}/apps/defualt.json
  • credentials MUST contain ios.apns_p8.bundle value, becuase of APNS requires to specify bundle-id to send push

Push Templates (for PC Pusher 5.2 API)

Templates File Sample

{
  "android": {
    "templates": {
      "transaction": [
        {
          "to": "%DEVICE_TOKEN%",
          "notification": {
            "tag": "%USER_ID%",
            "title": "There is new transaction to confirm",
            "body": "You have non-confirmed transactions",
            "icon": "paycontrol_push",
            "sound": "default"
          },
          "data": {
            "type": "PayControl_v2"
          }
        },
        {
          "to": "%DEVICE_TOKEN%",
          "data": {
            "type": "PayControl_v2",
            "userid": "%USER_ID%",
            "transactionid": "%TRANSACTION_ID%"
          }
        }
      ]
    }
  },
  "ios": {
    "templates": {
      "ios_to_fcm" : false,
      "transaction": [
        {
          "aps": {
            "alert": "There is new transaction to confirm",
            "sound": "default",
            "badge": 1,
            "mutable-content": 1,
            "category": "NEW_OPERATION"
          },
          "type": "PayControl",
          "userid": "%USER_ID%",
          "transactionid": "%TRANSACTION_ID%",
          "pc_notification_type": "alert",
          "pc_notification_priority": 10,
          "pc_notification_timeout": 600,
          "pc_collapse_id": "%USER_ID%"
        }
      ]
    }
  },
  "huawei": {
    "templates": {
      "transaction": [
        {
          "validate_only": false,
          "message": {
            "android": {
              "notification": {
                "tag": "%USER_ID%",
                "title": "There is new transaction to confirm",
                "body": "You have non-confirmed transactions",
                "icon": "paycontrol_push",
                "click_action": {
                  "type": 3
                }
              }
            },
            "token": [
              "%DEVICE_TOKEN%"
            ]
          }
        },
        {
          "validate_only": false,
          "message": {
            "android": {
              "collapse_key": -1,
              "urgency": "HIGH",
              "ttl": "86400",
              "data": "{\"type\": \"PayControl_v2\",\n\"userid\": \"%USER_ID%\",\"transactionid\": \"%TRANSACTION_ID%\"}"
            },
            "token": [
              "%DEVICE_TOKEN%"
            ]
          }
        }
      ]
    }
  }
}

PC Pusher has built-in push templates to work with PayControl and PayConfirm mobile apps (version 5.x).

In case you use PC Pusher API, you can configure your own push templates and credentials.

Templates are managed by PushReceiver microservice.

To use your own push templates, do the following:

  1. Create file with templates: {{system_id}}.json, where system_id is PC Server system-id (specified in send-push-request)
  2. Fullfill push templates with structure like the in sample in code area
  3. Place templates file to templates config directory {{path_to_config}}/systems/{{system_id}}.json