0

SinatraでGitHub OAuthする (2)

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.rbcontroller/auth.rbに処理を詰め込んであるので、この2つだけコピーすれば他のSinatraアプリにもGitHubログイン機能追加できるはず。

RackやSinatraのログイン系のプラグインを使っても良いかと思ったが、memcachedクライアントにpure rubyかつバイナリプロトコルサポートしているdalliを使いたかったのと、
1つのmemcachedのkeyにprefix付けてログイン情報とリポジトリ/Gist一覧を保存できるようにしたかったので自分で書いた libs/cache.rb に任せた。配列のようにアクセスするとkeyにprefixが付いて読み書きできて便利。

0

HerokuのNode.jsでMemcache使えるようにした

memjsというmemcached clientにpull requestが取り込まれた。

HerokuではアドオンのMemcacheMemcachierを使う事になるが、両方共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を通して使う。

0

Node.jsでMemcachedを使う

インストール

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

0

HerokuでSinatra+Memcached使う

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
% memcached -vv -p 11211
これでlocalhost:11211で起動する。


SinatraでMemcachedを使う

ふつうに上に書いたのを組み合わせてredirectするだけなのでgithub見ればわかると思う。
https://github.com/shokai/twiticon


controllerでは
redirect icon user, size
とだけ書いて、iconって関数は適当にキャッシュもしてくれるように書かれている


あと開発時はローカルのlocalhost:11211のmemcachedを見て欲しいので、環境変数が無かったらconfig.ymlから同じ値を探すようにしたらはかどった。


感想

memcache無料の5MBぐらいだと、tmp_cache gem使ったほうが設定もいらないし楽なのでは・・・