今回は、apigatewayを利用したnode.js@Lambdaでじゃんけんゲームを作ってみた。
環境構築やプログラムなどは、全て以下の参考①~④を参考に進めた。
だいたい、最初の①と②でLinebotが動く。そして③と④でLambda版のLinebotが動いた。筆者も言っているように感動ものである。
ちなみに、ほぼ1日でLinebotが動くようになった。
したがって、コードのほとんどは参考のまんまであることをお断りしておきます。
【参考】
①LINEBotをみんなで作ろう〜環境構築編〜【GWアドベントカレンダー1日目】
②LINEBotをみんなで作ろう〜おうむ返しbotを作ろう編〜【GWアドベントカレンダー3日目】
③LINEBotをみんなで作ろう〜レイヤーとAPIgateway設定編〜【GWアドベントカレンダー7日目】
④LINEBotをみんなで作ろう〜コードを実装編〜【GWアドベントカレンダー最終日】
ということで、この先のことも考えてじゃんけんゲームを作ってみた。
やったこと
・環境構築(Line)
・環境構築(Lambda@AWS)
・じゃんけんボット
・環境構築(Line)
参考①の解説のとおりで環境が構築出来ました。
LINE Developerのサイトにログインできるようにする。
- ログイン→開発者名、メール入力
- プロバイダーを作成→プロバイダー名;この下にボットを構築
- 新規チャネルを作成→Messaging APIを選択
- Messaging APIのチャンル作成する→ボット名、その他
- Botの設定→
- channel secret(短い方)とChannel access token (long-lived)(長い方)をアプリ側に設定、
- アプリの公開アドレスからWebhook URLを設定、
- BotのLINE Official Account featuresのeditから
- アカウント設定で応答設定;bot オン、
- あいさつ オフ、
- 応答メッセージ オフ、
- Webhook オン
おうむ返しボット
まず、自PC、Windows10でNode.jsを利用しておうむ返しボットを作ります。
ngrokをインストールする
Download & setup ngrokから自PCのOsにあったものをダウンロードして、解凍するとngrok.exeが入っているのでこれを実行すれば(ダブルクリックで)コンソールが動きました。そこで以下を実行すると実行できます。
※ちなみに、専用コンソールで実行してください。WindowsPromptだと動きませんでした
ngrok -v
ngrok version 2.3.35
node.js(v10以上推奨)をインストールする
node.js(v10以上推奨)ダウンロードからWindowsInstaller;node-v12.18.1-x64.msiをダウンロードして、インストール。
通常のコマンドラインで以下のように確認できる。
>node -v
v12.18.1
エディタ
使い慣れたjupyter notebookを使いました。
おうむ返しボットのnode.jsコード
以下のようにdesktop配下にDirを作って、そこで環境構築して作業します。参考にいろいろな拡張があって凄い記事になっていました。
【参考】
⑤1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest
cd deskTop
mkdir test-linebot
cd test-linebot
npm init -y
npm i @line/bot-sdk express
次にプログラムのメインとなるindex.jsをtest-linebotフォルダ内に作成します。
エディタで以下をコピペします。
上記のとおり、短い方と長い方をBotのBasic settingsとMessaging API settingsからコピペして設定します。
"use strict";
const express = require("express");
const line = require("@line/bot-sdk");
const PORT = process.env.PORT || 5000;
const config = {
channelSecret: "短い方",
channelAccessToken: "長い方"
};
const app = express();
app.post("/webhook", line.middleware(config), (req, res) => {
console.log(req.body.events);
Promise.all(req.body.events.map(handleEvent)).then((result) =>
res.json(result)
);
});
const client = new line.Client(config);
async function handleEvent(event) {
if (event.type !== "message" || event.message.type !== "text") {
return Promise.resolve(null);
};
let mes = { type: "text", text: event.message.text };
return client.replyMessage(event.replyToken, mes);
}
app.listen(PORT);
console.log(`Server running at ${PORT}`);
ここで、肝心な部分として、返信している文字列は
eventが以下のようなものなので、
event.message.text='動くかな😅'
となります。
{
type: 'message',
replyToken: '*******************************',
source: { userId: '*****************', type: '***' },
timestamp: **************,
mode: 'active',
message: { type: 'text', id: '*************', text: '動くかな😅' }
}
これで、Linebotを動かしてみます。
\Desktop\test-linebot>node index.js
Server running at 5000
この状態で、もう一個ターミナルを起動して、
ngrok http 5000
これで上記のindex.jsを公開します。
以下のような表示が出現します。以下は1時間37分ほど経過するとexpireするものになっています。
以下の表示からhttps://73e6916ab721.ngrok.io
というサイトからフォワードしていることが分かるので、ボットのWebhook URLとして、https://73e6916ab721.ngrok.io/webhook
とします。
※因みにこのサーバーは一意だと思いますが、毎回起動の度に変化します。また、Session Expiresの時間も長いとき(約7時間半)も短いとき(約1時間半)もバラバラです。
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Session Expires 1 hour, 37 minutes
Version 2.3.35
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://73e6916ab721.ngrok.io -> http://localhost:5000
Forwarding https://73e6916ab721.ngrok.io -> http://localhost:5000
これで動くと思います。動かなかったら、参考②や参考⑤を見てください。どちらもとても丁寧に書かれています。
出来ると、単なるおうむ返しですが、なんとなくうれしいです。
・環境構築(Lambda@AWS)
今度は、上記のindex.jsをLambdaで動作させApiGatewayを利用して、Linebotと連携します。
これも、参考③のとおりです。
・AWSアカウントでログイン;コンソールへ行く
・Lambdaを開く
・Lambda関数を作成・関数名(lamdbaTst)、ランタイムNode.Node.js 12js 12.x、ロール(基本的な...)等の設定
・コンソールに戻って、(検索して)API Gatewayを選択
・RestAPI 構築・REST・新しいAPI・API名;linebotAPI・エンドポイントタイプ;リージョン・APIの作成
・アクション・メソッドの作成・Post設定
・アクション;POSTセットアップ・Lambda関数・Lambdaプロキシ統合の使用;チェック・Lambda関数;lambdaTst・保存
・Lambda関数に権限を追加するダイアログ;OK
・アクション;POSTメソッドの実行・メソッドリクエスト・HTTPリクエストヘッダー・ヘッダー追加・名前欄にX-Line-Signatureと入力、必須にチェック
・アクション・APIのデプロイ・レイヤーの作成
・デプロイされるステージ;新しいステージ・ステージ名;test1・デプロイ
・Lambdaの関数の画面へ行き、関数にAPIGatewayが連携(追加)されていれば成功
・利用するNode.js環境をzipファイルにまとめて、レイヤーとして登録する・参考③はMac環境ですが、全く同じように作成します。
・cd Desktop・mkdir nodejs・npm init -y・npm i @line/bot-sdk・nodejsディレクトリをzip圧縮
・Lambda関数ページのレイヤーを開く・レイヤーの作成でnodejs.zipをアップロード。名前はそれらしい名前;linebot-SDK。・互換性のあるランタイムオプション;node.js 12,x node.js 10.x・作成
・Lambda関数ページのレイヤーを連携・レイヤーの追加・ランタイムと互換性のあるレイヤーのリストから選択・名前;linebot-SDK
・バージョン;1・追加
・関数画面でレイヤーで読み込めていたら(下に表示されたら)成功
・関数名をクリックして下へスクロール、環境変数の項目を探す、編集をクリック・編集・ACCESSTOKEN;長い方・CHANNELSECRET;短い方・保存
・Lambda関数をクリックして、関数を以下のコードをコピペして張り付ける。・右上の保存
・WEBhookURLを設定する・API Gatewayを押下・APIエンドポイントをコピペ・LinebotのWEBhookURLに張り付ける
これで、動きました。
さて、張り付けるコードは以下のじゃんけんゲームです。
じゃんけんゲームのコード
"use strict";
// モジュール呼び出し
const crypto = require("crypto");
const line = require("@line/bot-sdk");
// インスタンス生成
const client = new line.Client({ channelAccessToken: process.env.ACCESSTOKEN });
exports.handler = (event, context, callback) => {
// 署名検証
const signature = crypto
.createHmac("sha256", process.env.CHANNELSECRET)
.update(event.body)
.digest("base64");
const checkHeader = (event.headers || {})["X-Line-Signature"];
const body = JSON.parse(event.body);
const events = body.events;
console.log(events);
// 署名検証が成功した場合
if (signature === checkHeader) {
events.forEach(async (event) => {
let message;
// イベントタイプごとに関数を分ける
switch (event.type) {
// メッセージイベント
case "message":
message = await messageFunc(event);
break;
// フォローイベント
case "follow":
message = { type: "text", text: "追加ありがとうございます!" };
break;
// ポストバックイベント
case "postback":
message = await postbackFunc(event);
break;
}
// メッセージを返信
if (message != undefined) {
client
.replyMessage(body.events[0].replyToken, message)
.then((response) => {
const lambdaResponse = {
statusCode: 200,
headers: { "X-Line-Status": "OK" },
body: '{"result":"completed"}',
};
context.succeed(lambdaResponse);
})
.catch((err) => console.log(err));
}
});
}
// 署名検証に失敗した場合
else {
console.log("署名認証エラー");
}
};
const messageFunc = async function (event) {
var mes = await mesmakeFunc(event);
let message;
switch (event.message.type) {
case "text":
message= { type: "text", text: mes };
break;
case "image":
message = { type: "text", text: "がぞうを受け取ったよ!" };
break;
case "sticker":
message= { type: "text", text: "ステッカーを送ってくれたんだね!" };
break;
}
if (message !== undefined) {
return client.replyMessage(event.replyToken, message);
}
return message;
};
const mesmakeFunc = async function (event) {
console.log('event.text:', event.message.text);
var mes = ['グー','チョキ','パー',event.message.text];
var r = Math.floor( Math.random() * 4 );
var mes0 = mes[r];
console.log('message:',mes0);
return mes0;
};
const postbackFunc = async function (event) {
let message;
message = { type: "text", text: "ポストバックイベントを受け付けました!" };
return message;
};
自PCでのじゃんけんゲームのコード
"use strict";
const express = require("express");
const line = require("@line/bot-sdk");
const PORT = process.env.PORT || 5000;
const config = {
channelSecret: "短い方",
channelAccessToken: "長い方"
};
const app = express();
app.post("/webhook", line.middleware(config), (req, res) => {
console.log(req.body.events);
Promise.all(req.body.events.map(handleEvent)).then((result) =>
res.json(result)
);
});
const client = new line.Client(config);
async function handleEvent(event) {
if (event.type !== "message" ) {
return Promise.resolve(null);
};
let mes = await messageFunc(event);
console.log('mes_message:',mes);
return client.replyMessage(event.replyToken, mes);
};
const messageFunc = async function (event) {
var mes = await mesmakeFunc(event);
let message;
console.log('message_message:',event.message.type);
switch (event.message.type) {
case "text":
message= { type: "text", text: mes };
break;
case "image":
message = { type: "text", text: "がぞうを受け取ったよ!" };
console.log('image_message:',message);
break;
case "sticker":
message= { type: "text", text: "ステッカーを送ってくれたんだね!" };
console.log('sticker_message:',message);
break;
}
return message;
};
const mesmakeFunc = async function (event) {
console.log('event.text:', event.message.text);
var mes = ['グー','チョキ','パー',event.message.text];
var r = Math.floor( Math.random() * 4 );
var mes0 = mes[r];
console.log('message:',mes0);
return mes0;
};
app.listen(PORT);
console.log(`Server running at ${PORT}`);
まとめ
・Linebotを自PCとLambdaで連携して遊んでみた
・ちょっとした拡張として、じゃんけんゲームを作成してみた
・利用性の高いアプリを作ってみようと思う