温泉いって、Scalaで書かれたChirpUserStreams&WebSocketなTwitterクライアントをRev-WebSocketを使ってRubyで書いたった

あ…ありのまま 今 起こった事を話すぜ!
『おれはyuroyoroさんのScalaで書かれたChirpUserStreams&WebSocketなTwitterクライアントを改造していたと思ったら、いつのまにかRuby版を作っていた。』
な、何を言ってるのか(ry


7月18,19日に行われたCorona&Scala温泉開発合宿での自分の成果物の話です。
Scalaで書かれたChirpUserStreams&WebSocketなTwitterクライアントというのは、yuroyoroさんが5月10日に書かれた記事です*1
今回の合宿では当初、これに改良を加えようと目論んでいました。
で、結果からいうと、Scalaの型パラメーターに敗北して、Ruby版を作成することに方針転換したと。

合宿中に行ったこと、成果

  • Scala版のコードリーディング完了
  • 各種サンプルのコードリーディング完了
  • WebSocketの動作、仕様をある程度理解(含むJettyのWebSocket)
  • ChirpUserStreamsの動作、仕様をある程度理解
  • Ruby版途中までつくりかけ
  • Scalaの型パラメーターを扱う上でのイディオムがさっぱりわかっていないという事が認識出来た事

合宿中に結局できあがらず、戻ってきてから完成させました。

サーバ部分のコードは以下。

##########  chirp.rb  ##########

require 'net/http'
require 'uri'
require 'rubygems'
require 'rev/websocket'
Net::HTTP.version_1_2

# WebSocket chirp server
class ChirpConnection < Rev::WebSocket
  # 接続されたら呼ばれる
  def on_open
    puts "WebSocket opened"
    send_message("server: Hello, WebSocket!")
  end

  # メッセージが届いたら呼ばれる
  def on_message(data)
    auth_hash=Hash[data.split('&').map {|s| s.split('=') }]
    Thread.start {
      chirp(auth_hash['username'],auth_hash['passwd']) do |str|
        send_message str
      end
    }
  end

  def chirp(id,pass)
    uri = URI('http://chirpstream.twitter.com/2b/user.json')
    buf =""
    http = Net::HTTP.start(uri.host,uri.port)
    req = Net::HTTP::Get.new(uri.request_uri)
    req.basic_auth id, pass
    http.request(req) do |res|
      res.read_body do |body|
        buf += body
        until ( i = buf.index("\r\n")).nil?
          str = buf.slice!(0, i + 2).chomp
          unless str.size == 0
            puts str
            puts "----------------------- #{i} Bytes. -------"
            yield(str)
          end
        end
      end
    end
  end

  def on_close
    puts "WebSocket closed"
  end
end

host = '0.0.0.0'
port = ARGV[0] || 8081

server = Rev::WebSocketServer.new(host, port, ChirpConnection)
server.attach(Rev::Loop.default)

puts "start on #{host}:#{port}"

Rev::Loop.default.run


##########  chirp  ##########

#!/usr/bin/env ruby

fork {
	load 'chirp.rb'
	exit 0
}

require 'webrick'

server = WEBrick::HTTPServer.new({
	:Port => 8080,
	:BindAddress => '127.0.0.1',
	:DocumentRoot => File.dirname(__FILE__)+'/public'})

trap('INT') { server.shutdown }

server.start

ruby chirpでサーバースタートします。
クライアント部分はyuroyoroさんのをほぼそのまま使用しました。
htmlとcssを持ってきてWebSocketでの接続先を8080から8081に変更したぐらいです。
ChirpUserStreamsへのアクセス部分はこちらからぱくらせてもらいました。
WebSocketサーバは、EventMachineベースのEM-WebSocketを使っているものが多いようなのですが、ちょうど合宿の前日にリリースされていたので、Rev-WebSocketを使用してみました。

参加メンバーの成果

Corona&Scalaらしく、Corona関係のネタが4つ、Scalaネタが2つでした。残りは私のRubyと、アイデア、企画の精査?でした。
Corona SDKFireworksからCoronaに吐き出したりとか、3つ作られたiPhoneアプリは、3D時計アプリとか、プリクラアプリなどバラエティ豊かでした。
Scalaは環境セッティングの方と、武田さんの記事を参考に、AndroidアプリをScalaで動かすに挑戦された方でした。Android for Scalaは環境構築、確認用アプリのビルドだけでなく、既存のアプリをScalaで動かす所まで実現されていました。素晴らしい!

感想など

一年以上たっても余り進歩してないScala力を再認識した合宿でした。
何が足りていないかも大分把握できました。
毎日とはいかなくても、週に数回は必ずScalaに触ることを日課にしようと固く誓いました。
あと、WebSocketはちょっと仲良くなれた気がします。

*1:コップの会でずっと引っ張ったもんで、何回もトラックバックかましてしまって、なんだか申し訳ないので、今回はURLを貼らないようにしときました