Instan Vert.xを読みながらサンプルコードを試してみる。
今回はChat Server。
本の中のコードはほとんどJavaScriptで書かれているのだけれども、Javaの方がAPIを追っかけやすいのとJava8の勉強をかけてJavaで再実装。
コードはこんな感じ。
public class ChatServer extends Verticle {
private static final String MESSAGE_BROADCAST_ADDRESS = "broadcast_address";
public void start() {
NetServer netserver = vertx.createNetServer();
netserver.connectHandler((NetSocket socket) -> {
InetSocketAddress remoteAddr = socket.remoteAddress();
String addr = String.format("%s:%d", remoteAddr.getAddress(), remoteAddr.getPort());
socket.write(String.format("Welcome to the chat %s!", addr));
// コネクション1つにつき1つのハンドラを登録する。
Handler<Message<String>> messageHandler = (event) -> {
socket.write(event.body());
};
vertx.eventBus().registerHandler(MESSAGE_BROADCAST_ADDRESS, messageHandler);
// ソケットからメッセージを受け取ったときにEventBusを通じてメッセージをpublishする。
socket.dataHandler((Buffer data) -> {
ZonedDateTime now = ZonedDateTime.now();
String msg = String.format("%s<%s>: %s", now, addr, data);
vertx.eventBus().publish(MESSAGE_BROADCAST_ADDRESS, msg);
});
// コネクションが閉じられたらEventBusから閉じられたコネクションのメッセージハンドラを取り除く。
socket.closeHandler((Void event) -> {
vertx.eventBus().unregisterHandler(MESSAGE_BROADCAST_ADDRESS, messageHandler);
});
});
netserver.listen(1234);
}
}
サーバーへの接続は
telnet localhost 1234
でできる。
closeハンドラの所は本に載っていなかったけど、実装しておいた。ソケットにつなぐたびにEventBusにハンドラを登録する仕組みなので、接続がとじられた時にハンドラを除く処理がないとリークするはず。
Clojureでも書いてみた。
(ns chatsample-clj.core
(:require [vertx.core :as vertx]
[vertx.net :as net]
[vertx.stream :as stream]
[vertx.eventbus :as eb]))
(def ^:dynamic **broadcast-address** "broadcast-address")
(defn -connect-handler [sock]
(let [message-handler (fn [event] (stream/write sock event))
remote-addr (net/remote-address sock)
addr-info (format "%s:%d" (:host remote-addr) (:port remote-addr))
data-handler (fn [data] (let [now (java.time.ZonedDateTime/now)]
(eb/publish **broadcast-address**
(format "%s<%s> %s" now addr-info data))))]
(eb/on-message **broadcast-address** message-handler)
(-> sock
(stream/write (format "Welcome to the chat %s" addr-info))
(stream/on-data data-handler)
(net/on-close #(eb/unregister-handler **broadcast-address** message-handler)))))
(defn init[]
(let [server (net/server)]
(-> server
(net/on-connect -connect-handler)
(net/listen 1234 "localhost"))))