개발
GCP Cloud Function으로 FCM 메시지 보내기 + Pub/Sub
mycloudy
2021. 9. 29. 18:02
GCP Cloud Function과 Pub/Sub을 연동해서 FCM (Firebase Cloud Messaging) 사용하는 방법을 기록으로 남깁니다
대용량 FCM 메시지 보내기 위해 PubSub을 GCP로 구현한 두번째 내용입니다
이전 글에서는 GCP Pub/Sub 만드는 내용을 다루었고 이번 내용은 GCP Cloud Function을 구현하는 내용입니다
모든 코드는 github에서 확인할 수 있습니다
github에 테스트 코드도 함께 작성해놓았습니다 본문에는 따로 기재를 하지 않았지만 함께 확인하시면 좋습니다
1. Pub/Sub과 연동된 Cloud Function 생성
- 함수 이름과 GCP Pub/Sub의 topic을 선택하고 NEXT를 선택합니다
2. Cloud Function 언어 선택
- .NET, Go, Java, Node, Python, PHP, Ruby 가 가능합니다
- 저는 개인적으로 가볍고 이식성이 좋은 언어로 AWS Lambda나 GCP Cloud Function을 짜는 것을 좋아합니다 그래서 Python, Node를 선호하고 이번에는 Python으로 선택했습니다
3. 파이썬 프로젝트를 생성하고 firebase admin sdk를 설치합니다
# initialize project
pyenv local 3.9.6 # python 3.9.6 버전으로 작업
python3 -m venv venv # virtual environment 생성
source venv/bin/activate # virtual environment 활성화
# install firebase admin package
pip install firebase-admin
4. firebase service account를 다운로드 받습니다
- GCP에서 인증하는 방식은 여러가지 입니다
- 저는 그 중에서 service account 키 파일을 이용해서 인증을 했습니다
- Firebase Console > 프로젝트 설정 > 서비스 계정 > 새 비공개 키 생성
- code snippet 입니다
# main.py
# code snippet
import firebase_admin
from firebase_admin import credentials
...
cred = credentials.Certificate("./pointberry-292606-firebase-adminsdk.json")
firebase_admin.initialize_app(cred)
....
5. main.py 코드 작성
- entrypoint 함수의 첫번째 파라미터 event의 data 필드에는 base64로 인코딩된 PubSub Message가 있습니다
- event를 디코딩한 뒤에 메시지 내용을 추출합니다
# main.py
import base64
import json
import logging
from enum import Enum
from typing import Optional
import firebase_admin
from firebase_admin import credentials
from firebase_admin import messaging
# https://cloud.google.com/functions/docs/calling/pubsub
def entrypoint(event: dict, context) -> str:
FIREBASE_ACCOUNT_SERVICE = "./sample-project-5d15z-firebase-adminsdk-gabge-4fa79ee667.json"
try:
cred = credentials.Certificate(FIREBASE_ACCOUNT_SERVICE)
firebase_admin.initialize_app(cred)
except ValueError: # The default Firebase app already exists. This means you called initialize_app() more than once
pass
logging.info("event: ", event)
print("event:", event)
data = json.loads(base64.b64decode(event['data']).decode('utf-8'))
push_type: str = data['pushType']
if push_type != PushType.SINGLE_MESSAGE.name:
print("Not supported message type", push_type)
device_token = data['deviceToken']
title: str = data['title']
body: str = data['body']
metadata: dict = data.get('data', None)
return send_one_data(device_token, title, body, metadata)
def send_one_data(device_token: str, title: str, body: str, data: Optional[dict]) -> str:
message = messaging.Message(
notification=messaging.Notification(title=title, body=body),
data=data,
token=device_token,
)
try:
response = messaging.send(message)
print("successfully Sent message:", response)
return f"successfully Sent message: {response}"
except firebase_admin._messaging_utils.UnregisteredError:
print(f"No such deviceToken: {device_token}")
return f"No such deviceToken: {device_token}"
except firebase_admin.exceptions.InvalidArgumentError:
return f"The registration token is not a valid FCM registration token: ${device_token}"
class PushType(Enum):
SINGLE_MESSAGE = 1
MULTIPLE_MESSAGE = 2
6. requirements.txt 작성
pip freeze > requirements.txt
생성된 requirements.txt 파일입니다
# requirements.txt
CacheControl==0.12.6
cachetools==4.2.2
certifi==2021.5.30
cffi==1.14.6
charset-normalizer==2.0.4
firebase-admin==5.0.1
google-api-core==1.31.1
google-api-python-client==2.15.0
google-auth==1.34.0
google-auth-httplib2==0.1.0
google-cloud-core==1.7.2
google-cloud-firestore==2.2.0
google-cloud-storage==1.41.1
google-crc32c==1.1.2
google-resumable-media==1.3.3
googleapis-common-protos==1.53.0
grpcio==1.39.0
httplib2==0.19.1
idna==3.2
msgpack==1.0.2
packaging==21.0
proto-plus==1.19.0
protobuf==3.17.3
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycparser==2.20
pyparsing==2.4.7
pytz==2021.1
requests==2.26.0
rsa==4.7.2
six==1.16.0
uritemplate==3.0.1
urllib3==1.26.6
7. Cloud Function을 설정합니다
- Entry point는
entrypoint
로 함수로 설정합니다 - main.py는 위에서 작성한
main.py
를 복붙합니다 - requirements.txt도 requirements.txt 파일을 복붙합니다
sample-project-5d15z-firebase-adminsdk-gabge-4fa79ee667.json
을 생성합니다
- [과정4]에서 다운로드 받은 service account key 파일을 root 경로에 복사합니다
- main.py 코드에서 동일한 디렉토리에 key 파일을 검색하기 때문에 root 경로에 파일을 만들어줍니다