はじめに
これまで数多のMATLAB/LINE notifyに関する記事を書いてきた(2個)。しかしこれら(2個)の記事、まだまだ至らぬ点がある。
この記事ではこれらの課題を解決した上で、完全無欠なMATLAB x LINE Notifyモジュールを構築する。
環境
- Windows10 1909
- MATLAB R2020a
課題
まずは課題の列挙。
ではそれぞれ解決していこう。
解決編
これは2個目の記事のコードで発生する問題。以下の画像を見てほしい。
なんかいらん文字が入ってる(+とか=とか)。
これはMultipartFormProvider
の使い方が原因だった。MultipartFormProvider
の引数Parts
にはContentProvider
オブジェクトしか取れないものと思っていて、message
パラメータ(LINE notifyのパラメータ)にFormProvider
オブジェクトを渡していた。どうやら、FormProvider
は与えられた文字列とパラメータを=と+でくっつけてしまうらしい。
MultipartFormProvider
のドキュメントをよく読んでみると引数Parts
に「その他のタイプ」を取れるとあった。
なんだ、string
とかchar
も取れるじゃん。
というわけで書き換えるとこんな感じ。
msg = "test message from MATLAB";
provider = io.MultipartFormProvider('message', msg);
スタンプが利用できない
stickerPackageId
パラメータ、stickerId
(LINE notifyのパラメータ)にそれぞれスタンプパッケージIDとスタンプIDを渡してあげればよい。利用可能なスタンプはここ参照。購入したスタンプを自由に利用できるわけではないみたい。
なお、スタンプだけを送ることはできない(APIの制限)。必ずメッセージと一緒に送る必要がある。メッセージがない場合、400エラーを返されて終わるので気をつけよう。また、ID値は数値型ではなく文字列型で与えてやる必要がある(string
やchar
)。
それを踏まえるとこんな感じ。
msg = "test message from MATLAB";
provider = io.MultipartFormProvider('message', msg, 'stickerPackageId', string(4), 'stickerId', string(279));
美しくない
さて、本題。というか本命なので、次項で解説する。
完全無欠 MATLAB x LINE Notifyモジュール
完全無欠の条件
どでかい風呂敷を広げるために、完全無欠の条件を予め定めておく。
- アクセストークンを関数内にベタ書きしない
呼び出す側から設定したいので。 - 複数のアクセストークンに対応させる
使い分けできると便利なので。 - 関数のオーバーロード
msg_send
とかstamp_send
とかimg_send
みたいに使い分けするのは面倒。
でかい風呂敷のわりには案外少ないね。
ではコードをドン
classdef MATLAB_LINE_notify < handle
properties(Access = private)
token
uri
header
method
end
methods
function obj = MATLAB_LINE_notify(t)
obj.token = t;
obj.uri = 'https://notify-api.line.me/api/notify';
obj.header = matlab.net.http.HeaderField('Authorization', ['Bearer ', obj.token],...
'Content-Type', 'multipart/form-data');
obj.method = 'POST';
end
function status = notify(obj, msg, varargin)
if nargin < 2
msg = "This is a default message.";
end
switch nargin
case 1
provider = matlab.net.http.io.MultipartFormProvider('message', msg);
case 2
provider = matlab.net.http.io.MultipartFormProvider('message', msg);
case 3
if class(varargin{1}) == "double"
sticker_ids = validate_stamp(varargin{1});
provider = matlab.net.http.io.MultipartFormProvider(...
'message', msg, 'stickerPackageId', string(sticker_ids(1)),...
'stickerId', string(sticker_ids(2)));
elseif or(class(varargin{1}) == "char", class(varargin{1}) == "string")
img_path = validate_img(varargin{1});
img = matlab.net.http.io.FileProvider(img_path);
provider = matlab.net.http.io.MultipartFormProvider(...
'message', msg, 'imageFile', img);
end
case 4
if class(varargin{1}) == "double"
sticker_ids = validate_stamp(varargin{1});
img_path = validate_img(varargin{2});
img = matlab.net.http.io.FileProvider(img_path);
elseif or(class(varargin{1}) == "char", class(varargin{1}) == "string")
sticker_ids = validate_stamp(varargin{2});
img_path = validate_img(varargin{1});
img = matlab.net.http.io.FileProvider(img_path);
end
provider = matlab.net.http.io.MultipartFormProvider(...
'message', msg, 'imageFile', img,...
'stickerPackageId', string(sticker_ids(1)),...
'stickerId', string(sticker_ids(2)));
otherwise
error("入力引数が多すぎます。")
end
request = matlab.net.http.RequestMessage(obj.method, obj.header, provider);
resp = send(request, obj.uri);
status = resp.StatusCode;
end
end
end
%%
function sticker_ids = validate_stamp(sticker_ids)
if length(sticker_ids) ~= 2
error("スタンプIDが不正です。スタンプパッケージID、スタンプIDの順になっているか確認してください")
else
if sticker_ids(1) > 4
error("スタンプIDが不正です。スタンプパッケージID、スタンプIDの順になっているか確認してください")
end
end
end
function img_path = validate_img(img_path)
name = strsplit(img_path, '.');
if ~ismember(name(end), {'png', 'jpg', 'jpeg'})
error("画像ファイルの拡張子が不正です。pngもしくはjpgであることを確認してください。")
end
end
特に解説することはないかと思う。pythonでやっておられた方がオブジェクト指向で書かれていたので、それリスペクトでオブジェクト指向で書いてみた。実際こうすることで、複数のトークンに対応することが可能となっている。
本当はオーバーロードを使ってきれいに書きたかったんだけど、MATLABには僕の思っているような(C#とかにあるような)オーバーロードはなかった。そのため、nargin
やvarargin
を使って泥臭く書いてる。
使い方
特に迷うこともないかと思うが、一応。
まずはこのファイルをパスの通っているフォルダに保存。使用時は以下のように。
token = 'hogehoge';
msg = "Hello world!";
img = 'test.png';
bot = MATLAB_LINE_notify(token);
bot.notify(msg, img, [1,14])
まずはトークンやらの設定。このクラスを呼び出すときに、コンストラクタでトークンを設定してやる。(ないと思うけど、)途中でトークンを変更するならbot.token='new token'
などとすればよい。通知を出したいときは、notify
メソッドを呼べばOK。
実行するとこんな感じ。
ここで使ってるtest.pngはおそらくmatlabが用意してくれてるデフォルトのやつで、現在のフォルダーに呼び出してるtest.pngがないときこれが出てくる。
まとめ
本当はアドカレ記事の追記とするつもりだったけど、思ったよりでかい分量になったので新しく記事にした。でも、それに見合うくらいいいものができたんじゃないかな。
実は、記事執筆時点(2020/12/28 AM3:20現在)でnargin
やvarargin
を使って泥臭く書くか(載せたコード)、arguments
を使って名前と値のペア引数で書くべきか悩んでる。arguments
を使ったほうがデフォルト値の設定など融通がききやすいけど、ペア引数だとメソッドの呼び出しのときの打つ文字数が多くなるなあ、などと。ひとまずはこれで完成ということにしておきますが、また更新したりするかもしれません。
あと、今回のコードはGithubで公開してます。ぜひご利用ください。