#coding: utf-8
require "webrick"
include WEBrick
$thure_list = []
(Thure = Struct.new(:res_list, :subj)).class_eval {
def to_uri
"/read?id=#{object_id}"
end
def to_html(*ranges)
buf = "<dl>"
ranges.each {|range|
res_list[range] and
res_list[range].each {|res|
buf << "<dt style='margin-top:10px;'>#{res.no} :#{res.name}:#{res.date} ID:#{res.hash}</dt>"
buf << "<dd>#{res.text}</dd>"
}
}
buf << "</dl>"
buf << <<-FORM
<form method='POST' action='/post'>
<div>
<input type='submit' value='書き込む'>
名前:<input type='text' name='name'>
E-mail:<input type='text' name='mail'>
</div>
<textarea name='text'></textarea>
<input type='hidden' name='id' value='#{object_id}'>
</form>
FORM
end
}
Res = Struct.new :no, :text, :name, :mail, :date, :hash
class String
def nonempty?
empty? ? nil: self
end
end
def get_thure(id)
id = id.to_i
thure = $thure_list.find {|t| t.object_id == id }
thure or raise "スレッド(#{id})が見つかりません!"
end
def put_error(resp, e)
resp["Content-Type"] = "text/html"
resp.body = <<-PAGE
<html>
<head><title>エラー</title></head>
<body>
<h1>エラー</h1>
<p>#{e.to_s}</p>
</body></html>
PAGE
end
30.times {|i|
$thure_list << Thure.new([], ["はじまりです","おわりだお","まピョーン☆", "アラシはいやづら"][(rand * 4).floor])
1.upto((rand * 1000).floor) {|n|
$thure_list.last.res_list << Res.new(n,
"はじまりなのです".chars.to_a.shuffle.join,
"まろゆき".chars.to_a.shuffle.join, "sage", Time.now, "???")
}
}
$style = <<CSS
<style>
body {
background:#93ff93;
}
</style>
CSS
server = HTTPServer.new( Port: 8080 )
server.mount_proc("/") {|req, resp|
resp["Content-Type"] = "text/html"
resp.body = <<-PAGE
<html>
<head>
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'>
<title>Aちゃんねる</title>
#{$style}
<style>
body {
background:#93ff93;
}
h1 { text-align: center; }
body > div {
margin: 20px auto 0 auto;
padding: 5px;
width: 90%;
border:3px solid green;
background: #23a710;
}
h2 {
margin: -3px 0 30px 0;
border:5px solid darkgreen;
border-width: 0 0 0 10px;
}
textarea {
width: 45em;
height: 7em;
}
</style>
</head>
<body>
<h1>アラシはいやづら</h1>
<div>
PAGE
count = 0
$thure_list[0..9].each {|t|
resp.body << "<a href='#{t.to_uri}'>#{count += 1}</a>:<a href='##{t.object_id}'>#{t.subj}(#{t.res_list.size})</a>\n"
}
resp.body << "<hr>"
$thure_list.size > 10 and
$thure_list[10..-1].each {|t|
resp.body << "<a href='#{t.to_uri}'>#{count += 1}:#{t.subj}(#{t.res_list.size})</a>\n"
}
resp.body << "</div>"
$thure_list[0..10].each {|t|
resp.body << "<div><a name='#{t.object_id}'></a><h2>#{t.subj}</h2>#{t.to_html(0..0, [1,t.res_list.size-9].max..-1)}"
resp.body << "<div><a href='#{t.to_uri}&pos=%7c50'>最新50件</a></div></div>"
}
resp.body << <<-PAGE
<div>
<form method='POST' action='/post'>
<div>
<input type='submit' value='スレッドを立てる'>
主題:<input type='text' name='subj'>
名前:<input type='text' name='name'>
E-mail:<input type='text' name='mail'>
</div>
<textarea name='text'></textarea>
</form>
</div>
</body></html>
PAGE
}
server.mount_proc("/read") {|req, resp|
resp["Content-Type"] = "text/html"
begin
id = req.query["id"].to_i
thure = $thure_list.find {|t| t.object_id == id }
resp.body = <<-PAGE
<html>
<head>
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'>
<title>Aちゃんねる</title>
<style>
body {
background:#93ff93;
}
textarea {
width: 45em;
height: 7em;
}
</style>
</head>
<body>
<h1>スレ:#{thure.subj}</h1>
<div>ページ: 1
#{
s = ""
50.step(1000, 50) {|n|
break if n > thure.res_list.size
s << "<a href='?id=#{id}&pos=#{n-49}-#{n}'>-#{n}</a> "
}
s
}
</div>
#{
thure.to_html(*case req.query["pos"]
when /\|(\d+)/ then [[thure.res_list.size-$1.to_i,0].max..-1]
when /(\d+)(-(\d+))?/ then [$1.to_i..($3||$1).to_i]
else [0..-1]
end)
}
</body>
</html>
PAGE
rescue => e
put_error resp, e.to_s
end
}
server.mount_proc("/post") {|req, resp|
begin
text = (req.query["text"]||"").nonempty? or raise "本文が入力されてません"
name = (req.query["name"]||"").nonempty? || "名無しさん"
mail = req.query["mail"]||""
subj = req.query["subj"]||""
subj.force_encoding "UTF-8"
mail.force_encoding "UTF-8"
name.force_encoding "UTF-8"
text.force_encoding "UTF-8"
res = Res.new(1, text, name, mail,
Time.now, req.peeraddr.to_s.crypt("XX")[2..-1])
if subj.empty?
thure = get_thure req.query["id"]
thure.res_list << res
res.no = thure.res_list.size
unless mail =~/sage/
$thure_list.delete thure
$thure_list.unshift thure
end
else
$thure_list.unshift Thure.new([res], subj)
end
resp["Pragma"] = "no-cache"
resp.set_redirect(HTTPStatus::MovedPermanently, '/')
rescue => e
put_error resp, e.to_s
end
}
trap(:INT) { server.shutdown }
server.start