Tuppari入門中。Tuppariでchatを作ってみました。
@hakoberaさん謹製のTuppariを使ってchatを作ってみました。
Tuppari de chat
yosuke-furukawa/tuppari-de-chat · GitHub
Tuppariというのは、東京Node学園で紹介されたPusherのクローンで、WebSocket通信用に作られたサービスです。
Tuppariの詳細はhakoberaさんのこちらのエントリを参考にしてください。
Tuppari - WebSocket on Your Cloud - - Scalaとlift のはずだった ・・・
node.js版ですごく簡単にできました。せっかくなので、作るまでにやったことをまとめてみます。
tuppariインストールからアカウント作成まではこちらを読んでください。
node.js + express + tuppari作成
前準備
expressからサンプル・アプリケーションを作成してください。
$ express tuppari-de-chat
依存関係&tuppari インストール
$ cd tuppari-de-chat
$ npm install
$ npm install validator
$ npm install tuppari
app.js修正
tuppariを使えるようにします。app.js側は本当に簡単で、20〜30行位追加しただけでTuppariに送信できました。
app.js
/** * Module dependencies. */ var express = require('express') , routes = require('./routes') , http = require('http') , Tuppari = require('tuppari') , keys = require('./keys') , sanitize = require('validator').sanitize; var app = express(); var tuppari = new Tuppari(keys); //これでchannel作成とchannelへの参加を実施。 var channel = tuppari.join('chat'); app.configure(function(){ app.set('port', process.env.PORT || 3000); app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.favicon()); app.use(express.logger('dev')); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(app.router); app.use(express.static(__dirname + '/public')); }); app.configure('development', function(){ app.use(express.errorHandler()); }); app.get('/', routes.index); app.get('/chat', function(req, res){ var message = sanitize(req.query.message).entityEncode(); if (message) { //メッセージを送信。 channel.send('your_event', message, function (err, res, body) { if (err) { console.error(err); } if (res) { console.log(res.statusCode, body); } else { console.error("no response."); } }); } res.json(null); }); http.createServer(app).listen(app.get('port'), function(){ console.log("Express server listening on port " + app.get('port')); });
keys.js作成
keys.jsにTuppariのアプリケーションID等を入れておきます。
keys.js
module.exports = { applicationId: process.env.TUPPARI_APPLICATION_ID, accessKeyId: process.env.TUPPARI_ACCESS_KEY_ID, accessSecretKey: process.env.TUPPARI_ACCESS_SECRET_KEY };
あとでherokuにアップする際にはインストール時に得られたアプリケーションID等をprocess.envに入れてください。
$ heroku config:add TUPPARI_APPLICATION_ID=xxxxxx
$ heroku config:add TUPPARI_ACCESS_KEY_ID=yyyyyy
$ heroku config:add TUPPARI_ACCESS_SECRET_KEY=zzzzzz
ローカルで実行する場合は以下のようにして実行します。
$ export TUPPARI_APPLICATION_ID=xxxxxx
$ export TUPPARI_ACCESS_KEY_ID=yyyyyy
$ export TUPPARI_ACCESS_SECRET_KEY=zzzzzz
※この方法の方がスマートかも。
クライアント側
tuppariのAPPLICATION_IDを持つクライアントを作成し、app.jsで登録した'chat' channelをsubscribeします。
chat.js
function chat() { var message = $('#message').val(); console.log(message); $.ajax({ url: "/chat", data: {message: message}, async: false, success: function(data){ $("#message").val(''); //do nothing. } }); $('#form').submit(function() { return false; }); } var client = tuppari.createClient({ applicationId: '6545f512-301b-4951-b36f-a750716cb3a1' // Replace this with your Application ID. }); var channel = client.subscribe('chat'); channel.bind('your_event', function (data) { var date = new Date(); $('#list').prepend($('<dt>' + date + '</dt><dd>' + data + '</dd>')); });
あとはindex.jadeやlayout.jadeなんかはこんな感じです。
index.jade
extends layout block content h1= title form(id='form') input(type='text', name='message', id='message') button(type='submit', onClick="chat();") chat hr dl(id='list')
layout.jade
doctype 5 html head title= title link(rel='stylesheet', href='/stylesheets/style.css') script(type='text/javascript', src='http://cdn.tuppari.com/0.1.0/tuppari.js') script(type='text/javascript', src='/javascripts/jquery-1.7.min.js') script(type='text/javascript', src='/javascripts/chat.js') body block content
使ってみた感じの感想
簡単に使える良い感じのライブラリですね。
クライアントへのpush通知はこれでいいんじゃないかな、という気になります。
Fluentdとかと連携したりして、リアルタイムにリソース監視とか夢が広がります。
ハッカソンもあるので、もう少し入門してみます。
Node.js × GeekTool で ももクロ天気予報アプリ 作りました。
最近コードの匂いがしないエントリばかり書いていたので、危うさを感じ、作ってみました。
#といっても全然書いてないんですが。
Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)
- 作者: 山本陽平
- 出版社/メーカー: 技術評論社
- 発売日: 2010/04/08
- メディア: 単行本(ソフトカバー)
- 購入: 136人 クリック: 4,160回
- この商品を含むブログ (158件) を見る
また、最近上の本を読んで一度Restfulなアプリケーションを作ってみようと思ったことにも起因しています。
この本の感想は次のエントリに書きます。
とりあえず、ももクロ天気予報アプリ、名付けてmomoclo-weatherを紹介します。
紹介
momoclo-weatherはその日の天気に合わせてももクロちゃんの表情が変わるだけのアプリです。
晴れ:笑顔
曇:むくれ顔
雨:泣き顔
な感じです。2012年7月22日、現在、東京は雨なので、東京なら泣き顔が出ます。
momoclo-weatherの中身は expressとnode-yqlだけです。
クライアントはGeekToolで実行するので、天気予報をYQLから取得して、ExpressでJSONだけを返す、という事を実行しています。
GeekToolを入れていない人にもなんとなく、感覚をわかってもらうためにWeb用のアクセスも用意してます。
momoclo-weather
使い方
GeekToolを入れてください。
GeekToolのシェルに以下のように入れます。
curl --silent "http://momoclo-weather.herokuapp.com/weather.json?member=XXXXX&location=YYYYYY" | grep -E 'momocloimage' | sed -e 's/"momocloimage"://' -e 's/"//' -e 's/"//' | xargs curl --silent -o /tmp/weather_momoclo.png
memberのXXXXXにはmember名を入れます。
kanako, ayaka, reni, shiori, momokaのいずれかを入れてください。
locationのYYYYYにはweatherIDを入れます。
weatherIDはここで検索すれば分かります。
東京ならJAXX0085
横浜ならJAXX0099
という感じです。
例:東京でれにちゃん推しの場合:
curl --silent "http://momoclo-weather.herokuapp.com/weather.json?member=reni&location=JAXX0085" | grep -E 'momocloimage' | sed -e 's/"momocloimage"://' -e 's/"//' -e 's/"//' | xargs curl --silent -o /tmp/weather_momoclo.png
例:横浜でかなこ推しの場合:
curl --silent "http://momoclo-weather.herokuapp.com/weather.json?member=kanako&location=JAXX0099" | grep -E 'momocloimage' | sed -e 's/"momocloimage"://' -e 's/"//' -e 's/"//' | xargs curl --silent -o /tmp/weather_momoclo.png
後はweather_momoclo.pngをGeekToolのimageで出せばOKです。
もしも明日の天気予報をして欲しい場合はURLに&day=tomorrow を入れれば明日の顔が取得できます。
curl --silent "http://momoclo-weather.herokuapp.com/weather.json?member=kanako&location=JAXX0099&day=tomorrow" | grep -E 'momocloimage' | sed -e 's/"momocloimage"://' -e 's/"//' -e 's/"//' | xargs curl --silent -o /tmp/weather_momoclo.png
あとは、JSONから返ってくる値を色々加工すれば、色んな事ができます。冒頭にあった吹き出しで喋らせるような感じにもできます。
天気模様、Sunnyとか、Cloudyとかを出力する場合:
curl --silent "http://momoclo-weather.herokuapp.com/weather.json?member=shiori&location=JAXX0085" | perl -pe 's/,/,\n/g' | grep -E 'text' | sed -e 's/"text"://' -e 's/"//' -e 's/",//'
気温を出力する場合:
curl --silent "http://momoclo-weather.herokuapp.com/weather.json?member=ayaka&location=JAXX0085" | perl -pe 's/,/,\n/g' | grep -E 'temp' | sed -e 's/"temp"://' -e 's/"//' -e 's/",/C/'
と、こんな感じで出来ます。
コード紹介
実際に頑張っているのはYQLです。
YQLはYahooが作ったWebサービスで、SQLライクなQueryを食わせればYahooサービスの結果を取得できます。
やろうと思えばFlickrから画像取得とかも出来るっぽい。
さて、Node.jsにもYQLにアクセスするためのライブラリがあり、node-yqlです。
installの仕方等、詳しいことは以下のURLを見てください。
derek/node-yql · GitHub
コレを使って天気を取得するコードが以下の通り
//Tokyo : JAXX0085 //Yokohama : JAXX0099 //単位はCelcius固定。Fahrenheitがいいって人がいたら、'unit':'f'。 YQLWeather.prototype.executeQuery = function(area, callback) { yql.exec("SELECT * FROM weather.forecast WHERE location=@area AND u=@unit", function(response) { var validated_res = validate(area, response); callback(validated_res); }, {'area':area, 'unit':'c'}); };
多分、weather.forecast以外のテーブルも色々あるので、触ってみるのも面白そうです。
GitHub
yosuke-furukawa/momoclo-weather · GitHub
Herokuに置いたRedisをコマンドラインから使用する
前回の記事でMongoHQとRedis To Goを性能比較してみました。
今回はそれを実行している時に発見したTipsを紹介します。(Herokuを使っている人には常識なのかもしれませんが。)
MongoHQにはHeroku上のデータにウェブからアクセスできる管理画面があるのに対して、Redis To Goにはありません。
どうやってデータ管理するのかというと、'heroku' コマンドのプラグインとしてredis-cliへ接続する方法があるので、それを使用します。
Redisインストール
redisをインストールします。ダウンロードページからダウンロードしてmakeすれば実施できます。
Redisインストール済みで redis-cliへのパスが通っていれば、このセクションは読む必要ありません。
コマンドラインから実行する場合は以下のようにしておきます。
$ wget http://redis.googlecode.com/files/redis-2.4.13.tar.gz $ tar xzf redis-2.4.13.tar.gz $ cd redis-2.4.13 $ make
もしも Windows 環境の場合は以下のダウンロードページからダウンロードしてインストールできます。
Downloads · dmajkic/redis · GitHub
インストールできたか確認するためには以下のコマンドを実行してください。
$ src/redis-server
[38875] 06 May 13:12:21 - DB 0: 1 keys (0 volatile) in 4 slots HT.
[38875] 06 May 13:12:21 - 0 clients connected (0 slaves), 1005520 bytes in use
こういう結果が出れば、ひとまずRedisインストールは成功です。
redis-cliへのパスを通しておきます。
デフォルトは[ダウンロードされた先]/src/redis-cli にあります。
以下のやり方で通しても良いみたいです。
$ sudo cp redis-server redis-cli redis-benchmark /usr/local/bin/
詳細はココを参考にしてください。
Redis To Go
Download – Redis
heroku-redis-cliをインストールする
以下のコマンドでインストールできます。
$ heroku plugins:install https://github.com/rapportive-oss/heroku-redis-cli.git
herokuコマンドのバージョンが古いとエラーになる可能性があるので、(自分の環境では一度エラーが出ました)上のコマンドでエラーになったらupdateしてから最実行してください。
$ gem update heroku
インストールに成功したら、デプロイしているアプリケーションのフォルダへ移動してください。
以下のコマンドが実行可能になっているはずです。
$ cd <application_root> $ heroku redis:cli
実行すると、redis-cliと同じコンソールが使えるようになります。
また、他にも以下のコマンドが実行可能になります。
heroku redis:monitor - 現在Redisで実行されている操作がリアルタイムで表示される heroku redis:info - Redisのリソース状況表示
もしかしたらもっと簡単な方法があるのかもしれませんが、これでRedisの状況が見れたり、直接データが操作できるのは嬉しいです。
詳細はrapportive-oss/heroku-redis-cli · GitHubを参照してください。
ももクロスライダーで測る Redis vs MongoDB on Heroku 第二弾
今日はみどりの日らしく、ももクロスライダーも緑の話が活発です。
さてさて、前回に続いてRedisの話です。
危険なほど速いと言われていますが、実際の実力はどうなのか気になるところです。
確かに他の参考記事を見ると、かなり高速なようです。
redis、それは危険なほどのスピード|サイバーエージェント 公式エンジニアブログ
FreeBSDで,mongoDB V.S. Redis - なぜか数学者にはワイン好きが多い
じゃーって事で、RedisとMongoDBをベンチマーク比較してみました。
結論から言うと、Redisはやっぱり鬼のように速いです。
ベンチ方法
RedisとMongoにtwitpicから取得してきた ももクロの画像に関するデータを入れておき、それを取り出す処理がどちらが早いかだけを計測しています。更新系の操作も高速なようですが、ももクロスライダーは今は更新系の操作がないので、これで計測しています。
ももクロスライダーを少し拡張し、
- /directで実行するとtwitpic API直接呼出してJSON情報取得
- /redisで実行するとredisからJSON情報取得
- /mongoで実行するとmongoからJSON情報取得
できるようにしてから計測しています。
一応URLを貼っておきます。アクセスしてみれば、それぞれなんとなく性能の差が分かるかもしれません。
twitpic直接呼出し
redis呼出し
mongo呼出し
このURLに対してローカルサーバーへのアクセス(ホストをlocalhostにして)で計測したものとHeroku上で計測したものの2パターンとさらにアクセス高負荷で計測したものと低負荷なものの4パターンで計測しています。
計測ツールはJmeterを使っています。
低負荷は10秒間以内に10クライアントからのアクセスを測定。
高負荷は10秒間以内に1000クライアントからのアクセスを測定しています。
ベンチマーク結果
■ローカル環境で計測(低負荷:10秒間で10クライアントから接続される)
local(低負荷) | direct(twitpic api直) | redis | mongo |
response time | 2421ms | 3ms | 11ms |
twitpic APIを直接呼び出ししたときは比較にならないほど遅かったので、省いてグラフ化するとこんな感じです。
ミリ秒なのであまり差はありませんが、redisの方が若干早いですね。圧巻なのはこの次。
■ローカル環境で計測(高負荷:10秒間で1000クライアントから接続される)
local(高負荷) | direct(twitpic api直) | redis | mongo |
response time | N/A | 2ms | 3531ms |
twitpic APIはもはや受け付けてもらえず、エラーになってしまいました。
Redisはここでも超高速で、ほとんど低負荷の時と速度に差がありません。
mongoは平均3.5秒程度になってしまいました。mongoはメモリ上にデータはないので、ディスクアクセスになってしまい、負荷がかかるとその分、低速になります。
予想をはるかに上回るRedisの速度で、危険なほど速いというのも分かる気がします。
■Heroku環境で計測(低負荷:10秒間で10クライアントから接続される)
heroku(低負荷) | direct(twitpic api直) | redis | mongo |
response time | 958ms | 292ms | 252ms |
Heroku環境から計測してみると、ネットワークを介しているせいで結構大きな差が生まれています。
twitpicがローカルよりもかなり速いのが気になりますが、とりあえず、置いておきます。(Herokuサーバーに距離が近いのかな?)
redisとmongoだとここではmongoの方が若干早いですね。ただ、双方ネットワークがボトルネックなせいでローカルと比較してかなり遅延している事がわかります。
■Heroku環境で計測(高負荷:10秒間で1000クライアントから接続される)
heroku(高負荷) | direct(twitpic api直) | redis | mongo |
response time | N/A | 4985ms | 5664ms |
高負荷で計測してみると、ここでもredisの方が早いという結果が出ました。
ただし、ローカルで計測した時よりも全然Redisの恩恵は得られていません。
ネットワークがボトルネックなせいもありますが、Redis to goのコネクション制限がボトルネックになってきていると思われます。Herokuのデータストアとして、add-onであるRedis to goとMongoHQを使用していますが、Redis to goはフリープランでは10コネクションまでしかサポートされていないので、一度に2コネクション使用するももクロスライダーでは5アクセスしか同時に並列で使えません。
それを裏付けるグラフもとれたので紹介します。
この折れ線グラフを見て下さい、青がRedis、赤がMongoです。1000のリクエストを平均するのではなく、1つ1つ描画するとこのグラフになります。横軸がリクエスト発行順番、縦軸がレスポンスタイムです。1〜300番目のリクエストくらいだと早いのが分かります。
500〜600番目のリクエストまではRedisの方が優っていますが、徐々にコネクションがとれなくなり、Redisのレスポンスが下がることが分かります。
最終的な1000番目のリクエストには22秒くらいレスポンスに要していました。
Mongo HQのコネクションに関しては調査不足で分かりませんが、多少安定してレスポンスを返している所から、少なくとも10よりも大きく取られているように感じます。
ここから言えることは、ある程度クライアントが少ない間はRedis To Goの方が良いです。
600クライアント同時接続程度であれば5秒もかからずに返しています。600クライアント以上から同時に接続されるようなケースでは、Redis To Goのプランを見直すかMongo HQの方が良いかも知れません。
まとめ
Redisはやっぱり高速でした。3点まとめです。
- ローカル環境の単純なアクセスではRedis は爆速。
- Heroku環境でもネットワークがボトルネックになるもののかなり高速を維持する。
- クライアントの同時接続数が増えるとRedis To Go アドオンのコネクション数が頭打ちになるため、場合によってはMongoよりも遅くなる。
RedisとMongoだと特質が違うのでもちろん一概に性能だけを比較するものではありませんが、人気を二分するデータストアとしてベンチした甲斐はあったのかと思います。他にもHerokuにはMongo labとかのアドオンもあるので、気になるところです。また、memcached等、他のインメモリKVSと比較するのもいいかも知れませんね。
ももクロスライダー作ったよ。(Redisを使ったアプリをHerokuに置く) 第一弾
この前のNode学園でRedisを使ったアプリが多いのと、社内勉強会でRedisの話が出てきたので、試しにRedis使って何かアプリで実践してみようと思いやってみました。
Redisというのは危険なほど速いと噂のインメモリKVSです。memcachedと同じような感じですが、永続化ができること、memcachedよりも高速であること、pub/subという通知機能がある事が特徴です。
あと、せっかくだから最近ハマっているももクロの画像を流すアプリでも作ってやれ、という下心もプラスして作りました、「ももクロスライダー」
yosuke-furukawa/momoclo-slider · GitHub
ももクロスライダーの中身は Node.js + Redis + socket.ioになっています。
twitpicから #momoclo の付いた画像を持ってきて、Redisへ一定間隔でセット、せっかくなので、pub/subで新しい画像があったらクライアントへsocket.ioを使って送信までしてみました。特に画像を毎回見に行かなくてもそのまま流しておけば勝手に新しい画像を取ってきてくれるような仕組みになっています。
今回の話はももクロスライダーの中身の話を交えつつ、RedisをHerokuで使う時の注意点を伝えられるといいかなと思います。
■ app.js
/** * Module dependencies. */ var express = require('express') , routes = require('./routes'); var twitpic = require('twitpic').TwitPic; var redis = require('redis'); var io = require('socket.io'); var redisClient, subscriber; var port = process.env.PORT || 3000; // Herokuに置く場合、REDISTOGO_URLがSETされているので、その時は以下のようにする。 if (process.env.REDISTOGO_URL) { var rtg = require("url").parse(process.env.REDISTOGO_URL); redisClient = redis.createClient(rtg.port, rtg.hostname); subscriber = redis.createClient(rtg.port, rtg.hostname); redisClient.auth(rtg.auth.split(":")[1]); subscriber.auth(rtg.auth.split(":")[1]); } else { redisClient = redis.createClient(); subscriber = redis.createClient(); } var app = module.exports = express.createServer(); // Configuration redisClient.on("error", function(err) { console.log("Error! " + err); }); subscriber.subscribe('images'); var keyword = 'momoclo'; app.configure(function(){ app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(app.router); app.use(express.static(__dirname + '/public')); // setIntervalで1分間隔でtwitpicを検索。 setInterval(function() { try { console.log("keyword = " + keyword); twitpic.query('tags/show', {tag: keyword}, function (data){ if(data) { for (var index in data.images) { existsAndSet(data, index, keyword); } } }); } catch (e) { console.log(e); } }, 60000); }); app.configure('development', function(){ app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); }); app.configure('production', function(){ app.use(express.errorHandler()); }); // Routes app.get('/', routes.index); app.get('/img', function(req, res){ redisClient.hvals("images", function (err, images) { console.log('redis connect.'); if (!images) { console.log("images is null"); getImages(res); } else { var imageData = []; for (var index in images) { imageData.push(JSON.parse(images[index])); } res.json({title: keyword, data: imageData}); } }); }); //存在していたらsetしてpublishします。 function existsAndSet(data, index, keyword) { redisClient.hexists("images", data.images[index].short_id, function (err, res) { if (err) { console.log(err); } else if (res == 0) { if (data.images[index].message.indexOf(keyword) >= 0) { var jsonData = { category: 'twitpic', short_id: data.images[index].short_id, message: data.images[index].message, username: data.images[index].user.username, width: data.images[index].width, height: data.images[index].height }; redisClient.hset("images", data.images[index].short_id, JSON.stringify(jsonData), redis.print); redisClient.publish('images', JSON.stringify(jsonData)); } } else { //KEY EXISTS, DO NOTHING } }); } function getImages(res) { console.log("method getImages begin"); var imgJsonArray = new Array(); try { twitpic.query('tags/show', {tag: keyword}, function (data) { if (data) { for (var index in data.images) { var jsonData = { category: 'twitpic', short_id: data.images[index].short_id, message: data.images[index].message, username: data.images[index].user.username, width: data.images[index].width, height: data.images[index].height }; imgJsonArray.push(jsonData); redisClient.hset("images", data.images[index].short_id, JSON.stringify(jsonData), redis.print); } res.json( { title: 'Express1', data: imgJsonArray }); } }); } catch (e) { console.log(e); } } io = io.listen(app); //subscriberが受信したら、その内容をsocket.ioでemitします。 subscriber.on('message', function(channel, message) { console.log('getMessage: ' + message); io.sockets.emit('updated', JSON.parse(message)); }); app.listen(port, function(){ console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env); });
Herokuに置くときの注意点はココです。
// Herokuに置く場合、REDISTOGO_URLがSETされているので、その時は以下のようにする。 // Herokuの場合 if (process.env.REDISTOGO_URL) { var rtg = require("url").parse(process.env.REDISTOGO_URL); redisClient = redis.createClient(rtg.port, rtg.hostname); subscriber = redis.createClient(rtg.port, rtg.hostname); redisClient.auth(rtg.auth.split(":")[1]); subscriber.auth(rtg.auth.split(":")[1]); } // Herokuじゃない場合 else { redisClient = redis.createClient(); subscriber = redis.createClient(); }
REDISTOGO_URLにauth用の文字列も格納されているのでそれを使ってredisのクライアントの認証を済ませておくことがポイントです。
Redisライブラリによっては面倒なurlのparseをしなくてもいいところがあるみたいですが、ひとまずnode_redisライブラリではこの様にします。
コマンドでは以下のようにしてデプロイします。
$ git init $ git add . $ git commit -m "slider appli." $ heroku create --stack cedar momoclo-slider $ heroku addons:add redistogo:nano $ git push heroku master
redistogo:nanoであれば無料で5MBまでですが使えます。
最近では、このRedisをセッション管理に使ってsocket.ioをスケールアウトするのにも使えるみたいですね。
自分も試してみよう。
次回はRedisじゃなくてMongoの場合、twitpicから取得してくるだけの場合でベンチ比較してみようかと思います。
play2.0でアプリをherokuにデプロイするまでの道のり
先日、四則演算で10を作るプログラムをScalaで書いてみたので、それをwebアプリ(Make10)にしてみました。
今回はPlay 2.0で作ったサイトをherokuにデプロイするまでやった事を簡単に説明していきます。
ちなみに四則演算の問題を前に出していました。
https://twitter.com/yosuke_furukawa/status/181063838932799488:twitter:detail:left
これの答えは以下の通り:
7,8,8,9の答え
4,4,6,6の答え
4,4,6,7の答え
4,5,5,9の答え
5,5,5,7の答え
3,4,7,8の答え
1,1,5,8の答え
さてさて、冒頭の通り、今回Play Framework 2.0でWebアプリ(Make10)にしてみました。
Play Framework 2.0からScala主体になっている上に色々な機能が追加されています。
Play1.0との差異は以下のサイトに書かれています。
API Only - Stack Exchange
Play2.0のアプリをherokuにデプロイするまでやった事を簡単に説明していきます。
まずはwebアプリをローカルで動作するようにします。
$ play new make10
これでひな形アプリが作られます。
これだけだと何でもないアプリなので、変更をしていきます。
まず自分はEclipse派なので、eclipseプロジェクト化を行います。
$ cd make10
$ play
と実行してください。
その後、
[make10] $ eclipsify
と実行するとeclipseプロジェクトにしてくれます。
そこからeclipseへ既存プロジェクトのインポートをすればeclipseプロジェクトとして実行できます。
※このやり方だとviewsに変更を加えても即座に反映はされないようです。Eclipseでエラーになってもブラウザで見るとエラーになっていない事が多いです。この辺りはScala IDE側の問題としてPlay teamは説明しています。
Documentation: IDE — Playframework
Application.scalaに変更を加えていきます。
一応何の変更をしたかを書いておきます。
Applicaiton.scala
package controllers import play.api._ import play.api.mvc._ import core.Make10 import play.api.templates.Html object Application extends Controller { def index = Action {implicit request => taskForm.bindFromRequest.fold( errors => Ok(views.html.index("Please input 4 digit numbers")), label => { val array = label.split(' ').toList.map { _.toInt } if (array.length != 4) { BadRequest(views.html.index("error!! please input 4 digit numbers.")) } else { val list10 = Make10.make10(array) println(array) println(list10) if (list10.size >= 1) { val answerList = list10.map{_._2} Ok(views.html.answers("Please input 4 digit numbers", new Html(answerList.mkString("<li>10 = ","</li><li>10 = ", "</li>")))) } else { Ok(views.html.index("The answer is nothing. " + label)) } } } )} }
変更したらサーバーを走らせてみます。
[make10] $ run
localhostに9000でアクセスすれば結果が得られます。
完成したらherokuにデプロイします。
まず、herokuにデプロイするためにProcfileをプロジェクトのルートフォルダに作ります。
Procfile
web: target/start -Dhttp.port=${PORT} -DapplyEvolutions.default=true
その後、プロジェクトのルートフォルダで以下のコマンドを実行します。
$ git init
$ git add .
$ git commit -m "init"
gitが入っていない場合はインストールしてください。
gitでのコミットが終わったら、以下のherokuコマンドを実行します。
$ heroku create --stack cedar
これでherokuにアプリケーションのプラットフォームができます。
$ git push heroku master
これでherokuにpushされます。
こんな感じでデプロイできます。
デフォルトで作成される名前が気になるようならrenameもできます。
さて、これでwebアプリになったので、どんな問題が出ても解けるね。
9 9999 9999 99999
とかも解けるね( ̄ー ̄ )
English Tweet Botの英語追加ページを若干アップグレード。
English Tweet Bot
・English Tweet BotのページにあったEditボタンとdeleteボタンを実装しました。
・追加した人以外が編集/削除してもエラーになるようにしました。
・Botのコメントに#English, #eigoのハッシュタグをつけるようにしました。
あまり大きな変更ではないですが。
デザインも刷新していきたいですね。
これを使ってみようと思います↓
Twitter Bootstrap
追記:ちょっと使ってみました。
かっこよくなったのはいいのですが、少し薄くて見にくいような・・・。