前回の記事の続きです。
ゼロから始めるLINEBot(AWS×node.js)②オウム返しする
https://qiita.com/tenn25/items/498f768a58ba6a6de156
この記事で分かること
- LINEに投稿された画像をS3に保存する
この記事の対象者
- いろいろと初心者(自分がそうなので)
- MessagingAPIのような外部APIを使ったことがない
- AWSもあんま詳しくない(アカウントは持ってるくらい)
流れ
第1回 とりあえず動かす
1.LINE Developersの登録/設定
2.実装(Lambda/node.js)
3.定期実行の設定(CloudWatch)
第2回 オウム返しの実装
4.ドメイン取得,DNS設定,SSL証明書の設定(Route53/ACM/SNS/S3)
5.イベントの受け取り(APIGateWay)
6.ユーザへの返信(Lambda/node.js)
第3回 ユーザ情報や投稿画像の保存(この記事)
7.ストレージ(S3やDB)との連携
投稿画像の取得
投稿からS3保存までの流れは以下の通りです。
①ユーザがLINEに画像を投稿する。
②画像は一旦LINEサーバに保存され、WebHookによって、APIGateWayが叩かれる。
③APIGateWayの裏でLambdaが実行される。
④Lambdaの処理でLINEサーバへ画像を取得する。
⑤Lambdaの処理でS3に画像を保存する。
S3への保存ファイル名は「ユーザID/現在時刻.jpg」としようと思います。
LINEにメッセージが投稿されると、WebHookを通じてLambdaにリクエストが届きますが、
リクエストのevent.events[0].message.typeがimageであれば画像が投稿されたと判断できます。
画像は一旦LINE側のサーバに保存されているようなので、
https://api.line.me/v2/bot/message/{messageId}/content
に対してGETリクエストを投げる必要があります。
GETリクエストの結果をdataとしてバッファに流し込めばS3に転送できそうです。
var https = require('https');
var AWS = require('aws-sdk');
AWS.config.update({
accessKeyId: process.env.AWS_S3_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_S3_SECRET_ACCESS_KEY,
region: process.env.AWS_S3_REGION
});
exports.handler = (event, context, callback) => {
//リクエストを取得
event = event.events[0];
var replyToken = event.replyToken;
var message = event.message;
var userId = event.source.userId;
if(message.type === 'text'){
//テキストが投稿された場合の処理はこちら
}else if(message.type === 'image'){
//画像が投稿された場合の処理はこちら
var s3 = new AWS.S3();
var message_id = message.id;
//投稿された画像はmessage_idによって取得
var send_options = {
host: 'api.line.me',
path: '/v2/bot/message/'+ message_id +'/content',
headers: {
"Content-type": "application/json; charset=UTF-8",
"Authorization": " Bearer " + process.env.CHANNEL_ACCESS_TOKEN
},
method:'GET'
};
var data = [];
//LINEサーバに対してリクエストを投げると画像(data)が取得できるのでS3に保存する
var reqImg = https.request(send_options, function(res){
res.on('data', function(chunk){
data.push(new Buffer(chunk));
}).on('error', function(e){
console.log("ERROR: " + e.stack);
}).on('end', function(){
//ここらへんはPromiseで書いた方がいいかもしれない
//ファイル名として現在時刻を取得
var nowDate = new Date();
var nowTime = nowDate.getTime();
var params = {
Bucket: process.env.S3_BUCKET_NAME, // ←バケット名
Key: userId + '/' + nowTime + '.jpg', // ←バケットに保存するファイル名
Body: Buffer.concat(data)
};
s3.putObject(params, function(err, data) {
context.done();
});
});
});
reqImg.end();
}
};
node.jsの話になってしまいますが、
④Lambdaの処理でLINEサーバへ画像を取得する。
⑤Lambdaの処理でS3に画像を保存する。
このへんが非同期処理になってしまうため、
④が完了してから⑤が開始するようになんらか工夫する必要ああります。(上記の書き方かPromiseを使うなど)