radarbase/radar-appserver
General purpose application server for the radar platform.
10K+
General purpose application server for the radar platform currently with capability to schedule push notifications.
This is an app server which provides facilities to store app information (User related) and scheduling of push notifications using Firebase Cloud Messaging.
This is specifically developed to support the RADAR-Questionnaire application but can be easily extended or modified to suit the needs of different applications.
The app server provides REST endpoints to interact with the entities and data. For detailed info on the REST API please see the relevant section below. There is also support for legacy XMPP protocol for FCM.
First you will need to create a Firebase project for your application and add it to your app. This will give you access to all the Firebase services. Follow the instructions on the official docs according to your platform.
Configure the Server Key and Sender ID (obtained from FCM) in application.properties.
The AppServer needs a database to work. You can either use a stand-alone
instance of the database of use an in-memory embedded
instance-
3.1. To use the standalone instance, run the database a docker service by
```bash
docker-compose -f src/integrationTest/resources/docker/docker-compose.yml up -d hsqldb
```
This will start the database at `localhost:9001`
3.2. To use as an embedded in-memory database instance (Not recommended for production deployments), set the spring.datasource.url=jdbc:hsqldb:mem:/appserver
in application-<profile>.properties
. Also, change the properties in src/main/resources/application.properties
to dev or prod according to your requirements.
Build the project using gradle wrapper and run using spring boot. Note: This project uses JAVA 11, please download and install it before building.
The build will need to create a logs directory. The default path is /usr/local/var/lib/radar/appserver/logs
. Either create the directory there using sudo mkdir -p /usr/local/var/lib/radar/appserver/logs
followed by sudo chown $USER /usr/local/var/lib/radar/appserver/logs
or change logs file directory in src/main/resources/logback-spring.xml
to local log directory like <property name="LOGS" value="logs" />
There are 2 ways to communicate with the Firebase Cloud Messaging- XMPP and Admin SDK. At least one of these needs to be configured. To configure these, please look at the FCM section.
To run the build on mac or linux, run the below -
./gradlew bootRun
You can also run in an IDE (like IntelliJ Idea) by giving the /src/main/java/org/radarbase/appserver/AppserverApplication.java
as the main class.
The App-server is now connected to the FCM XMPP server and is able to send and receive messages. On your mobile application, try sending an upstream message using the FCM sdk for your platform. Notification scheduling parses payloads from upstream messages containing the action SCHEDULE. The format of the data payload of upstream message should contain at least-
{
"data":
{
"notificationTitle":"Schedule id 1",
"notificationMessage":"hello",
"action":"SCHEDULE",
"time":"1531482349791",
"subjectId":"test",
"projectID":"test",
"ttlSeconds":"900"
},
...
}
Voila!, you will now receive a notification at the schedule time (specified by time
in the payload) on your device.
You can also achieve the same using more reliable and flexible REST API using the schedule endpoint. Please refer to REST API section below for more info.
API documentation is available via Swagger UI when you launch the app server. Please refer to the Documentation section below.
The same result as stated in Getting Started can be achieved using REST endpoints of the AppServer.
Run the AppServer by following the first 3 steps in the Getting Started section.
Create a new Project by making a POST
request to the endpoint http://localhost:8080/projects
with the following body-
{
"projectId": "radar"
}
Create a new User in the Project by making a POST
request to the endpoint http://localhost:8080/project/test/users
with the following body-
{
"subjectId": "sub-1",
"fcmToken" : "get-this-from-the-device",
"enrolmentDate": "2019-07-29T00:00:00Z",
"timezone": 7200,
"language": "en"
}
Note: You will need to get the FCM token from the device and the app. Please see the setup info for your platform.
Add (and schedule) a notification for the above user by making a POST
request to the endpoint http://localhost:8080/project/test/users/sub-1/notifications
with the following body-
{
"title" : "Test Title",
"body": "Test Body",
"ttlSeconds": 86400,
"sourceId": "z",
"fcmMessageId": "12864132148",
"type": "ESM",
"sourceType": "aRMT",
"appPackage": "aRMT",
"scheduledTime": "2019-06-29T15:25:58.054Z"
}
Please update the scheduledTime
to the desired time of notification delivery.
You will now receive a notification at the scheduledTime
for the App and device associated with the FCM token for the user.
There are other features provided via the REST endpoints. These can be explored using swagger-ui. Please refer to Documentation section.
The FCM related code is provided in the org.radarbase.fcm
package. This can be explored in java-docs as mention in the Documentation section.
To use Firebase Cloud Messaging(FCM), you will need to configure the following properties -
Property | Description | Default | Required? |
---|---|---|---|
fcmserver.senderid | Sender ID from FCM. Can be found in the FCM project settings | NA | Yes |
fcmserver.serverkey | Server Key from FCM. Can be found in the FCM project settings | NA | Yes |
fcmserver.fcmsender | The Sender to use for sending messages. There is a choice of using XMPP or FCM Admin SDK. | org.radarbase.fcm.downstream.XmppFcmSender | No |
Note: Only sending messages via XMPP protocol supports Delivery Receipts on FCM.
To configure AdminSDK, follow the official Firebase documentation till you setup the enviroment variable. In the properties file, you would need to change fcmserver.fcmsender
to org.radarbase.fcm.downstream.AdminSdkFcmSender
and set fcmserver.xmpp.upstream.enable
to false
.
The AppServer is also available as a docker container. It's Dockerfile is provided with the project. It can be run as follows -
docker run -v /logs/:/var/log/radar/appserver/ \
-e "FCMSERVER_SENDERID=3487134635" \
-e "FCMSERVER_SERVERKEY=AAAA8wZuFjE:APA91bGpJQ3Sft0mZAaVMjDJGNLjFsdDLTo-37ZN69r4" \
radarbase/radar-appserver:0.0.1
The same can be achieved by running as a docker-compose service. Just specify the following in docker-compose.yml
file -
services:
appserver:
image: radarbase/radar-appserver:1.1.0
restart: always
ports:
- 8080:8080
volumes:
- ./radar_is.yml:/resources/radar_is.yml
- ./logs/:/var/log/radar/appserver/
environment:
JDK_JAVA_OPTIONS: -Xmx4G -Djava.security.egd=file:/dev/./urandom
FCMSERVER_SENDERID: "4562864135"
FCMSERVER_SERVERKEY: "AAAA8wZuFjE:APA91bGpJQ3Sft0mZAaVMjDJGN"
RADAR_ADMIN_USER: "radar"
RADAR_ADMIN_PASSWORD: "radar"
SPRING_APPLICATION_JSON: '{"spring":{"boot":{"admin":{"client":{"url":"http://spring-boot-admin:1111","username":"radar","password":"appserver"}}}}}'
RADAR_IS_CONFIG_LOCATION: "/resources/radar_is.yml"
SPRING_BOOT_ADMIN_CLIENT_INSTANCE_NAME: radar-appserver
An example docker-compose
file with all the other components is provided in integrationTest resources.
Here is a high level architecture and data flow diagram for the AppServer and its example interaction with a Cordova application (hybrid) like the RADAR-Questionnaire.
┌───────────────────┐ Downstream
│Device (Google Play│◀─────────────────────────────────Message .───────────.
│ Services/Apple │ │ _.─' `──.
│ IPNS) │ └───────────────────────────────────────,' `.
└────────▲────┬─────┴─────────────────────────────────────┐ ,' `.
│ │ │ ╱ ╲
│ │ XMPP ; :
│ │ Upstream │ Firebase Cloud Messaging │
.┴────▼─. Message───────────────────────────────────▶│ Service │
,' `. : ;
; Native Code : ╲ ╱
:(IOS/Android); ╲ ╱
╲ ╱ `. ,'│
`▲ ,' `. ,' │
│`─────│ ▲`──. _.─' │
│ │ │ `──▲──────'▲ │
│ │ │ │
│ │ │ ┃ ┃ │
│ │ │ XMPP │ Read
│ │ │ Connection ┃ Upstream
│──────▼. Send Message and
,─' '─. downstream ┃ ┃ Schedule
╱ Cordova FCM ╲ Message at message
; Plugin : Scheduled ┃ ┃ for future
: ; Time delivery
╲ ╱ │ ┃ ┃ │
╲ ╱ │ FCM Admin │
'─▲ ,─' │ ┃ SDK (Only │
│`─────'│ │ downstream │
│ │ │ ┃ messaging) │
│ │ │ │
│ │ │ ┃ ┃ │
│ │ │ │
│ │ ┌────┴───────▼───────┻───────▼────┐
│ │ │ │
┌─────┴───────▼─────────┐ │ │
│ │ ┌───────────────────────────────────▶ │
│ │ Schedule message │ │
│ │ for future delivery │ New App Server │
│ │ using HTTP REST │ │
│ ├───────────────────────────────────┘ │ (XMPP, HTTP Protocol) │
│ CORDOVA APPLICATION │ │ (REST API and FCM Admin SDK) │
│ │ Get confirmation of ─────────────────────────┤ │
│ ◀───────────────────────success for each request. │ │
│ │ │ │
│ │ ┌───────────────────────────────────▶ │
│ │ │ │ │
│ │ Get/Set user metrics, │ │
│ ├───────────────────schedule, notifications, etc │ │
│ │ │ │
│ │ More │ │
│ ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ functionality ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ▶ │
└───────────────────────┘ ..... └─────────────────────────────────┘
The Appserver manages the lifecycle of the Notifications through state change events. It uses Pub/Sub paradigm utilising Spring Events so other subscribers can also hook up to the Events as listeners. Currently, there are 10 possible states as follows -
// Database controlled
ADDED, UPDATED, CANCELLED
// Scheduler Controlled
SCHEDULED, EXECUTED
// Controlled by entities outside the appserver.
// These will need to be reported to the appserver.
DELIVERED, OPENED, DISMISSED
// Miscellaneous
ERRORED, UNKNOWN
REST Endpoints are provided to update and query the STATE. Update can only be made to any of the ones above that can be updated by external entities(i.e. DELIVERED, OPENED, DISMISSED, ERRORED and UNKNOWN ).
Here is a simple flow between the states --
┌───────────────────────────────────────────────────────┐
│ │
▼ │
.─────────────────. .─────────────────.
_.──' `───. _.──' `───.
╱ ╲ ╱ ╲
┌─────▶( SCHEDULED ) ─────────────────────▶( UPDATED )
│ `. ,────────────┐ `. ,'
│ `───. _.──' │ `───. _.──'
│ `───────────────' │ `───────────────'
┌─────────────────────────────────┐ │ │ │ │
│ │ │ │ │ │
│ ▼ │ │ │ │
┌───────────────┐ .──────────────────┘ │ │ │
│ │ _.──' `───. └────────┐ ┌───────────────│────────────────────────────┘
│ REST │ ╱ ╲ │ │ │
│ │────┐ ▲ ADDED )────┐ │ │ │
│ │ │ │`. ,' │ │ │ │
└───────────────┘ │ │ `───. _.──' │ ▼ ▼ │
▲ │ │ `───────────────' │ .─────────────────. │ .─────────────────.
┌─────────┘ │ │ │ _.──' `───. │ _.──' `───.
┌───┴─────┐ │ │ │ ╱ ╲ │ ╱ ╲
│ Request │ ┌────┼────┘ ├───▶( ERRORED ) └───────────▶( EXECUTED )
└─────────┴───┐ │ │ │ `. ,' `. ,'
▼ │ │ │ `───. ◀─────────┐ `───. _.──'
┌───────────────┤ │ │ `───────────────' │ `───────────────'
│ │ │ .─────────────────. │ ▲ │ │
│ │ │ _.──' `───. │ │ │ │
│ XMPP │ │ ╱ ╲ │ └──────────────────┼───────────────────────────┤
│ │ └────▶( CANCELLED )───┘ │
docker pull radarbase/radar-appserver