SinatraでGitHub OAuthするの続き
試しにGitHub認証して、成功したらリポジトリとGistの一覧を表示するだけのアプリを作ってHerokuに置いておいた
http://sinatra-github-oauth-sample.herokuapp.com/
ソースコード
shokai/sinatra-github-oauth-sample · GitHub
https://github.com/settings/applicationsからRegister new Applicationした
OAuthのコールバックは /auth.callback に来る。
右上からログインすると
一度GitHubに移動してから戻ってきて、GitHub APIが使われてリポジトリとGistの一覧が出てくる
右上にGitHubに登録したアイコンが表示される。
1. GitHub認証して(これはSinatraでGitHub OAuthするに書いた)
2. 乱数とMD5でセッションID作ってブラウザに渡して
3. memcachedにセッションIDをkeyにしてgithubの情報を入れておく(2週間でexpireする)
4. トップページでは、ログイン状態ならoauth tokenをoctokitに渡してGitHubからリポジトリ/Gist一覧を取得する(これはmemcacheで1時間保持する)
必要な時にmemcachedからユーザー情報を取り出せるhelperを書いた
libs/cache.rbとcontroller/auth.rbに処理を詰め込んであるので、この2つだけコピーすれば他のSinatraアプリにもGitHubログイン機能追加できるはず。
RackやSinatraのログイン系のプラグインを使っても良いかと思ったが、memcachedクライアントにpure rubyかつバイナリプロトコルサポートしているdalliを使いたかったのと、
1つのmemcachedのkeyにprefix付けてログイン情報とリポジトリ/Gist一覧を保存できるようにしたかったので自分で書いた libs/cache.rb に任せた。配列のようにアクセスするとkeyにprefixが付いて読み書きできて便利。
6月132013
0
7月152012
memjsというmemcached clientにpull requestが取り込まれた。
HerokuではアドオンのMemcacheかMemcachierを使う事になるが、両方共SASLによる認証が入っている。
SASL認証を使うにはバイナリプロトコルが使えるmemcache clientが必要なのだが、node.jsにはバイナリ使えるのmemjsしか無かったのでとりあえず試したけど認証なしでしか動かなかった。
この時にmemcacheとmemcachierのアドオンを入れたり消したりしてたらmemcachierの中の人からメールが来て、相談してたらOpCode 0x21の時にKeyが必要なところが入ってなかったのを見つけて、修正したらうまく動いたのでpull requestして取り込まれた。
これでNodeでHerokuのMemcacheが使えるようになりました。
memjsの使い方はこんなの。
まだREADMEがしっかり書かれていないのでflagとかが何だかわからないけど、テストコード見たらだいたい使い方もわかってbugfixもできた。
// npm install memjs
var memjs = require('memjs');
var cache = new memjs.Client.create(null, {expires: 10}); // 10sec expire
// set value
cache.set('name', 'shokai', function(err, val){
if(err) console.error('set error');
else{
// get value
cache.get('name', function(err, val, flag){
if(err) console.error('get error');
else console.log('get : '+ (val ? val.toString() : null));
});
// wait 11 sec, then get value
setTimeout(function(){
console.log('wait 3 sec');
cache.get('name', function(err, val, flag){
if(err) console.error('get error');
else console.log('get : '+ (val ? val.toString() : null));
});
}, 11000);
}
});
2バイト以上の文字はencodeURI/decodeURIを通して使う。
6月272012
インストール
https://github.com/elbart/node-memcacheを使う。npm install memcache
プログラム書いた
2秒expireで書き込み→すぐ読む→3秒待って読む、という例。memcache-test.js
var memcache = require('memcache');
var client = new memcache.Client(11211, 'localhost');
client.connect();
var get = function(){
client.get('name', function(err, val){
if(!err) console.log(val);
else console.error('get error');
});
};
client.set('name', 'shokai', function(err, res){
if(err){
console.error('set error');
process.exit(1);
}
get();
setTimeout(function(){
console.log('wait 3 sec');
get();
}, 3000);
}, 2);
実行
node memcache-test.js
結果
shokai
wait 3 sec
null
値がまだ書き込まれていないかexpireしている時はnullが返ってくる。
返り値のerrorは、setはnullが、getはundefinedが入っていた。
setのresultには保存失敗した場合はSTORED返ってきた。errorの方だけ見ればいいかも。
接続エラー
memcahedが起動していなかったり、client.connect()せずにsetするとこういうエラーがでる。最初connect忘れていてなんだこのエラーは!?と思った。
node_modules/memcache/lib/memcache.js:110
this.conn.write(query + crlf);
^
TypeError: Cannot call method 'write' of null
6月222012
Memcached使ってみたかった。なんかキャッシュしなきゃならんので
ブラウザ <---> Heroku <---(cache)---> Twitter
なものを作った。
できたもの http://twiticon.herokuapp.com/
twitterのユーザーアイコンをHTMLに簡単に貼れるやつ。ソースコードはこここういうHTMLでアイコンがでる。
<img src="http://twiticon.herokuapp.com/shokai">
小さいのや大きいのも貼れる。
テキストや http://twiticon.herokuapp.com/shokai.txt
JSONでも取得できる http://twiticon.herokuapp.com/shokai.json
使い方は http://twiticon.herokuapp.com に詳しく書いてある。
Twitterのアイコン
ここにAPIがあるGET users/profile_image/:screen_name | Twitter Developers
ユーザーが新しいアイコンをアップロードする毎にURLが変わる。
例えば今の俺のアイコンは https://si0.twimg.com/profile_images/2328443341/tmp_normal.png になってる。
Memcached
ふつうのSQL DBみたいにHDDにデータは保存しないけど、メモリ上で高速に動作する。あとExpireする期限を決めれる。今回は保存したアイコンURLは12時間で消滅するようにした。
12時間1秒経過すると、再度Twitter APIを使ってURLを取りに行く。
Herokuでmemcached使う
Memcache | Heroku Dev Centerにドキュメントがある。Herokuのmemcachedはユーザー名とパスワードによる認証があって、SASLというプロトコルを使っているので対応しているgemじゃないと使えない。
dalliというpure rubyのgemが推奨されている。
いつも使ってるCで書かれてるmemcached gemはSASLサポートしてるって記述があるんだけど、使い方がドキュメントに書いてないし面倒臭くなってdalliに落ち着いた。
Herokuにmemcached addon追加した。無料だけどクレジットカード番号登録しないと使わせてもらえない。
% heroku create --stack cedar
% heroku addons:add memcache:5mb
パスワードとかは
% heroku configで見れる。
MEMCACHE_PASSWORD, MEMCACHE_SERVERS, MEMCACHE_USERNAMEがそれ。
これがHerokuで動かしてるアプリの環境変数に入るので、ENV[‘MEMCACHE_SERVERS’]とかで取り出す。
dalliでMemcached使う
認証なしrequire 'rubygems'
require 'dalli'
cache = Dalli::Client.new 'localhost:11211'
Heroku用
cache = Dalli::Client.new ENV['MEMCACHE_SERVERS'], {:username => ENV['MEMCACHE_USERNAME'], :password => ENV['MEMCACHE_PASSWORD']}
で、あとはcacheにset/getすればよい。
# cache 1 hour
cache.set('icon_shokai', 'https://si0.twimg.com/profile_images/2328443341/tmp_normal.png', 3600)
# get icon
puts cache.get('icon_shokai')
ちなみにHerokuのmemcachedは自分のローカル環境からも接続できる。
addons:add memcachedしたらすぐに起動するので、手元で開発してるプログラムで
cache = Dalli::Client.new 'xxxxx.ec2.northscale.net', {:username => '123456heroku.com', :password => 'asdf122345hujiko'}とか書いても動かせる。太平洋横断してるから遅いけど。
ローカル開発環境にMemcachedをインストール
homebrewやapt-getでインストールできる。% brew install memcachedこれでlocalhost:11211で起動する。
% memcached -vv -p 11211
SinatraでMemcachedを使う
ふつうに上に書いたのを組み合わせてredirectするだけなのでgithub見ればわかると思う。https://github.com/shokai/twiticon
controllerでは
redirect icon user, sizeとだけ書いて、iconって関数は適当にキャッシュもしてくれるように書かれている。
あと開発時はローカルのlocalhost:11211のmemcachedを見て欲しいので、環境変数が無かったらconfig.ymlから同じ値を探すようにしたらはかどった。