uTrackMe 向け DB登録スクリプト

uTrackMe 4.xから仕様が大幅に変わったので,この情報はもう役に立ちません.そのうちまたまとめます.まー、誰も使わないと思うんですけどね.(2010/9/2追記)
ここ最近,iPodTouch/iPhone の uTrackMe というアプリにはまっていましたが,このアプリ向けの位置情報DB登録のための CGI スクリプトを公開します.

承前 uTrackMe とはなんぞや

uTrackMe は,iPodTouch/iPhone で動作するアプリで,WiFi あるいは 3G 経由でユーザの規定した サーバ CGI に現在地情報などを POST することが出来ます.また,POST 時の CGI からの戻りが,uTrackMe の解釈できる XML であった場合,その XML に埋め込まれた他ユーザの位置情報や速度などをアプリ画面上で確認できるようになり,”友達がどこにいる”といったことが分かるようになります.
しかし,このアプリは大変 漢(オトコ)らしいアプリでして,そういうサーバ CGI などは自分で作れというスタンスでありまして,このアプリが全く売れていない理由となっております.しかし,このアプリはよく似た GPSed と異なる,優れた機能があります.それは,

  • WiFi や 3G 網の切断により POST に失敗したとしても,POST 出来なかった位置情報を,WiFi/3G が復帰した後に,再度 POST してくれる

というところです*1.これはオプション設定 Publish Entire Track の ON/OFF で切り替えられます.
ただし,弱点もあります.

  • 位置情報測位をするためには,常に uTrackMe アプリが フォアグランドである必要があります(Backgrounder でも不可).
  • 同様に,スリープモード(電源ボタンのショートプレス)でも動作しません.常に uTrackMe を眺めておく必要があります.

ぶっちゃけ,開発環境があれば,ぼくが バックグラウンドで動作するアプリ作るのに!!

サーバ側 DB 登録 CGI スクリプト

このスクリプトは,MySQLMySQL/Ruby を利用します.
MySQL の使い方については説明しません.ぼくもよく分かっていないからです.よくわかりませんが,このへんが参考になるんじゃないですかい?
MySQL/RubyRubyMySQL を使うためのラッパです.インストール方法は上記公式サイトに書かれているので,その通りにします.ruby-devel が必要となりますので,ちゅうい.

ここでは,MySQL DB は CGI を動作させる サーバ上にあり,すでに,utrakcme ユーザ,utrackme ユーザがアクセス可能な DB utrackme が存在するものと仮定しています.(つまり,CGI 設置前に,空 DB を作成しておいてください)

で,SQL にアクセスするための CGI は下記の通り.

#!/usr/bin/ruby

require "cgi"
require "csv"
require "digest/md5"
require "mysql"

cgi = CGI.new

MySQL_SERVER   = "localhost"
MySQL_USER     = "utrackme"
MySQL_PASSWORD = "XXXXXXXX"
MySQL_DATABASE = "utrackme"

DATABASE_SKIP  = 5
LOST_TIME      = 900

def ret_group_members(cgi, db, rew)
  myid = Digest::MD5.hexdigest(cgi["id"])
  t = Time.now.to_i - rew
  res = db.query("select * from track where id!='#{myid}' and time>'#{t}'order by time desc limit 1;")

  print "(\n"
  while row = res.fetch_hash
    print "{\n"
    print "udid = \"" + row['id'] + "\";\n"
    print "label = \"" + row['label'] + "\";\n"
    print "delta = " + row['delta'] + ";\n" 
    print "lock = " + row['lck'] + ";\n" 
    print "time = " + row['time'] + ";\n" 
    print "lat = " + row['lat'] + ";\n" 
    print "lon = " + row['lon'] + ";\n" 
    print "acc = " + row['acc'] + ";\n" 
    print "spd = " + row['spd'] + ";\n" 
    print "dir = " + row['dir'] + ";\n" 
    print "alt = " + row['acc'] + ";\n" 
    print "},\n"
  end
  print ")\n"
end

