Skip to content

Instantly share code, notes, and snippets.

@seki
Created May 27, 2009 15:55
Show Gist options
  • Save seki/118708 to your computer and use it in GitHub Desktop.
Save seki/118708 to your computer and use it in GitHub Desktop.
tiny chat for toRubyKaigi
#!/usr/local/bin/ruby
require 'drb/drb'
DRb.start_service
ro = DRbObject.new_with_uri('druby://localhost:54321?cgi')
ro.start(ENV.to_hash, $stdin, $stdout)
require 'rinda/tuplespace'
require 'erb'
require 'webrick/cgi'
require 'rbtree'
require 'nkf'
require 'digest/md5'
require 'enumerator'
class Page
include ERB::Util
def initialize
@color = create_color
end
def create_color
Hash.new do |h, k|
md5 = Digest::MD5.new
md5 << k.to_s
r = 0b01111111 & md5.digest[0]
g = 0b01111111 & md5.digest[1]
b = 0b01111111 & md5.digest[2]
h[k] = sprintf("#%02x%02x%02x", r, g, b)
end
end
Base = <<EOS
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Koto</title>
<meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Refresh" content="1;URL=<%= refresh_url%>"/>
<style type="text/css" media="screen">@import "../iui/iui.css";</style>
<style type="text/css">
body > ul > li {
font-size: 14px;
}
</style>
</head>
<body>
<div class="toolbar">
<h1 id="pageTitle">Koto</h1>
<a id="backButton" class="button" href="#"></a>
</div>
<ul id="home" title="Rinda" selected="true">
<%=h Time.now %>
<%
last_group = nil
context.each_slice(13) do |ary|
ary.each do |k, v|
time = Time.at(-0.1 * k)
str, from = v
group = group_header(from, time)
if group != last_group %>
<li class="group" style="font-size: 13px;color:<%= @color[from] %>"><%=h group %></li>
<% last_group = group
end
%> <li><%=h str %></li><%
end
break
end
%>
</ul>
</body>
</html>
EOS
ERB.new(Base).def_method(self, 'to_html(context, refresh_url)')
def group_header(from, time)
from + ' @ ' + time.strftime("%H:%M")
end
end
class Njet
def initialize(value)
@value = value
end
def ===(other)
@value != other
end
end
class Store
def initialize
@tree = MultiRBTree.new
@ts = Rinda::TupleSpace.new(3)
@ts.write([:latest, 0])
end
attr_reader :tree
def each_slice(n, &blk)
@tree.each_slice(n, &blk)
nil
end
def via_drb
'via drb ' + Thread.current[:DRb]['client'].stream.peeraddr[2] rescue nil
end
def via_cgi(req)
req.peeraddr[2] rescue nil
end
def latest
@ts.read([:latest, nil])[1]
end
def wait(key)
@ts.read([:latest, Njet.new(key)], 5)
end
def import_string(str)
NKF.nkf('-edXm0', str)
end
def add(str, req=nil)
str = import_string(str)
from = req ? via_cgi(req) : via_drb
from ||= 'local'
@ts.take([:latest, nil])
begin
key = -10 * Time.now.to_f
@tree[key] = [str, from]
puts "#{Time.now.strftime('%H:%M:%S')}(#{from}) #{str}"
str
ensure
@ts.write([:latest, key.to_i])
end
end
end
class MyApp < WEBrick::CGI
def initialize(*args)
super(*args)
@store = Store.new
@page = Page.new
end
attr_reader :store
def do_str(req)
return unless req.query['str']
str = req.query['str'].to_s
@store.add(str, req)
end
def do_age(req)
return unless req.query['age']
age = req.query['age'].to_i
@store.wait(age)
rescue
end
def prepare(req)
do_str(req)
do_age(req)
end
def do_GET(req, res)
res['content-type'] = 'text/html; charset= EUC-JP'
prepare(req)
uri = req.request_uri.dup
uri.query = "age=#{@store.latest}"
res.body = @page.to_html(@store, uri.to_s)
res.status = 200
end
def do_POST(req, res); do_GET(req, res); end
end
class Front
def initialize(app)
@app = app
end
def [](key)
return @app.store if key == 'store'
@app
end
end
app = MyApp.new
DRb.start_service('druby://:54321', Front.new(app))
DRb.thread.join
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment