2021-09-29 @이영훈
GCP Cloud Function과 Pub/Sub을 연동해서 FCM (Firebase Cloud Messaging) 사용하는 방법을 기록으로 남깁니다
대용량 FCM 메시지 보내기 위해 PubSub을 GCP로 구현한 두번째 내용입니다
1. Pub/Sub과 연동된 Cloud Function 생성
a.
함수 이름과 GCP Pub/Sub의 topic을 선택하고 NEXT를 선택합니다
2. Cloud Function 언어 선택
a.
.NET, Go, Java, Node, Python, PHP, Ruby 가 가능합니다
b.
저는 개인적으로 가볍고 이식성이 좋은 언어로 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 활성화
Shell
복사
# install firebase admin package
pip install firebase-admin
Shell
복사
4. firebase service account를 다운로드 받습니다
a.
GCP에서 인증하는 방식은 여러가지 입니다
b.
저는 그 중에서 service account 키 파일을 이용해서 인증을 했습니다
c.
Firebase Console > 프로젝트 설정 > 서비스 계정 > 새 비공개 키 생성
d.
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)
....
Python
복사
5. main.py 코드 작성
1.
entrypoint 함수의 첫번째 파라미터 event의 data 필드에는 base64로 인코딩된 PubSub Message가 있습니다
2.
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
Python
복사
6. requirements.txt 작성
pip freeze > requirements.txt
Shell
복사
생성된 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
Python
복사
7. Cloud Function을 설정합니다
a.
Entry point는 entrypoint 로 함수로 설정합니다
b.
main.py는 위에서 작성한 main.py 를 복붙합니다
c.
requirements.txt도 requirements.txt 파일을 복붙합니다
d.
sample-project-5d15z-firebase-adminsdk-gabge-4fa79ee667.json 을 생성합니다
•
[과정4]에서 다운로드 받은 service account key 파일을 root 경로에 복사합니다
•
main.py 코드에서 동일한 디렉토리에 key 파일을 검색하기 때문에 root 경로에 파일을 만들어줍니다