Skip to content

Commit

Permalink
Merge pull request #980 from shankari/migrate_to_new_api
Browse files Browse the repository at this point in the history
Migrate to the new FCM HTTP v1 API
  • Loading branch information
shankari authored Sep 12, 2024
2 parents de250e7 + 5a8ca40 commit 802640c
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 20 deletions.
4 changes: 3 additions & 1 deletion conf/net/ext_service/push.json.sample
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
"provider": "firebase",
"server_auth_token": "Get from firebase console",
"app_package_name": "full package name from config.xml. e.g. edu.berkeley.eecs.emission or edu.berkeley.eecs.embase. Defaults to edu.berkeley.eecs.embase",
"ios_token_format": "fcm"
"ios_token_format": "fcm",
"project_id": "Get from the General project settings (https://console.cloud.google.com/project/_/settings/general/) tab of the Firebase console.",
"service_account_file": "Download according to the instructions at https://firebase.google.com/docs/cloud-messaging/migrate-v1#provide-credentials-manually and put the path to the file here"
}
3 changes: 2 additions & 1 deletion emission/net/ext_service/push/notify_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

push_config = ecbc.get_config('conf/net/ext_service/push.json',
{"PUSH_PROVIDER": "provider", "PUSH_SERVER_AUTH_TOKEN": "server_auth_token",
"PUSH_APP_PACKAGE_NAME": "app_package_name", "PUSH_IOS_TOKEN_FORMAT": "ios_token_format"})
"PUSH_APP_PACKAGE_NAME": "app_package_name", "PUSH_IOS_TOKEN_FORMAT": "ios_token_format",
"PUSH_PROJECT_ID": "project_id", "PUSH_SERVICE_ACCOUNT_FILE": "service_account_file"})

try:
logging.warning(f"Push configured for app {push_config.get('PUSH_APP_PACKAGE_NAME')} using platform {push_config.get('PUSH_PROVIDER')} with token {push_config.get('PUSH_SERVER_AUTH_TOKEN')[:10]}... of length {len(push_config.get('PUSH_SERVER_AUTH_TOKEN'))}")
Expand Down
65 changes: 48 additions & 17 deletions emission/net/ext_service/push/notify_interface_impl/firebase.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import requests
import copy
import time
import pyfcm

# Our imports
import emission.core.get_database as edb
Expand All @@ -21,7 +22,8 @@ def get_interface(push_config):

class FirebasePush(pni.NotifyInterface):
def __init__(self, push_config):
self.server_auth_token = push_config.get("PUSH_SERVER_AUTH_TOKEN")
self.service_account_file = push_config.get("PUSH_SERVICE_ACCOUNT_FILE")
self.project_id = push_config.get("PUSH_PROJECT_ID")
if "PUSH_APP_PACKAGE_NAME" in push_config:
self.app_package_name = push_config.get("PUSH_APP_PACKAGE_NAME")
else:
Expand All @@ -33,6 +35,30 @@ def get_and_invalidate_entries(self):
# Need to figure out how to do this on firebase
pass

def notify_multiple_devices(self, push_service, fcm_token_list,
notification_title=None, notification_body=None, data_payload=None):
results = {}
n_success = 0
n_failure = 0
for t in fcm_token_list:
trunc_t = t[:10]
try:
result = push_service.notify(fcm_token=t,
notification_title=notification_title,
notification_body=notification_body,
data_payload=data_payload)
results.update({trunc_t: result['name']})
n_success = n_success + 1
print("Successfully sent to %s..." % (trunc_t))
except (pyfcm.errors.FCMNotRegisteredError, pyfcm.errors.InvalidDataError) as e:
results.update({trunc_t: str(e)})
n_failure = n_failure + 1
print("Found error %s while sending to token %s... skipping" % (e, trunc_t))
response = {"success": n_success, "failure": n_failure, "results": results}
print(response)
logging.debug(response)
return response

@staticmethod
def print_dev_flag_warning():
logging.warning("dev flag is ignored for firebase, since the API does not distinguish between production and dev")
Expand Down Expand Up @@ -128,20 +154,22 @@ def send_visible_notification(self, token_map, title, message, json_data, dev=Fa
# convert tokens if necessary
fcm_token_map = self.convert_to_fcm_if_necessary(token_map, dev)

push_service = FCMNotification(api_key=self.server_auth_token)
data_message = {
"data": json_data,
"payload": json_data
}
push_service = FCMNotification(
service_account_file=self.service_account_file,
project_id=self.project_id)
# Send android and iOS messages separately because they have slightly
# different formats
# https://github.com/e-mission/e-mission-server/issues/564#issuecomment-360720598
android_response = push_service.notify_multiple_devices(registration_ids=fcm_token_map["android"],
data_message=data_message)
ios_response = push_service.notify_multiple_devices(registration_ids=fcm_token_map["ios"],
message_body = message,
message_title = title,
data_message=data_message)
android_response = self.notify_multiple_devices(push_service,
fcm_token_map["android"],
notification_body = message,
notification_title = title,
data_payload = json_data)
ios_response = self.notify_multiple_devices(push_service,
fcm_token_map["ios"],
notification_body = message,
notification_title = title,
data_payload = json_data)
combo_response = {"ios": ios_response, "android": android_response}
logging.debug(combo_response)
return combo_response
Expand All @@ -155,20 +183,23 @@ def send_silent_notification(self, token_map, json_data, dev=False):
# multiplying by 10^6 gives us the maximum resolution possible while still
# being not a float. Have to see if that is too big.
# Hopefully we will never send a push notification a millisecond to a single phone
ios_raw_data.update({"notId": int(time.time() * 10**6)})
ios_raw_data.update({"notId": str(int(time.time() * 10**6))})
ios_raw_data.update({"payload": ios_raw_data["notId"]})

push_service = FCMNotification(api_key=self.server_auth_token)
push_service = FCMNotification(
service_account_file=self.service_account_file,
project_id=self.project_id)

# convert tokens if necessary
fcm_token_map = self.convert_to_fcm_if_necessary(token_map, dev)

response = {}
response["ios"] = push_service.notify_multiple_devices(registration_ids=fcm_token_map["ios"],
data_message=ios_raw_data,
content_available=True)
response["ios"] = self.notify_multiple_devices(push_service,
fcm_token_map["ios"], data_payload=ios_raw_data)

response["android"] = {"success": "skipped", "failure": "skipped",
"results": "skipped"}
print(response)
logging.debug(response)
return response

Expand Down
2 changes: 1 addition & 1 deletion setup/environment36.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dependencies:
- utm=0.7.0
- pip:
- git+https://github.com/JGreenlee/[email protected]
- pyfcm==1.5.4
- pyfcm==2.0.1
- pygeocoder==1.2.5
- pymongo==4.3.3
- pykov==0.1
Expand Down

0 comments on commit 802640c

Please sign in to comment.