LoginSignup
11
3

More than 1 year has passed since last update.

QRコードリーダーLINEBotを作る【nodejs】

Last updated at Posted at 2021-04-28

完成デモ

抱えてた課題

nodejsでQRコードを解析する場合、fsモジュールでプロジェクト配下に画像をダウンロードする必要がある。
AWS Lambdaでそれをやろうとすると、read onlyなのでダウンロードはできないと言われて困った。
S3なんかに画像をアップロードする手もあったかもしれないが、そこまでのことでもなかったので、解決策を探した。

▼Lambdaで怒られてる画像

▼参考にしたサイト
Node.jsでQRコードを読み込む

解決策

LINEから送られてきた画像を取得し、jimpqrcode-readerのモジュールを利用する

index.js
//Lambdaで動かす
"use strict";
// モジュール呼び出し
const crypto = require("crypto");
const line = require("@line/bot-sdk");
const QRReader = require("qrcode-reader");
const jimp = require("jimp");

// インスタンス生成
const client = new line.Client({ channelAccessToken: process.env.ACCESSTOKEN });

exports.handler = (event) => {
  let signature = crypto
    .createHmac("sha256", process.env.CHANNELSECRET)
    .update(event.body)
    .digest("base64");
  let checkHeader = (event.headers || {})["X-Line-Signature"];
  if (!checkHeader) {
    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 "postback":
          message = await postbackFunc(event);
          break;
        case "follow":
          message = { type: "text", text: "追加ありがとうございます!" };
          break;
      }
      // メッセージを返信
      if (message != undefined) {
        await sendFunc(body.events[0].replyToken, message);
        // .then(console.log)
        // .catch(console.log);
        return;
      }
    });
  }
  // 署名検証に失敗した場合
  else {
    console.log("署名認証エラー");
  }
};

async function sendFunc(replyToken, mes) {
  const result = new Promise(function (resolve, reject) {
    client.replyMessage(replyToken, mes).then((response) => {
      resolve("送信完了");
    });
  });
  return result;
}

async function messageFunc(event) {
  let message = "";
  message = { type: "text", text: `メッセージイベント` };
  if (event.message.type === "image") {
    const imageBuffer = await (() =>
      new Promise((resolve) => {
        client.getMessageContent(event.message.id).then((stream) => {
          const bufs = [];
          stream.on("data", (chunk) => {
            bufs.push(chunk);
          });
          stream.on("end", async () => {
            resolve(Buffer.concat(bufs));
          });
          stream.on("error", (err) => {
            // error handling
          });
        });
      }))();
    const img = await jimp.read(imageBuffer);
    const qr = new QRReader();
    const value = await new Promise((resolve, reject) => {
      qr.callback = (err, v) => (err != null ? reject(err) : resolve(v));
      qr.decode(img.bitmap);
    });
    message = { type: "text", text: `解析結果${value.result}` };
  }
  return message;
}
const postbackFunc = async function (event) {
  let message = "";
  message = { type: "text", text: "ポストバックイベント" };
  return message;
};

リポジトリ

lambda版も作った

おわりに

ずっと悩んでたことが解決できてよかった!!
ここもよかったら参考にどうぞ

11
3
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
11
3