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

#完成デモ
https://twitter.com/inoue2002/status/1387071683828207618?s=20

#抱えてた課題

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

▼Lambdaで怒られてる画像
<img src='https://scrapbox.io/files/6087d3b0860e200022563152.png' />

▼参考にしたサイト
[Node.jsでQRコードを読み込む](https://qiita.com/n0bisuke/items/78faeaeef59df716d7cf)

#解決策
LINEから送られてきた画像を取得し、[jimp](https://www.npmjs.com/package/jimp)と[qrcode-reader](https://www.npmjs.com/package/qrcode-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;
};

```

#リポジトリ
https://github.com/inoue2002/qrcode-reader-linebot
#lambda版も作った
https://github.com/inoue2002/qrcode-reader-linebot/blob/main/lambda.js

#おわりに
ずっと悩んでたことが解決できてよかった！！
[ここもよかったら参考にどうぞ](https://scrapbox.io/inouenote/qrcode%E3%82%92node%E3%81%A8Lambda%E3%81%A7%E8%A7%A3%E6%9E%90%E3%81%99%E3%82%8B
)