h2oとmruby
ある日、
「h2oとmruby使ったらhtmlがなくてもresponse返せるんじゃないか?」
と思ったので、やってみることにしました。
mrubyでどのように返すデータを持つか
さて、responseの内容をmruby scriptの中にベタ書きするのはカッコ悪そうなので、yamlに記述して、外部から読みこむことにします。
h2oの用意
ひとまず、mrubyで簡単なresponseを返すh2oを用意します。
FROM unasuke/h2o-alpine:v2.0.4
COPY . /etc/h2o
CMD ["h2o", "--mode=master", "-c", "h2o.conf"]
listen: 80
hosts:
"127.0.0.1:80":
paths:
"/":
mruby.handler-file: server.rb
access-log: /dev/stdout
class Server
def call(env)
[200,
{
"content-type" => "text/plain; charset=utf-8",
},
["Hello mruby in h2o!"]
]
end
end
Server.new
Create simple server · unasuke/mruby_ac2016@27cf7eb
# buildしてrun
% docker build -t h2o_mruby .
% docker run -it -p 8080:80 h2o_mruby
すると、このように8080番ポートでアクセスできるようになりました。mrubyがresponseを返しているのがわかります。
mrubyがyamlを読みこむために
mruby scriptの中でyamlを読みこむためには、AndrewBelt/mruby-yamlを使う必要があります。が、このmrbgemは素のh2oには含まれていないので、mruby-yamlを含んだh2oをbuildしなくてはいけません。
そこで、そのようなh2oを用意しました。
unasuke/h2o at mruby-yaml
用意といっても簡単で、deps
以下にmruby-yamlをcloneしてくるだけです。
そして、Dockerfileを次のように変更して、h2oをbuildします。
FROM alpine
RUN apk add --no-cache --virtual=builddeps \
bison \
ca-certificates \
cmake \
curl \
gcc \
git \
g++ \
libc-dev \
linux-headers \
make \
openssl \
perl \
ruby \
ruby-dev \
wget \
yaml-dev \
zlib-dev \
&& git clone https://github.com/unasuke/h2o.git \
&& cd h2o \
&& git checkout mruby-yaml \
&& cmake -DWITH_BUNDLED_SSL=on -DWITH_MRUBY=on . \
&& make install \
&& cd .. \
&& rm -rf h2o-* \
&& apk del builddeps \
&& apk add --no-cache --virtual=rundeps \
libstdc++ \
perl
RUN mkdir /etc/h2o
WORKDIR /etc/h2o
EXPOSE 80 443
COPY . /etc/h2o
CMD ["h2o", "--mode=master", "-c", "h2o.conf"]
Build h2o with mruby-yaml · unasuke/mruby_ac2016@4a3c552
yamlを読む
いろいろ準備が整ったので、yamlを読みこんでresponseを返していきます。
このようなyamlを用意しました。
responses:
-
path: "/"
message: "index"
-
path: "/hoge"
message: "hoge"
-
path: "/fuga"
message: "fuga"
そして、その内容に従ってresponseを返すように、mruby scriptを次のように書きかえます。
class Server
def call(env)
response = fetch_response env['PATH_INFO']
if response
[200,
{
"content-type" => "text/plain; charset=utf-8",
},
[response]
]
else
[404,
{
"content-type" => "text/plain; charset=utf-8",
},
["Not found"]
]
end
end
def fetch_response(path)
yaml = YAML.load(File.open('data.yml').read)
message = nil
yaml['responses'].each do |res|
if res['path'] == path
message = res['message']
end
end
message
end
end
Server.new
Return response from yaml · unasuke/mruby_ac2016@125a17b
docker buildしてrunすると、このようにyamlの内容に従ってresponseが返ってくるようになりました。
余談
本当はhaconiwaのなかでh2oを動作させたかったのですが、どうにもうまくできず諦めました。