def push_track(cgi, m, n, max, db)
  hashed_id = Digest::MD5.hexdigest(cgi["id"])
  fixed_param = ["'" + hashed_id + "'" ,
                 "'" + cgi["label"] + "'" ,  
                 cgi["delta"].to_i, 
                 cgi["lock"].to_i]
  fixed_str = fixed_param.join(",")
  step = max
  for i in m .. n
    var_param = [ cgi["time[#{i}]"],
                  cgi["lat[#{i}]"],
                  cgi["lon[#{i}]"],
                  cgi["acc[#{i}]"],
                  cgi["spd[#{i}]"],
                  cgi["dir[#{i}]"],
                  cgi["alt[#{i}]"]]
    var_str = var_param.join(",")
    str = fixed_str + "," + var_str
    if cgi["time[#{i}]"].to_i - step >= DATABASE_SKIP
      db.query("insert into track values (#{str})")
      step = cgi["time[#{i}]"].to_i
    end
  end
end

db = Mysql.new(MySQL_SERVER, MySQL_USER, MySQL_PASSWORD, MySQL_DATABASE)

unless db.list_tables.include? "track"
  sql = <<SQL
create table track (
  id varchar(256),
  label varchar(64),
  delta integer,
  lck integer,
  time integer,
  lat double,
  lon double,
  acc double,
  spd double,
  dir double,
  alt double
)
SQL
  db.query(sql)
end

print "Content-type: text/html\n\n"

hashed_id = Digest::MD5.hexdigest(cgi["id"])
res = db.query("select max(time) from track where id='#{hashed_id}'")
chk = db.query("select * from track where label='#{cgi['label']}' and id!='#{hashed_id}'");
if chk.num_rows != 0
  puts "Your label has been used!"
  exit
end

m = 0
n = 0

max = String.new
res.each{|p| max = p.join}
for i in 0..86399
  if cgi["time[#{i}]"].empty?
    n = i - 1
    break
  end
  if cgi["time[#{i}]"].to_i < max.to_i
    m = i
  end
end
push_track(cgi, m, n, max.to_i, db)
ret_group_members(cgi, db, LOST_TIME)

db.close

この CGI めがけて uTrackMe アプリから POST すると,MySQL DB にログが格納されていきます.
また,他のユーザの最終ログがLOST_TIME秒以内に同一 DB 上に存在すれば,uTrackMe アプリには,当該ユーザの情報も併せて表示されます.この機能で友達と追いかけっこしよう!!

その他・注意

  • CGI スクリプトについて責任はとれません.
  • SQLインジェクション 等は考慮していません.したがって,DB の破壊は容易です.本 DB 操作に使うユーザにはあまり権限を与えないようにしてください.大事な他の DB までぶっとばされんようにしてください.
  • ソースコードが汚すぎる ⇒ 書き直していただけるので? ありがとうございます m(__)m
  • このソースは Vine Linux 4.2 CR で動作確認しております.rpm -qa|egrep 'MySQL|ruby|apache' の結果は下記の通り.
    • MySQL-shared-5.0.27-0vl6
    • MySQL-server-5.0.27-0vl6
    • MySQL-devel-5.0.27-0vl6
    • MySQL-client-5.0.27-0vl6
    • liberuby-1.0.5-0vl3
    • ruby-openssl-1.8.5-1.4vl4
    • ruby-docs-1.8.5-1.4vl4
    • ruby-gtk2-0.16.0-0vl1
    • ruby-mode-1.8.5-1.4vl4
    • eruby-1.0.5-0vl3
    • ruby-tcltk-1.8.5-1.4vl4
    • libruby-1.8.5-1.4vl4
    • ruby-gnome2-0.16.0-0vl1
    • ruby-devel-1.8.5-1.4vl4
    • ruby-1.8.5-1.4vl4
    • ruby-gnome2-devel-0.16.0-0vl1
    • apache2-devel-2.2.3-3.9vl4
    • mod_ssl-apache2-2.2.3-3.9vl4
    • php5-apache2-5.2.9-4vl4
    • apache2-2.2.3-3.9vl4
    • apache2-manual-2.2.3-3.9vl4

*1:もっと正確に言えば,過去の測位情報を覚えていて,全部 POST しています.いったい過去何ポイント分のデータを覚えていて,POST してくれるのかは不明.