標籤

Notify

Day9 - SQS 串接 Notify 實作!

首先先建立一個consumer/資料夾,新增__init__.py以及notify_handler.py

notify_handler.py輸入以下程式碼

import json
import requests


def line_notify_handler(event, context):
    print(event)
    body = json.loads(event['Records'][0]['body'])
    print(body)
    headers = {
        'Authorization': f"Bearer {body['token']}",
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    r = requests.post('https://notify-api.line.me/api/notify',
                      headers=headers,
                      data={'message': body['message']})
    print(r)

# AWS record sample
# {'Records': [{'messageId': 'fddc42ba-a122-4581-965e-d0144ac8a5ad', 'receiptHandle': 'AQEBjO32gY5pXOfOrmDR0hD4k1av9KyjbHFpc+rIBPV2Brif7Lo+jqnGevSjfFwlICyGf+BhWwKaxFw8XdB3QTzRbw0vnLURjnQeDSBrJHa/S57SRs9TOLRBq38maycAVg69iZbetg9VhLMBCcLtOtPHTzKkmo+/Sosm51WA5CzXK7A0rteikx6nxS1CUIpq6MAujodupP0Hgr5RjK5nH/nmxA4Db0leWEmLokalZbtlx4W14tp7PZxPOrQOLDaGrH//p4h32tY8IN3MkCqi+gyNT7kCU4KwCGOIrybb07ZWyKBTKw+KOMNr/Ykj4z2N1qxIvTM55UY9d8V29YsH32OjrZTei5P7Nke/51E2tWkmkqoFAlqzxDjQPvpP+Pvvr8aazeeZ6opkr59UefAiiyM71Q==', 'body': 'hi', 'attributes': {'ApproximateReceiveCount': '9', 'SentTimestamp': '1566621263072', 'SenderId': '901588721449', 'ApproximateFirstReceiveTimestamp': '1566621263072'}, 'messageAttributes': {}, 'md5OfBody': '49f68a5c8493ec2c0bf489821c21fc3b', 'eventSource': 'aws:sqs', 'eventSourceARN': 'arn:aws:sqs:us-east-1:901588721449:LINE_notify_consumer', 'awsRegion': 'us-east-1'}]}

接著在requirements.txt加入boto3,他是一個使用 python 介接 AWS 的套件

boto3==1.9.189

加入SQS_URL以及SQS_ARN.env裡面

SQS_URL=sqs url
SQS_ARN=your sqs arn

add controller/notify_sqs_controller.py

from flask_restful import Resource, reqparse
import json
from lib.db import Database
import psycopg2.extras
import os
import boto3


def send_message(url, attr, body, delay=0):
    cli.send_message(
        QueueUrl=url,
        DelaySeconds=0,
        MessageAttributes=attr,
        MessageBody=body,
    )


class SendNotifyBySQSController(Resource):
    cli = boto3.client("sqs", region_name=os.environ("region"))

    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument(
            'message', required=True, help='message can not be blank!')
        args = parser.parse_args()
        msg = args['message']
        with Database() as db, db.connect() as conn:
            with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
                cur.execute(
                    f"SELECT token FROM notify")
                fetch = cur.fetchall()
        for f in fetch:
            body = {
                'token': f"Bearer {f['token']}",
                'message': f"Hello everyone, {msg}"
            }
            cli.send_message(
                QueueUrl=os.environ("SQS_URL"),
                DelaySeconds=0,
                MessageAttributes={},
                MessageBody=json.dumps(body),
            )
        return {'result': 'ok'}, 200

程式寫完了就是要加一條路由/notify/sqs

from controller.notify_sqs_controller import SendNotifyBySQSController
api.add_resource(SendNotifyBySQSController, '/notify/sqs')

接著透過wsgi在本地起一個 server

sls wsgi serve

再搭配 postman 來做測試,測試內容如下

{
  "message": "test Content"
}

接著透過sls deploy部署上會遇到一個問題,會有 Access Denied,所以要在serverless.yml加入 IAM role 的設定

add iam in provider

iamRoleStatements:
  - Effect: Allow
    Action:
      - sqs:SendMessage
    Resource:
      - ${env:SQS_ARN}

測試

結論

使用 SQS 這類服務都會需要透過boto3來幫忙串接,最需要注意的就是 IAM role,因為在本地端的 key 通常權限都是最大的,但上到 AWS 上就會有權限的問題,所以要記得加入 IAM 哦!

Code is here

專案也會持續更新,更多詳情可以 follow 我的專案 aws-python-line-api

繼續閱讀

Day6 - 建立一個使用 Query string 來幫忙發送的 LINE Notify

繼上一篇我們已經可以讓使用者註冊 Notify 並將 token 放入資料庫,接著就帶各位使用 query string 的方式讓你的 Notify 可以送訊息給所有註冊過的 Notify。

首先我們進入我們已經建立過的 controller/notify_controller.py,會看到 class 下有我們之前建立的 post method,這時我們就在前面加入 get method,並加入以下的 code,讓這個 class 看起來比較有順序(潔癖)

from flask import request

class NotifyController(Resource):

    def get(self):
            msg = request.args.get('msg')
            with Database() as db, db.connect() as conn:
                with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
                    cur.execute(
                        f"SELECT token FROM notify")
                    fetch = cur.fetchall()
            for f in fetch:
                headers = {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Authorization': f"Bearer {f['token']}"
                }
                payload = {'message': msg}

                r = requests.post(
                    'https://notify-api.line.me/api/notify', data=payload, headers=headers)
            return {'result': 'ok'}, 200

    def post(self):
        ...

這次使用的套件比上次多 import 一個 flask 底下的 request (注意沒有 s 哦),這個主要是讓我們可以抓到網址問號後面接的參數,這邊我設定打 API 的人會打一個 msg 的參數。

接著就是使用進 DB 撈我們的 token 們,並用一個迴圈來跑

再來是設定 headers 以及 payload

headers 的部分參考 Notify 的文件,如下圖 我們需要設定 Content-Type 以及 Authorization,需要注意的是 Authorization 是使用 Bearer 格式(參考),他中間是有加空白鍵的,這邊很多朋友都會錯在這裡,千萬要記得檢查這邊!

接著是要送出去的東西是要用什麼送出,本篇只用 message 做範例,若需要使用到其他的功能,像是圖片、貼圖等等的可參考以下的圖片

接著我們就可以使用sls deploy來部署我們的程式啦

等等! 這邊有個需要注意的地方是,照著這次的範例使用的話會需要用 docker 來幫忙跑編譯,因為 psycopg2-binary 這個套件如果不是在 Linux 的環境下會需要透過 docker 幫忙編譯完再丟過去 這部分需要在serverless.yml下填入參數

custom:
  pythonRequirements:
    dockerizePip: true

如此一來當前環境若不是 Linux 的話他就會使用 docker 來幫忙,記得 docker 要開哦 🙏

當然最簡單的方法就是把它直接抓下來放在專案中,只是這樣就會比較髒一點,可以從這邊抓 -> 參考

這邊可以先在環境變數上加上SLS_DEBUG=* 接著在加上 sls deploy 後面加上--verbose可以看到 serverless 到底都在背地裡做了什麼事情 🤣

接著我們就使用 Postman 來幫我們送字串出去,參考下圖,當回傳 ok 就成功了 🎉 你的 Notify 應該要回你了~

結論

這邊帶大家做一個簡單的應用,一般來說我覺得放在 query string 讓其他 API 來呼叫的時候帶參數來就可以直接用是很方便的,不用再特地自己寫方法去呼叫 LINE Notify 來幫我們送,反正 AWS Lambda 有一百萬次的請求不怕 🤣

繼續閱讀

Day3 - LINE Notify 介紹

LINE Notify 顧名思義就是通知屬性的服務,這個服務不是 LINE 的 Message API,千外別把這兩個搞在一起哦!

在實作前要先認識一下在接的 api 服務原理 首先先參考LINE Notify 官網 開頭的介紹:

Overview: Becomes a provider based on OAuth2 (https://tools.ietf.org/html/rfc6749). The authentication method is authorization_code. The access token acquired here can only be used for notification services

不負責任翻譯: 這個服務是基於 OAuth2 實作的,授權模式(grant_type)是 authorization_code 參考 access_token 則是只能讓通知服務所使用的一個鑰匙

更詳細的流程可以參考 https://blog.yorkxin.org/2013/09/30/oauth2-4-1-auth-code-grant-flow.html

The host name for authentication API endpoint is notify-bot.line.me.

然後 API 的網址是 notify-bot.line.me

接著我們來看看流程圖 https://notify-bot.line.me/doc/en/

  • 當使用者拜訪你的網站時,會導向 LINE 請求認證
  • 認證過了之後會回傳一個名為 code 的參數
  • 接著網站需要持這個 code 在去找 LINE 討東西
  • 討成功後就會拿到一個 access_token
  • 網站就會知道這個 access_token = 來註冊的使用者
  • 然後就可以透過 access_token 發送通知給使用者了?

事前準備

首先就是要先加入他好友,如果之前有不小心封鎖的話要記得解除封鎖哦,不然後續會收不到消息。 https://ithelp.ithome.com.tw/upload/images/20190903/20111481Zno98NSHwL.png

下一篇會帶著時做出簡單的 index.html + 使用 Serverless 蓋我們第一個 API 來做認證。 會使用到 LINE Notify 的 API 為以下三個,不清楚裡面實際上功能的朋友可以嗑一下官網文件

GET https: //notify-bot.line.me/oauth/authorize -> 前往認證拿到 code 參數
POST https://notify-bot.line.me/oauth/token -> 拿 code 參數換 access_token
POST https://notify-api.line.me/api/notify -> 發送訊息

其他

今年中有帶著朝陽的學弟妹手把手實作 LINE Notify,如果只想自己用的話可以參考我之前簡報

LINE Notify 如何快速建置一個 LINE Notify 的服務

繼續閱讀