LINEのbotを作ると、記述が冗長になったり条件分岐が多すぎたりしたので、クラスにして簡単に書けるようにしました。
ソースコード
おうむ返しbotを作成します。const client = new Client_("ACCESS_TOKEN");
client.on("message",event => {
const text = event.message.text;
event.reply(text);
});
function doPost(e){
const data = JSON.parse(e.postData.contents);
client.run(data);
}
完成しました。(1分)
ただし、これではClient_が定義されていないので、次のソースコードをコピペしてください。
クラスの用意
class Client_{
constructor(ACCESS_TOKEN){
this.token = ACCESS_TOKEN;
this.users = new UserManager_(this);
this.followers = new FollowerManger(this);
this.https = HttpsRequest_(this);
this.functions = {};
}
on(type,func){
const arr = this.functions[type] || [];
arr.push(func);
}
onFailed(func){ //funcの引数は、event,err
this.failedHandler = func;
}
run(data){
const [events] = data.events;
this.functions[events.type].forEach(f => {
try{
f(new Events_(events,this));
}catch(err){
this.failedHandler(events,err);
}
});
}
}
class FollowerManger{
constructor(client){
this.client = client;
}
/**
*
* @param {string} userId
* @returns {User_}
*/
fetch(userId){
const endpoint = "https://api.line.me/v2/bot/profile/" + userId;
const userdata = this.client.https.get(endpoint);
// {
// "displayName": "LINE taro",
// "userId": "U4af4980629...",
// "language": "en",
// "pictureUrl": "https://obs.line-apps.com/...",
// "statusMessage": "Hello, LINE!"
// }
return new User_(client,userdata);
}
/**
*
* @param {object} {limit,start}
*/
getAllFollowers({limit,start}){
const endpoint = "https://api.line.me/v2/bot/followers/ids";
const requestUrl = new URLSearchParams(endpoint).setParams({limit,start}).toString();
return this.client.https.get(requestUrl);
// {
// "userIds": ["U4af4980629...", "U0c229f96c4...", "U95afb1d4df..."],
// "next": "yANU9IA..."
// }
}
}
class UserManager_{
constructor(client){
this.client = client;
}
/**
*
* @param {string} userId
* @returns {User_}
*/
fetch(userId){
const endpoint = "https://api.line.me/v2/bot/profile/" + userId;
const userdata = this.client.https.get(endpoint);
// {
// "displayName": "LINE taro",
// "userId": "U4af4980629...",
// "language": "en",
// "pictureUrl": "https://obs.line-apps.com/...",
// "statusMessage": "Hello, LINE!"
// }
return new User_(this.client,userdata);
}
}
class User_{
/**
*
* @param {Client_} client
* @param {JSON} userdata
*/
constructor(client,userdata){
this.displayName = userdata.displayName;
this.userId = userdata.userId;
this.language = userdata.language;
this.pictureUrl = userdata.pictureUrl;
this.statusMessage = userdata.statusMessage;
this.client = client;
}
updateInfo(){
const endpoint = "https://api.line.me/v2/bot/profile/" + this.userId;
const userdata = this.client.https.get(endpoint);
return new User_(this.client,userdata);
}
toString(){
return `<m userId="${this.userId}">`
}
}
class Events_{
constructor(events,client){
this.client = client;
this.rawdata = events;
this.type = events.type;
this.replyToken = events.replyToken;
this.source = new User_(client,events.source);
this.timestamp= events.timestamp;
this.message = events.message;
this.postback = events.postback;
this.follow = events.follow;
}
reply(messages){
if(typeof messages === "string"){
messages = {
type : "text",
text : messages
};
}
if(!Array.isArray(messages)){
messages = [messages];
}
const endpoint = "https://api.line.me/v2/bot/message/reply";
const payload= {
messages : messages,
replyToken: this.replyToken
};
this.client.post(endpoint,payload)
}
}
class HttpsRequest_{
constructor(client){
this.client = client
}
/**
*
* @param {string} url
* @param {object} params
* @returns {JSON}
*/
get(url,params){
const requestUrl = new URLSearchParams(url).setParams(params).toString();
const options = {
method: 'get',
contentType: 'application/json',
headers: {
Authorization: 'Bearer ' + this.client.token
}
};
const result = UrlFetchApp.fetch(requestUrl,options).getContentText();
return JSON.parse(result);
}
/**
*
* @param {string} url
* @param {object} payload
*/
post(url,payload){
const options = {
method: 'post',
contentType: 'application/json',
headers: {
Authorization: 'Bearer ' + this.client.token
},
payload: JSON.stringify(payload)
};
const result = UrlFetchApp.fetch(url,options).getContentText();
return JSON.parse(result);
}
}
class URLSearchParams{
constructor(url){
this.originUrl = url.split("?")?.[0];
this.param = url.split("?")?.[1] || "";
}
setParams(obj){
this.param = Object.entries(obj).filter(arr => arr[1]).map(arr => arr.join("=")).join("&");
}
toString(){
return this.originUrl + "?" + this.param;
}
}
(記法はdiscord.jsリスペクトです。)
使い方(簡易)
詳細は次回以降に回します。//メイン
const client = new Client_("ACCESS_TOKEN");
function doPost(e){
const data = JSON.parse(e.postData.contents);
client.run(data);
}
//メッセージイベントハンドラのセット。
client.on("message",event => {
//eventは、e.postData.contents.events[0]とほぼ同等。
const text = event.message.text; //"こんにちは"
//rawdataはevent.rawdata。doPostで受け取ったJSONがそのまま入っている
//replyメソッドでquick-replyが可能。
event.reply(text);
});
//以下の内容と同等の処理をしている。
function doPost(e){
const data = JSON.parse(e.postData.contents);
const event = data.events[0];
if(event.type !== "message") return;
const text = event.message.text;
const replyToken = event.replyToken;
UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + ACCESS_TOKEN,
},
'method': 'post',
'payload': JSON.stringify({
'replyToken': replyToken,
'messages': [{
'type': 'text',
'text': text,
}]
})
});
}
//フォローイベント
client.on("follow",event => {});
//アンフォローイベント
client.on("unfollow",event => {});
//postbackイベント
client.on("postback",event => {});
//その他イベントも同様に記述可能。
//失敗時のハンドラ
client.onFailed((event,err) => {})
//ユーザー取得
client.users.fetch("U4af4980629...");
//友達ID取得
client.followers.getAllFollowers({limit,start});
//メンション
client.on("follow",event => {
const user = event.source; /**@type {User_} */
const message = "登録ありがとうございます!";
event.reply(user.toString() + message); //メンションつきメッセージ
})
//その他、Access tokenが必要なLINEのAPIを叩くとき
//get
client.https.get("url",{param1 : value1});
//post
const payload = {};
client.https.post("url",payload);