ActiveResourceをUNIX Domain Socketで使ってみる
現状、内部APIとの通信はHTTPで行われており、localhostへの接続とはいえそれなりに通信コストがかかっているため、今後、内部APIはPHP-FPMで動かし、unix domain socket経由で叩けるようにしたいところです。
http://inside.pixiv.net/blog/2012/11/08/pixiv-dot-comfalsequan-ti-xiang/
ふむふむ。
ActiveResource で UNIX Domain Socket 叩けるんだろうかと思って実験してみた。
このあたりを参考にしながら準備。
適当な Rails アプリケーションを作って、
% rails new crazyresource -J -O % cd crazyresource
Gemfile を作って、
source 'https://rubygems.org' gem 'rails', '3.2.11' gem 'activeresource'
bundle install して、
% bundle install --path vendor/bundle
適当な scaffold を作る。(bookmark というのは参考にしたサイトにあわせた)
% bundle exec rails generate scaffold bookmark title:string url:string comment:text
で、まずは普通に http://localhost:8080 からリソースを取得するようにしてみて、
% vi app/models/bookmark.rb
class Bookmark < ActiveResource::Base self.site = 'http://localhost:8080/' end
次にポート 8080 に nginx を立てた。
% mkdir nginx % mkdir nginx/logs % mkdir nginx/html % echo '[{"comment":"Google Search","id":1,"title":"Google","url":"http://www.google.com/"}]' > nginx/html/bookmarks.json % vi nginx/nginx.conf
nginx.conf はこんな感じ。
worker_processes 1; events { worker_connections 1024; } http { server { listen 8080; server_name localhost; location / { root html; } } }
nginx 起動。
% nginx -p $PWD/nginx -c nginx.conf % curl "http://localhost:8080/bookmarks.json" [{"comment":"Google Search","id":1,"title":"Google","url":"http://www.google.com/"}]
ここまでできたら Rails を起動して、
% bundle exec rails server
リソースが取得できることを確認。
% curl "http://localhost:3000/bookmarks.json" [{"bookmark":{"comment":"Google Search","id":1,"title":"Google","url":"http://www.google.com/"}}]
nginx は UNIX Domain Socket でもリクエストを受け付けられるので、設定を以下のように変えて、
worker_processes 1; events { worker_connections 1024; } http { server { listen unix:/tmp/nginx.sock; server_name localhost; location / { root html; } } }
nginx を再起動すると、
% nginx -s stop % nginx -p $PWD/nginx -c nginx.conf
curl "http://localhost:3000/bookmarks.json"
は失敗するようになる。
これでようやく準備完了。
次に、unix_socket_hack というのを使う。
Gemfile にこういうのを追加して、bundle install する。
gem 'unix_socket_hack', :git => 'git://github.com/walf443/unix_socket_hack.git'
実は Net::HTTP だと unix_sock_hack がうまく動かないので、 https://github.com/walf443/unix_socket_hack/issues/2 に書いたような変更を 対応してもらいました。vendor/bundle/ruby/1.9.1/bundler/gems/unix_socket_hack-93e97dea2425/lib/unix_socket_hack.rb
に加える。
localhost:8080 への TCPSocket を乗っ取って /tmp/nginx.sock への UNIXSocket にしたいので、 config/application.rb
にこういうのを追加しして、
require 'unix_socket_hack' UNIXSocketHack.apply({ 'localhost:8080' => '/tmp/nginx.sock' })
Rails を再起動すると、また動くようになった。
% curl "http://localhost:3000/bookmarks.json" [{"bookmark":{"comment":"Google Search","id":1,"title":"Google","url":"http://www.google.com/"}}]
nginx のログに unix: というのがあるので、ちゃんと UNIX Domain Socket でアクセスしてることがわかる。
% tail -f nginx/logs/access.log unix: - - [20/Jan/2013:18:10:23 +0900] "GET /bookmarks.json HTTP/1.1" 200 85 "-" "Ruby"
Macに最初から入ってるmemcachedを常時起動するようにした
Mac に memcached をインストールしようと思ったら、Lion には最初から入ってたので、それを有効にした。
検索しても Lion に memcached が入ってることはほとんど知られてないみたいで、↓このへんぐらいしか出てこなかった。
これを参考に、
~/Library/LaunchAgents/com.danga.memcached.plist
というファイルを作って、
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>KeepAlive</key> <true/> <key>Label</key> <string>memcached</string> <key>Program</key> <string>/usr/bin/memcached</string> <key>RunAtLoad</key> <true/> <key>UserName</key> <string>ユーザー名</string> </dict> </plist>
とか書いて、(ユーザー名のところは自分のユーザー名にした)
launchctl load -w ~/Library/LaunchAgents/com.danga.memcached.plist
と打って実行。RunAtLoad=true なので起動したら実行する。
MacBook AirのCPU温度を取得する
Mac OS Xのバッテリー残量は
ioreg -n AppleSmartBattery
というコマンドで取得できるけど、CPUの温度については標準で付いてくるコマンドではどうやら取得できないらしい。
IOKitのインターフェイスを使ってCで持ってこれるんだけど、まさにそういうツールを公開してる人がいて、↓の smc.h と smc.c でOKみたい。(たぶんこのソースもどこかから持ってきたものみたいだけど)
ただし、Mac OS X 10.5 (Leopard) 以降ではIOConnectMethodStructureIStructureO
がIOConnectCallStructMethod
に変わったことでコンパイルできなくなっていた。
で、その修正版も公開してる人がいた。
- http://d.hatena.ne.jp/bootblack/20090610
- http://d.hatena.ne.jp/bootblack/20120603/p1
- http://www.geocities.jp/freeggggroup/nf/ ←の "ClamNF.app v5.5.9 for Mac (OS X 10.8 Mountain Lion)" ではなく、旧版の "ClamNF.app v5.5.5 for Mac OS X 10.5.8" の中にある
.app の中にソースが入ってるのだけど、面倒なので Gist に貼っておいた。(元々 GPL なので)
clang -framework IOKit -o smc smc.c
使い方
$ ./smc -h Apple System Management Control (SMC) tool 0.01_2 Usage: ./smc [options] -f : fan info decoded -h : help -k <key> : key to manipulate -l : list all keys and values -r : read the value of a key -w <value> : write the specified value to a key -v : version $ ./smc -f Total fans in system: 1 Fan #0: Actual speed : 1997 Minimum speed: 2000 Maximum speed: 6500 Safe speed : 0 Target speed : 2000 Mode : auto Temp = 55.375 Temp TB0T = 32.6875 Temp TC0D = 55.375 Temp TC0P = 50.5 Temp TM0P = 46.875 Temp TN0P = 0 Temp Th0H = 0 Temp Ts0P = 30.625 Temp TN1P = 0 Temp Th1H = 35.375
現在のCPU温度は55.375度だそうな。
GrowthForecast.plで自分ロギングしてみた
こちらのブログではお久しぶりです。
定期的に数字を投げておけば勝手にいい感じでグラフ化してくれるツールが欲しい…!と思っていたら、GrowthForecastというのがPerl界隈で流行ってると教えてもらいました。
早速使ってみようと思ったのですが、MacではRRDtoolが落ちるため、色々やった挙句諦めてVirtualBoxにインストールしてようやく使えました。
使い方については既に色々書かれているので省略しますが、グラフを作り始める設定とかも不要でHTTPでPOSTし始めれば今すぐにでも数値ログを取れるという、まさに思った通りのツールでした。
ところで最近はライフログにハマっています。
パソコンを触っている時間を記録しておいて、何時に眠りに落ちたのか分かるようにしたかったので、GrowthForecastでキータイプとマウスイベントの回数をロギングしてみました。
Macでキーイベントを取得するにはObjective-Cだろうと思って書き始めたのですが、XCodeに慣れなくて結局Vimで書きました。
かなりCっぽいObjective-Cのソース置いときます。
これでコンパイルできるはずです。
clang sample.m -o sample -framework Cocoa -lcurl
GrowthForecastに投げる部分はlibcurlを使ってこんな感じになります。
#include <curl/curl.h> ... size_t curl_write_callback_func(char* ptr, size_t size, size_t nmemb, void* nothing) { return 0; } int post(char *name, int num) { char url[MAXLINE]; sprintf(url, "http://localhost:5126/api/me/log/%s", name); char postdata[MAXLINE]; sprintf(postdata, "number=%d", num); printf("%s: %d\n", name, num); CURL *curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_callback_func); CURLcode res = curl_easy_perform(curl); curl_easy_cleanup(curl); return res == CURLE_OK; }
Macのイベント取得部分はCGEventTapというAPIを使って書けるそうです。
#import <Cocoa/Cocoa.h> #include <time.h> ... CGEventRef catchEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* nothing) { // http://stackoverflow.com/questions/4727149/application-randomly-stops-receiving-key-presses-cgeventtaps if (type == kCGEventTapDisabledByTimeout) { CGEventTapEnable(eventTap, true); } if (type == kCGEventKeyDown) { /* to listen for key events, run this program as root */ int key = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); printf("%d\n", key); count_key++; } else if (type == kCGEventMouseMoved || type == kCGEventScrollWheel) { count_mouse++; } return event; } int main() { CFRunLoopSourceRef runLoopSource; eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 0, kCGEventMaskForAllEvents, catchEventCallback, NULL); runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); CGEventTapEnable(eventTap, true); ... CFRunLoopRun(); return 0; }
キーイベントを取得するにはこのプログラムをroot権限で実行する必要があります。
それから、普通にキーイベントだけを取得すると、何故か突然イベントを取得できなくなることがあるのですが、どうやらイベントが連続して起こった時などに CGEventTap が外されてしまうそうです。StackOverflowでSnow Leopardのバグだとかいう書き込みを見ましたが真相は不明です。その時に kCGEventTapDisabledByTimeout というイベントが出るので、それを捕まえて CGEventTap をまた有効にしてあげないといけません。
定期的にGrowthForecastにPOSTする部分はCFRunLoopTimerRefというのを使いました。
#include <time.h> #include <dispatch/dispatch.h> ... void postEventsAsync(int num_key, int num_mouse) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{ post("key", num_key); post("mouse", num_mouse); }); } void recordCountsCallback(CFRunLoopTimerRef timer, void* nothing) { time_t this_time; struct tm * timeinfo; time(&this_time); timeinfo = localtime(&this_time); timeinfo->tm_sec = 0; this_time = mktime(timeinfo); if (this_time == prev_time) { // within less than 60 sec (do nothing) return; } else if (prev_time == 0) { // first time (set prev_time to this_time) } else if (difftime(this_time, prev_time) >= 120.0) { // come back from sleep (discard) count_key = 0; count_mouse = 0; postEventsAsync(count_key, count_mouse); } else { // more than 60 sec (record) postEventsAsync(count_key, count_mouse); count_key = 0; count_mouse = 0; } prev_time = this_time; } int main() { ... CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, 0, 1.0, 0, 0, recordCountsCallback, NULL); CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); CFRunLoopRun(); return 0; }
Grand Central Dispatch を使ってみました。こうしないと、HTTP通信待ちの間に後続のキーイベント等をブロックしちゃうので、パソコンがプチフリーズしたみたいになってしまうためです。
こんなところです。それではみなさんもHappy Life Logging!
ニョーン
↑ pixiv.js はほぼykskさんが書いたものなので、僕のコメントは無いだろうと思って開いたんですが、
7686: // マウスオーバーでおすすめタグをニョーンと出す
と
7629: // TODO: pixiv.storage.localStorage の使い方が分かりにくいのでとりあえず window.localStorage を使う
は僕でした。pixiv.storage.localStorage
ってのがあったので使おうかと思ったんですが、挙動がよく分からなかったので敢えてラップする必要ないかなーと思って単に window.localStorage
使っちゃいました(ゴメンネ)
ちなみにニョーンってやつの挙動は↓これです。
ちなみにpixivはIE7以下は対応しません。過去より未来を見ましょう。
pixivに入社しました
東京に住み始めたので近くの人は遊びに誘ってください。
3月31日にGEEK DAY TOKYOというイベントで(たぶん)WebGLについて何か話します。ネタはまだ決めてませんが15分程度になる予定です。
http://geekday.jp/ワクワクエンジニアリング
ギークだってはしゃぎたい!
GEEK DAY TOKYOは、パイプ椅子に座ってプレゼンを聞いて、神妙な面持ちでメモを取るようなイベントとは、ちょっと違います。
メモの代わりに酒や肴を片手に、プレゼンを聞いたり展示を見たり。
ちょっと疲れたら、参加者同士でギークな話に花を咲かせたり。
お酒が飲めなくてもOK。会場にはコーラやレッドブルも完備です。
3月31日。GEEK DAY TOKYOは、ワクワクエンジニアリングをテーマに、終始ゆるーくお送りします。
↓100人までだそうですが、すぐ埋まりそうな感じですね。
それからこのブログ並びに僕のオンラインでの活動は全て個人的な表現活動であり、雇用者の意見と必ずしも一致するものではありません。
学校辞めた
趣味だったウェブのことにどっぷりハマってきたので、思い切って大学院をやめました。
就活は11月ぐらいからやってたりします。といっても「いわゆる就活」はほっとんどしてませんが。
数ヶ月以内には仕事を始めたいところです。