RSS Pipesを使って、実用的なことをしよう、というお話です。
以前、RSS Pipesで広告エントリの除去という記事を書いたのですが、あまり自分でも使っていませんでした。今回、どうしてもやりたいことがあったので、久しぶりにRSS Pipesをいじりました。
やりたいことというのは、RSSのURLの修正です。RSSのURLにリダイレクトURLが使われていることがあります。例えば、bit.lyなどの短縮URLが使われている場合です。通常は困らないのですが、そのRSSをプログラムで処理しようとする場合に、短縮URLではなく最終的なURLが欲しい場合があります。めずらしいケースだとは思います。
URLのリダイレクトをたどるにはこれまでのRSS Pipesの仕組みの上だけではできず、新たな関数を作り込む必要がありました。具体的には、getRedirectURL()
という関数を作りました。
ところが、このgetRedirectURL()
は同期的には結果を返すことができません。nodeでは、通常callbackを使って非同期処理を書くのですが、RSS Pipesのフィルターは同期的に書くように作られていたので困りました。仕方なく、promiseを使うことにしました。
フィルターの方でもpromiseを扱えるようにする必要があるため、Qを使えるようにしました。しかし、これでブロックするようなコードも書けてしまうので、悪意コード対策がいずれ必要になりますね。promiseにタイムアウトの概念を持ち込めれば簡単にできるかしら。
さて、新しくなったRSS Pipesで書いたフィルターがこちらです。
function rssPipesFilterFunction(articles) {
var promises = [];
articles.forEach(function(article) {
var maxRedirects = 5;
var loop = function() {
var promise = getRedirectURL(article.link).then(function(link) {
if (article.link === link || --maxRedirects < 0) {
return article;
} else {
article.link = link;
return loop();
}
});
return promise;
};
promises.push(loop());
});
return Q.all(promises);
}
https://gist.github.com/dai-shi/8934864
にも同じものを同じものを置いてあります。
リダイレクトが多重になっている場合を想定してループにしてみましたが、promiseをちゃんと理解していればもっとうまく書けるのかもしれません。どなたか改良してくれたら、うれしいです。
しかしこれでサーバ側の処理がますます重くなるので、キャッシュ機構を入れる必要がでてきそうです。そのうち、気が向いたらやりますか。今のところ、それほどユーザがいないのでほっておいても大丈夫です。それはそれでさびしいものの。
コメント