Windymeltです。僕は今はてなサマーインターンで京都に滞在しており、id:masawadaが私立プログラミングキャンプのお誘いをしてくれて僕も参加してきたのでそのレポートです。私立プログラミングキャンプははてなオフィスで行われたため迷わず会場に来ることができました。会場では大量のレッドブルとサイボウズウォーターが配給?されてメンバーの戦意を高揚させていました。このキャンプ、ひとたび自己紹介が終わればいきなり作業に突入するタイプのイベントのようです。事前に何もする目標を決めていなかったので恐怖以外のなにものでもありませんでしたが、なんと同じScalaユーザであるUAdachiさんに遭遇したためScalaプログラミングをすることにしました。Device)の作成でした。Activatorを利用して開発しました。UAdachiさんはサーバサイドに強い方ということなのでJenkinsサーバの建築などを行なっていただきました。XFDを知らない方の為に説明すると、これはテストの結果などをちょっと楽しく通知しようというエクストリームプログラミング的な楽しみの一つです。電子工作やギミックなどを活用し、大々的にテストの結果をチームに共有することで修正の機運を高めようという試みです。ギミックを見てひとときの癒しを得るという非常に良い効能があります。blogなどを参照なさると良いと思います。Frameworkなどのイカした機能を用いて実装しています。Cometなんか扱わなくても良い喜びがあります。WebSocketを扱うURLとWebSocketを扱うjavascriptを送り出すURL、そしてJenkinsがWebhookとして叩くURLが必要になるため、conf/routesにルーティングの記述を行います。build_number)Jenkinsが叩くURLは本来はPOSTであるべきでしたが、うまく実装できずに時間が不足してきたためGETを用いて実装しています。続いて、リクエストを処理するためのControllerをapp/controllers/Application.scalaに実装します。全コードを載せ、続いて細かい説明を行います。}}コードの中盤でViewを呼び出している部分があります。これはrouteで/xfd/statusにGETが投げられた時に呼ばれるアクションとして定義されています。}Playではリクエストに対するアクションをActionというDSL的な囲いの中で定義します。OKでviews.html.iphone()というViewを呼び出すものです。views.html.iphoneに対応するViewは、app/views/iphone.scala.htmlに、以下のように定義されています。src="/assets/javascripts/ws.js"></script>}簡単に説明すると、最上行は引数がないことを示しており、途中の行ではmainテンプレートを"xfd"という引数で呼び出しています。mainはhtmlタグやheadタグなどの定義を共通して行う為に定義してあるものです。次にメッセージ表示のためのsectionタグが置かれ、次に/assets/javascripts/ws.jsというスクリプトが呼ばれています。このスクリプトはクライアントサイドで動作するもので、後程説明します。app/controllers/Application.scalaに戻りましょう。String)これらのケースクラスは、Actorに処理を投げるときにデータのカプセルとして使います。Akkaでのメッセージパッシングは通例ケースクラスを用いて行います。ConnectはWebSocketの接続時に、JankinsNotifyはJenkinsから飛んできたWebhookを渡すときに中間のデータホルダとして、Broadcastは接続している全てのWebSocketにメッセージを投げるときに使います。JenkinsからのWebhookの受付部分を見てみましょう。}}受け取ったクエリパラメータをJenkinsNotifyクラスにカプセル化してJenkinsReceiverに渡しています。WebSocketの受付部分を見てみましょう。}xfdメソッドはもう見ましたが、その前後を見ていきます。JenkinsReceiverクラスで定義されたアクターを作成してjenkinsReceiverという名前に割り当てています。Frameworkで半自動的に定義さているので、特に別途の設定を行う必要が無ければそのまま使うことができます。xfdWsメソッドを見てみましょう。このメソッドはクライアントがWebSocketで接続を開こうとするときに呼ばれるコードです。WebSocketの通信はActionでは処理できないため、ActionではなくWebSocket.asyncで処理しているのが分かると思います。requestが渡ってきますが、処理には必要でないので使っていません。メソッド1行目ではアクターにメッセージを投げた時にどのくらい応答が無ければタイムアウトとしてエラーを返すかを定義しています。WebSocketのタイムアウトとは関係のない定義です。そもそもWebSocketにタイムアウトはありません。メソッド2行目でjenkinsReceiverにConnectケースクラスを投げて返答させます。akka.pattern.askすることで使えるようになります。askは非同期で行われるので処理は次に進みます。Enumerator[String])という型で待ち受けるよう定義し、それをブロックの戻り値にしています。Enumerator[String])]を受けることになります。(WebSocket.asyncはdeprecatedになっているようです。tryAcceptを使えと怒られました。Enumerator[A])]]を受けます。)ここでIterateeとEnumeratorという厄介な概念が登場するのですが、Iterateeは入力を担当し、Enumeratorは出力を担当しています。ストリーミングなどの複雑な処理をを容易に行うために利用されているようなのですが、僕も良く分かっていません。Concurrent.broadcast[String]の部分では、WebSocketに接続している全てのクライアントに対して送信するためのチャンネルを取得しています。書き方次第では個別に通信できそうなのですが、このあたりの仕組みは後ほど調べたいと思います。...の部分はメッセージを受信した時の処理をパターンマッチを用いて記述しています。Connect(_)を受け取った時は"foreachでメッセージを受けて自分に対してBroadcastを送り、mapで相手が接続を終了した時はBroadcasttを投げる"という処理をiterateeとして定義しています。これを送信元にenumeratorと組にして返しています。String]をケースクラスから取り出し、selfに対してmsgをJSONに変換したものをBroadcastメッセージに載せて送信しています。Broadcastメッセージを受け取った時は接続している全てのWebSocketに対してメッセージを送信しています。クライアント側のjavascriptではJSONを受信した時にその内容で画面の色を変える操作を行なっています。メッセージが送られてくるとws.onmessageが呼ばれます。"\n");};これによりJenkinsのビルドの状況をWabhookするとクライアントに状況が通知されるシステムが出来ました。週間)Web開発者です。Lisp/Perl/Goまわりの話題が多いです。月別アーカイブスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。