GrailsでServer Sent Eventsを送信

このガイドではGrailsとRxJavaを使用して、Server Sent Eventsを送信する方法を解説します。

Authors: Graeme Rocher (意訳:@tyama)

Grails Version: 3.2.3

1 前準備・前説

こんばんわ、@tyamaです。

この意訳記事は、 G*Advent Calendar(Groovy,Grails,Gradle,Spock…) Advent Calendar 2016 11日目のエントリーです! Grails Guides の記事を意訳しています!今後他の記事も意訳するかもしれません! 同じように他記事を意訳した方がいたらご連絡ください! grails.jp に載っけちゃいましょう!

2016年も 今週のGrails!! 日本語版 読んで頂きありがとうございます。来年も頑張ります!

余談ですが、この記事は 元記事リポジトリ と同じ方法(asciidocを使用したgrails-doc?)で作成しました。いろいろ物足りなくて個人的には gaiden の方が好みです;-)

では、はじまりはじまり!

このガイドでは、 Server Sent Events を使用してJavaScriptクライアントと通信を行うGrailsアプリケーションの作成方法を解説します。

1.1 必要な物

このガイドを完了するには以下の項目が必要となります。:

  • 手のあいた時間

  • 使い慣れたテキストエディタまたはIDE

  • JDK 1.7以上がインストールされて JAVA_HOME が設定されている事

1.2 このガイドをコンプするには!

このガイドを完了するにはGithubにあるソースを取得してガイドのステップを順番に実行していきましょう!

始める前に以下の項目を実行してください:

grails-guides/server-sent-events/completecd するとイッキにコンプできます!

2 アプリケーション作成

2.1 RxJava依存の追加

最初に必要な依存ライブラリを設定します。 build.gradleRxJavaプラグイン を追加します。

dependencies {
    ...
    compile "org.grails.plugins:rxjava"
}

RxJavaは、リアクティブプログラミングモデルを簡単にJavaScriptクライアントにイベントを送信するために使用します。

2.2 コントローラの作成

次に、 TickTock という名称でコントローラを作成します。 Grailsがインストールされている場合 grails create-controller コマンドを使用します。インストールされていない場合は grailsw というコマンドラッパーを使用します。

$ ./grailsw create-controller TickTock
最初の grails コマンド実行でアプリケーションに必要な依存関係をダウンロードするため遅いですが、以降のコマンドではもっと速くなります。

コマンドの出力は次のようになります:

| Created grails-app/controllers/example/TickTockController.groovy
| Created src/test/groovy/example/TickTockControllerSpec.groovy

grails-app/controllers/example ディレクトリに新たにコントローラが生成されています。Grailsでは、 grails-app/conf/application.yml に設定されている grails.codegen.defaultPackage の値でパッケージ名を設定します。

2.3 コントローラの実装

コントローラが生成されたので、今度はRxJavaの機能を活用するための実装を行います。 grails.rx.web.RxController traitを使用するために必要なimportとimplementsを追加します。

grails-app/controllers/example/TickTockController.groovy
import rx.Subscriber
import grails.rx.web.*
/**
 * Demo Server Sent Events Controller
 */
class TickTockController implements RxController {

次に index アクションを実装します。 index アクションは指定が無い限りコントローラのデフォルトアクションとなります。

RxController traitは、 rx というヘルパーをコントローラに追加しコントローラからクライアントへのレスポンスをコントロールする事が可能になります。

Server Sent Eventsを開始するには、 rx.stream(..) メソッドを使用します:

grails-app/controllers/example/TickTockController.groovy
def index() {
    rx.stream { Subscriber subscriber ->
    }
}

stream メソッドには、 rx.Observer インターフェイスから送信されたデータが送信できる状態になったらクライアントにイベント送信を行う rx.Subscriber インスタンスを受け取るクロージャを渡します。

rx ヘルパーのメソッドを使用して、Subscriberの onNext メソッドに値を受け渡します。例として:

grails-app/controllers/example/TickTockController.groovy
for(i in (0..5)) {
    if(i % 2 == 0) {
        subscriber.onNext(
            rx.render("Tick")
        )
    }
    else {
        subscriber.onNext(
            rx.render("Tock")
        )
    }
    sleep 1000
}

この例では0から5の間をループして奇数と偶数でそれぞれ rx.render(..) をよびだし、それぞれ"Tick"または"Tock"を出力します。 sleep(..) の実行では、外部のWebサービスが取得できるようにスローなリクエストをシミュレートしています。

イベント送信が完了したらSubscriberの onCompleted イベントでイベントを完了させます:

grails-app/controllers/example/TickTockController.groovy
subscriber.onCompleted()

以下が完全なロジックです:

grails-app/controllers/example/TickTockController.groovy
def index() {
    rx.stream { Subscriber subscriber ->
        for(i in (0..5)) {
            if(i % 2 == 0) {
                subscriber.onNext(
                    rx.render("Tick")
                )
            }
            else {
                subscriber.onNext(
                    rx.render("Tock")
                )
            }
            sleep 1000
        }
        subscriber.onCompleted()
    }
}

2.4 クライアント実装

クライアント側を実装するには先ず grails-app/index.gsp を開き追加ヘッダーを "Welcome to Grails" <h1> の次の行に追加します:

grails-app/views/index.gsp
<h1>Welcome to Grails</h1>
<h2 style="text-align:center;font-size:50px" id="message"></h2>

このヘッダーにはServer Sent Eventsから受信した内容を表示する場所とします。

次に以下の <script> ブロックをページの下部に追加します:

grails-app/views/index.gsp
<script type="text/javascript">
    (function() {
        var eventSource = new EventSource("tickTock");
        eventSource.onmessage = function(event) {
            console.log("data: "+event.data)
            document.getElementById('message').innerHTML = event.data;
        };
    })();
</script>

このJavaScriptコードは、Server Sent Eventの EventSource オブジェクトを使用してコントローラからのイベント受信を開始します:

grails-app/views/index.gsp
var eventSource = new EventSource("tickTock");
EventSource オブジェクトを使用するには モダンブラウザ が必要です。

そして、最初に追記した <h2> ヘッダーをサーバからのレスポンスで更新するリスナーをレジストします:

grails-app/views/index.gsp
eventSource.onmessage = function(event) {
    console.log("data: "+event.data)
    document.getElementById('message').innerHTML = event.data;
};

からのー、、、それだけです!これであとはアプリケーションを起動するだけです。

3 アプリケーション起動

アプリケーションを起動するには、 ./gradlew bootRun コマンドを実行します。 8080ポートで起動します。

http://localhost:8080 を表示すると、"Welcome to Grails!"メッセージの下で、サーバイベントを受信して"Tick"と"Tock"が入れ替わるのがわかります。