Skip to content

Instantly share code, notes, and snippets.

@nihen
Created August 29, 2011 20:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nihen/1179323 to your computer and use it in GitHub Desktop.
Save nihen/1179323 to your computer and use it in GitHub Desktop.
use 5.14.1;
use Plack::Request;
use Text::Xslate::Util qw/html_escape/;
use POSIX qw/strftime/;
use List::Util qw/first/;
use JSON::XS;
use IO::Handle;
use Encode;
my $header = ['content-type' => 'text/html'];
my $articles = [];
my $recent_articles = [];
my $article_contents = [];
my $sidebar = '';
my $index_content = '';
my $max_articleid = 0;
my $json_encoder = JSON::XS->new->latin1;
my $json_decoder = JSON::XS->new->utf8;
my $log_file = './logfile';
my $log;
my $base_top =<<_EOF_;
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html" charset="utf-8">
<title>isucon now!</title>
<link type="text/css" href="/css/jquery-ui-1.8.14.custom.css" rel="stylesheet">
<link type="text/css" href="/css/isucon.css" rel="stylesheet">
<script type="text/javascript" src="/js/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="/js/jquery-ui-1.8.14.custom.min.js"></script>
<script type="text/javascript" src="/js/isucon.js"></script>
</head>
<body>
<div id="view">
<div id="titleimage"><a href="/post"><img src="/images/isucon_title.jpg" style="border: none;"></a></div>
<div id="mainview">
_EOF_
my $base_bottom =<<_EOF_;
</div>
</body>
</html>
_EOF_
my $post_content =<<_EOF_;
<div id="articleview">
<form method="POST" action="/post">
<table>
<tr><td><input type="text" name="title" size="60"/></td></tr>
<tr><td><textarea name="body" cols="60" rows="8"></textarea></td></tr>
</table>
<input type="submit"/>
</form>
</div>
_EOF_
{
#preload
if ( -e $log_file ) {
open $log, '<', $log_file;
my @lines = <$log>;
$log->close;
open $log, '>', $log_file;
for my $line (@lines) {
chomp $line;
my $ops = $json_decoder->decode($line);
for my $str ( @$ops ) {
$str = Encode::encode('utf-8', $str);
}
if ( $ops->[0] eq 'post' ) {
post(@{$ops}[1..@$ops-1]);
}
elsif ( $ops->[0] eq 'comment' ) {
comment(@{$ops}[1..@$ops-1]);
}
}
}
else {
open $log, '>', $log_file;
for ( 0..10 ) {
post($_, $_);
}
}
}
sub get_sidebar {
my @body = ('<div id="sidebar"><table><tr><td>新着コメントエントリ</td></tr>');
for my $article ( @{$recent_articles}[0..9] ) {
push @body, sprintf(
'<tr><td><a href="/article/%s">%s</a></td></tr>',
$article->{id},
$article->{title},
);
}
push @body, '</table></div>';
return join '', @body;
}
sub get_index_content {
my @body = ('<div id="articleview">');
for my $article ( @{[reverse @{$articles}]}[0..9] ) {
push @body, sprintf(
'<div class="article"><div class="title">%s</div><div class="created">%s</div><div class="body">',
html_escape($article->{title}), html_escape($article->{created_at})
);
my @lines = split "\n", $article->{body};
for my $line (@lines[0..8]) {
push @body, html_escape($line), '<br />';
}
push @body, '</div><div class="articlelink">';
if ( @lines > 7 ) {
push @body, '... ...';
}
push @body, sprintf('<a href="/article/%s">read more</a></div></div>', $article->{id});
}
return join '', @body, '</div>';
}
sub get_article_content {
my $articleid = shift;
my $article = $articles->[$articleid];
my $abody = '';
for my $body_line ( split "\n", $article->{body} ) {
$abody .= html_escape($body_line);
$abody .= '<br />';
}
my @body = sprintf('<div id="articleview"><div class="article">
<div class="title">%s</div>
<div class="created">%s</div>
<div class="body">%s</div>
</div>
<div class="comments">
<div class="commenttitle">以下みなさまの反応</div>
', html_escape($article->{title}), html_escape($article->{created_at}), $abody);
for my $comment (@{$article->{comments}}) {
my $cbody = '';
for my $body_line ( split "\n", $comment->{body} ) {
$cbody .= html_escape($body_line);
$cbody .= '<br />';
}
push @body, sprintf('
<div class="comment">
<div class="name">%s</div>
<div class="created">%s</div>
<div class="body">%s</div>
</div>
', html_escape($comment->{name} eq '' ? '名無しさん' : $comment->{name}), html_escape($comment->{created_at}), $cbody);
}
push @body, sprintf('
<div class="commentform">
<div class="commenttitle">あなたの反応</div>
<form method="POST" action="/comment/%s">
<table>
<tr><td>おなまえ: <input type="text" name="name" size="30"/></td></tr>
<tr><td><textarea name="body" cols="60" rows="4"></textarea></td></tr>
</table>
<input type="submit"/>
</form>
</div>
</div>', $articleid);
return join '', @body, '</div>';
}
sub post {
$log->printflush($json_encoder->encode([post => @_]), "\n");
my ($title, $body) = @_;
my $articleid = $max_articleid++;
my $article = {
id => $articleid,
title => $title,
body => $body,
created_at => strftime('%Y-%m-%d %H:%M:%S', localtime()),
comments => [],
};
$articles->[$articleid] = $article;
$article_contents->[$articleid] = get_article_content($articleid);
$index_content = get_index_content();
}
sub comment {
$log->printflush($json_encoder->encode([comment => @_]), "\n");
my ($articleid, $name, $body) = @_;
my $article = $articles->[$articleid];
push @{$article->{comments}}, {
name => $name,
body => $body,
created_at => strftime('%Y-%m-%d %H:%M:%S', localtime()),
};
my $this_article = first { $_->{id} eq $articleid } @$recent_articles;
if ( $this_article ) {
$recent_articles = [$this_article, grep { $_->{id} ne $articleid } @$recent_articles];
}
else {
unshift @$recent_articles, $article;
if ( @$recent_articles > 11 ) {
pop @$recent_articles;
}
}
$sidebar = get_sidebar();
$article_contents->[$articleid] = get_article_content($articleid);
}
sub app {
my $path_info = $_[0]->{PATH_INFO};
if ( $path_info =~ m{\A/article/(\d+)\z}o ) {
return ['200', $header, [
\$base_top,
\$sidebar,
\$article_contents->[$1],
\$base_bottom,
]];
}
elsif ( $path_info eq '/' ) {
return ['200', $header, [
\$base_top,
\$sidebar,
\$index_content,
\$base_bottom,
]];
}
elsif ( $path_info =~ m{\A/comment/(\d+)\z}o ) {
my $param = Plack::Request->new($_[0])->body_parameters;
comment($1, $param->{name}, $param->{body});
return ['302', [Location => '/article/' . $1], []];
}
elsif ( $path_info eq '/post' ) {
if ( $_[0]->{REQUEST_METHOD} eq 'GET' ) {
return ['200', $header, [
\$base_top,
\$sidebar,
\$post_content,
\$base_bottom,
]];
}
else {
my $param = Plack::Request->new($_[0])->body_parameters;
post($param->{title}, $param->{body});
return ['302', [Location => '/'], []];
}
}
return ['404', [], []];
}
\&app;
@nihen
Copy link
Author

nihen commented Aug 29, 2011

nginxでstaticファイルを処理したら、feersumとの組み合わせで214,204req/minでた

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment