Created
May 27, 2009 15:55
-
-
Save seki/118708 to your computer and use it in GitHub Desktop.
tiny chat for toRubyKaigi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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