アーカイブ
‘TokyoCabinet’ タグのついている投稿
gyaazzというアウトラインエディタ風wikiを作っている
2010 年 9 月 18 日
コメントはありません
増井先生が作ってるgyazzが元ネタ。JavaScriptの勉強がしたくてN村ヒロユキっていう人と作った。
ダブルクリックした行から編集できる。方向キーか、ctrlキーを押しながらemacs的操作でカーソル移動できる。
一応アウトラインエディタなので、ctrlやshiftを押しながらキー操作するとブロック毎移動したりインデントしたり、ブロックまるごと入れ替えたりできる。
[[ と ]]で囲んだ部分がURLならリンクに、画像へのURLだったらimgタグに、URLでなければ新しいwikiページへのリンクになる。
しばらく操作しないで置いておくと、右下に「saved!」と表示されて編集が保存される。
あと他の人が編集するとsyncする。
UIはjQueryを使ったので、JSよくわからないけど2、3日でエディタ的機能は実装できた。
サーバー側はSinatraを使っている。ページのデータをJSONで返す簡単なAPIが用意されている。なので一番上の階層に小文字で「api」というページは作れない。
データベースにはTokyoCabinetを使ってる。
ソースコードとインストール方法はhttp://github.com/shokai/gyaazzにある。
でもmongodb使って作り直そうかな
あと、
- ページ名の変更
- ページのコピー
- 認証付きページを作れる機能
ShinagawaSeaside
2010 年 7 月 5 日
コメントはありません
tokyo tyrantのサーバーを起動したり終了したりするrake taskを作った。
名前は、tokyotyrantの周辺のライブラリがmiyazaki resistanceとかそういう名前ばかりだったのでそういう作法なのかなと思って天王洲アイルと迷いつつ品川シーサイドに決めた。
■インストール
sudo gem isntall shinagawaseaside
■使う
Rakefile
require 'rubygems'ShinagawaSeaside::set_tasks するとrake taskが追加される。
require 'shinagawaseaside'
ttdb = [ { :name => 'users', :port => 20010},
{ :name => 'videos',:port => 20011},
{ :name => 'comments', :port => 20012} ]
ShinagawaSeaside::set_tasks(ttdb, :basedir => File.dirname(__FILE__)+'/ttdb')
Rakefileのあるディレクトリの下に ttdb というディレクトリが作られて、
その中にusers.tch, videos.tch, comments.tch というDBができる。pidはusers.pid, videos.pid, comments.pidの中に入る。
% rake -T
rake ttrestart # restart TokyoTyrant server
rake ttstart # start TokyoTyrant server
rake ttstop # stop TokyoTyrant server
中身はRakeでTokyoTyrant serverを起動/終了 – 橋本詳解と大体同じ。(複数サーバー起動できるようにした)
tokyotyrantをソースからインストールすると一緒に入る ttservctl を参考にした。
タスクの名前は初期値がttstart, ttstopだけど、変更もできる
ShinagawaSeaside::set_tasks(ttdb,
:basedir => File.dirname(__FILE__)+'/ttdb',
:start => 'start', # set task name
:stop => 'stop',
:restart => 'restart'
)
俺はyamlで設定ファイルを書いてそこから読み込むようにしている。そうするとアプリからも、どのDBがどのportにあるか見つけやすい。
config.yaml
ttdb :
- name : users
port : 23240
- name : videos
port : 23241
Rakefile
require 'rubygems'
require 'yaml'
require 'shinagawaseaside'
begin
conf = YAML::load open(File.dirname(__FILE__)+'/config.yaml')
rescue
STDERR.puts 'config.yaml load error'
exit 1
end
ShinagawaSeaside::set_tasks(conf['ttdb'], :basedir => File.dirname(__FILE__)+'/ttdb')
■ソースコード
githubに置いた
mbedで取得したセンサーの値をsinatra+tokyocabinetで保存する
2010 年 4 月 25 日
コメントはありません
まずセンサーのデータを時系列で溜めたり、取り出したりするためのwebサービスをsinatra+TokyoCabinetで作っておいた。
そこにmbedのADコンバータでCdSの明るさを計測、LEDを点灯/消灯 と mbedにEthernetを接続しtwitterにpostするを合体させ、約10秒間隔でセンサーの値をhttp-postしまくった。
一度web APIが出ている場所にマイコンの情報も保存しておけば、あとでマッシュアップできて便利になる。このAPIの下にmbedでもgreasemonkeyスクリプトでも何個でもぶら下げられる。
mbedからwedataに保存しても良かったんだけど、あえて自分で作ってみた。
■mbedで明るさを計測してhttp-postする
作った回路。CdSで明るさを取得し、LEDで明るさを表示する。mbedのRD+,RD-,TD+,TD-ピンにトランス入りEthernetジャックを接続し、LANケーブルを刺した。

プログラム。CdSに入る光量が少なくなると緑色のLEDが光る。http-postはTickerで定期的に呼び出したかったが、Ticker内でHTTPClient.hの関数を使うとmainに戻ってこなくなるので仕方なくmain内で20ループ毎(約10秒毎)にHTTPClient.post()するようにした。stdは使えるけど、pthread等のスレッド機能は無いみたいなのでこれは痛い。
sensor_http_post | mbed
#include "mbed.h"せっかくC++が使えて、mbed.hのAPIはC++っぽいのに、HTTPClient.hはそうでもないみたいだ。
#include "HTTPClient.h"
#include <string>
using namespace std;
Serial pc(USBTX, USBRX);
DigitalOut led1(LED1); // blink
DigitalOut led2(LED2); // blink when http-post
DigitalOut led3(p11); // represent ADC value
AnalogIn adc(p15);
float ain;
HTTPClient http; // use DHCP
const string api_uri = "http://shokai.mag.keio.ac.jp/sensor-storage/shokai/cds/";
const string mbed_name = "shokai-mbed01";
const string sensor_name = "CdS";
void blink_led(DigitalOut led, int num){
for(int i=0; i < num*2; i++){
led = !led;
wait(0.1);
}
}
void post_sensor_value(){
blink_led(led2, 2);
char query[256] = "";
char result[4096] = ""; // 4kb
sprintf(query, "name=%s&%s=%f", mbed_name.c_str(), sensor_name.c_str(), (float)ain);
pc.printf("post:%s => %s\n", query, api_uri.c_str());
http.post(api_uri.c_str(), query, result, 4096);
pc.printf("%s\n", result);
blink_led(led2, 2);
}
int main(void){
led1 = 1;
int count = 0;
while(1) {
ain = adc;
pc.printf("sensor:%f\n", float(ain));
led1 = !led1; // blink LED
if(ain > 0.1) led3 = 0; // represent CdS value
else led3 = 1;
if(count > 20){
post_sensor_value();
count = 0;
}
count++;
wait(0.5);
}
}
mbedのローカルのストレージがfopenで読めるので、そこに設定ファイルを置けるようにしたい。yamlやjsonをparseするライブラリを作りたい。
動作はシリアル通信で見れる。表示にはserialterm.rbを使った。
postすると返り値がjsonで来る。

■tokyocabinetとsinatraでデータを溜めるAPIを作る
できたもの
sensor-storage API
githubでソースを全部公開しておいた。
shokai's sensor-storage at master – GitHub
http://shokai.mag.keio.ac.jp/sensor-storage/ にhttp-postした内容を、json stringにエンコードして時刻_マイクロ秒をキーにしてTokyoCabinetに保存する。
keyの _ の左側が時刻になっているので後で使う時に便利。
http://shokai.mag.keio.ac.jp/sensor-storage/keys で保存されているkeyの一覧がJSON形式で見れる。
http://shokai.mag.keio.ac.jp/sensor-storage/recentで最近10件のkeyとvalueが取れる。他にもrecent/件数や、last(最後に入れたデータ)、count(データ件数)などのAPIがある。
今回のmbedでCdSの値を保存しているのは http://shokai.mag.keio.ac.jp/sensor-storage/shokai/cds/recent になる。shokai/cds/last , shokai/cds/recent , shokai/cds/count などで色々データが取り出せる。
/ 以下に適当に文字列を付けると新しくDBを作るようになっている。もしデータをpostしてみたいなら、mbedの方のコードは/shokai/cds/をハードコーディングしているので、そこを適当に変えてから使ってくれるとうれしい
あまりにも大きいデータは入らない。
スクリプト自体はわりとシンプル。sinatra使って1ファイルに書いてある。
server/main.rb at master from shokai's sensor-storage – GitHub
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'rubygems'
require 'sinatra'
require 'sinatra/reloader' if development?
require 'rack'
require 'json'
require 'tokyocabinet'
include TokyoCabinet
@@dbdir = 'db'
def db_open(dbname='/')
dbname = dbname.to_s.gsub(/\//, '_')
@hdb = HDB.new
Dir.mkdir(@@dbdir) if !File.exists?(@@dbdir)
@hdb.open("#{@@dbdir}/_#{dbname}.tch", HDB::OWRITER|HDB::OCREAT)
end
after do
@hdb.close if @hdb
end
get '*/' do
path = "../" * params[:splat].first.count('/')
redirect "#{path}./readme"
end
get '*/keys' do
db_open(params[:splat])
@hdb.keys.reverse[0...10000].to_json
end
get '/dbs' do
Dir::glob("#{@@dbdir}/*.tch").map{|i|
name = i.to_s.scan(/.*\/(.+)\.tch/).first.to_s.gsub(/_/,'/')
tmp = name.split(//u)
tmp.shift
tmp.to_s + "/"
}.uniq.delete_if{|i|
i =~ /\/\//
}.sort.to_json
end
get '*/count' do
db_open(params[:splat])
{"count", @hdb.rnum}.to_json
end
get '*/last' do
db_open(params[:splat])
key = @hdb.keys.last
{key, @hdb[key]}.to_json
end
get '*/recent' do
db_open(params[:splat])
@hdb.keys.reverse[0...10].map{|k| {k, @hdb[k]} }.to_json
end
get '*/recent/:num' do
db_open(params[:splat])
num = [params[:num].to_i, 1000].min
@hdb.keys.reverse[0...num].map{|k| {k, @hdb[k]}}.to_json
end
get '*/:tc_key' do
db_open(params[:splat])
key = params[:tc_key]
{key, @hdb[key]}.to_json
end
post '*/' do
db_open(params[:splat])
now = Time.now
key = "#{now.to_i}_#{now.usec}"
params.delete(:splat.to_s)
@hdb.put(key, params.to_json)
{key, @hdb[key]}.to_json
end
delete '*/:tc_key' do
key = params[:tc_key]
v = @hdb[params[:tc_key]]
@hdb.out(params[:tc_key])
{key,v}.to_json
end
githubのmiscディレクトリ以下にテスト用にhttp postしたりするためのスクリプトがある。mbedが無い時の動作チェックにどうぞ。
サーバーはthinで10個preforkさせておいて、それぞれ別のportで起動させてある。apache2のmod_proxy_balancerでそこにproxyして、80番ポートのサブディレクトリ下にあるように見せている。
- 橋本商会 apache2のサブディレクトリをthinで起動してるsinatraにプロキシする
- ubuntu8.04にtokyocabinetインストール – 橋本詳解
- Macにtokyocabinetインストール – 橋本詳解
- 開発時に自動リロードする – 橋本詳解
- shotgunでコード自動リロードを有効にする – 橋本詳解

最近のコメント