はじめに
LINE Bot Serverを作ってみる その2のつづきです。
前回開設の途中で終わったdispatchMessageEventの部分からです。
サンプルの全ソースコードはこちらです
https://github.com/bathtimefish/line-bot-server-example
Message Eventを判別する
export const dispatchMessageEvent = async (event: line.MessageEvent): Promise<(Promise<line.MessageAPIResponseBase> | undefined)[]> => {
let result = undefined;
const replyToken: string = event.replyToken; // message event has a reply token
let textEventMessage: line.TextEventMessage;
let imageEventMessage: line.ImageEventMessage;
let imageUrl: string;
switch (event.message.type) {
case 'text':
/* Text Event Message用の処理 */
break;
case 'image':
/* Image Event Message用の処理 */
break;
}
LINE Platformから送信されるメッセージタイプは複数あります。イベントはmessage.type
を持っているので上記の処理ではswitch文で評価しメッセージタイプを識別しています。このコードはサンプルのためTextEventMessage
とImageEventMessage
のみを判別しています。その他のイベントを処理するにはこのswitch文を拡張することで対応できます
イベントメッセージタイプは現時点で他にFileEventMessage
、AudioEventMessage
、VideoEventMessage
、StickerEventMessage
、LocationEventMessage
がありそれぞれにTypeScriptの型定義が提供されています
また、イベントはreplyToken
を持ちます。replyToken
は返信用のメッセージトークンで受信したメッセージイベントに対してメッセージを返信するために使用します
テキストメッセージを返信する
switch (event.message.type) {
case 'text':
textEventMessage = {
type: 'text',
id: event.message.id,
text: event.message.text,
};
result = client.replyMessage(
replyToken,
textEventMessage,
);
break;
TextEventMessageを受信した場合の処理を記述しています。このサンプルでは受信したメッセージのテキストをそのまま返信するようにしています。いわゆるオウム返しです。返信には上記のようにTextEventMessageを作成しreplyTokenと合わせてreplyMessageで返信します。
画像メッセージを処理する
case 'image':
imageEventMessage = {
type: 'image',
contentProvider: event.message.contentProvider,
id: event.message.id,
}
imageUrl = await downloadImageContent(imageEventMessage);
textEventMessage = {
type: 'text',
id: event.message.id,
text: imageUrl,
};
result = client.replyMessage(
replyToken,
textEventMessage,
);
break;
ImageEventMessageの場合、送信されるメッセージデータに画像データそのものが載ってくるわけではありません。イベントメッセージのid
に対応する画像データをダウンロードする処理を記述する必要があります。LINE Messaging API SDKにはデータをダウンロードするためのmethodが用意されています。処理を順に見ていきましょう
上記ではまず、受信したイベントを元にImageEventMessage
を作成し、downloadImageContentに渡しています
const downloadImageContent = async (imageEventMessage: line.ImageEventMessage): Promise<string> => {
const exp = 'jpg';
const downloadPath= path.join(__dirname, '../public', 'downloaded', `${imageEventMessage.id}.${exp}`);
const messageId = await downloadContent(imageEventMessage.id, downloadPath);
const imageUrl = `${config.baseUrl}/downloaded/${messageId}.${exp}`;
return imageUrl;
};
ここではサーバー上に画像データを保存するパスを用意したあとdownloadContentにidを渡して用意したパスに画像データをダウンロードして保存します。正常に保存されたら画像にアクセスできるURLを作成して返しています
const downloadContent = async (messageId: string, downloadPath: string): Promise<string> => {
const stream = await client.getMessageContent(messageId);
return new Promise((resolve, reject) => {
const writable = fs.createWriteStream(downloadPath);
stream.pipe(writable);
stream.on('end', () => { resolve(messageId); });
stream.on('error', () => { reject(); });
});
};
downloadContent
でLINE Platformから画像データをダウンロードして保存しています。getMessageContentがそれです。getMessageContentはPromise<internal.Readable>
を返します。このReadble Streamをfs.createWriteStreamを使って指定のパスにファイルとして保存しています
imageUrl = await downloadImageContent(imageEventMessage);
textEventMessage = {
type: 'text',
id: event.message.id,
text: imageUrl,
};
result = client.replyMessage(
replyToken,
textEventMessage,
);
break;
dispatchMessageEvent
に戻って読むとdownloadImageContent
が返す画像のURLをTextEventMessage
として返信しています。LINEアプリで画像をアップすると画像のURLが返ってくる仕組みになります。
以上がdispatchMessageEvent
でやっていることです
おわりに
今回はサンプルBotサーバーの心臓部である部分のコードを解説しました。その他のコードはWebサーバーの基本機能部分ですので説明を割愛します
これで「[LINE Bot 開発入門] LINE Bot Serverを作ってみる」の連載は終わりです。この記事でLINE Bot サーバーのコードレベルでの基本的な仕組みを理解いただければ幸いです。おつかれさまでした!