LoginSignup
1
1

More than 3 years have passed since last update.

【AWS;Lambda入門】第三弾;Linebotなじゃんけんゲームで遊ぶ♬

Last updated at Posted at 2020-06-27

今回は、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からコピペして設定します。

index.js
"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に張り付ける
これで、動きました。
さて、張り付けるコードは以下のじゃんけんゲームです。

じゃんけんゲームのコード

index.js
"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でのじゃんけんゲームのコード

index.js
"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で連携して遊んでみた
・ちょっとした拡張として、じゃんけんゲームを作成してみた

・利用性の高いアプリを作ってみようと思う

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1