Statistical Programming

Iteratee, Websocket周りのメモ書き

server側のwebsocketコード

  def ws =WebSocket.using[String]{ request => 

    val in=Iteratee.foreach[String]{str => str match{
      case "click"=>
        println("clicked")
      case "grasp"=>
        println(“grasp please”)
      case "drop"=>
        println("Why don we stop it here? : got from client str: "+str)
      }
    }.map { _ => println("Disconnected")}

    val out=Enumerator("1","2","3")

    (in,out)

    //Tuple(Iteratee[String],Enumerator(String))
  }

usingはwebsocketを作成するためのメソッド。返り値にWebSocketを返す。その他に2つほどWebSocketを返すメソッドがあって、一つがasyncメソッド。もう一つがadapterメソッド。まあ基本的にはusingで良さげだな…

def using[A]
(f: (RequestHeader) ⇒ (Iteratee[A, _], Enumerator[A]))(implicit frameFormatter: FrameFormatter[A]): WebSocket[A]

Creates a WebSocket result from inbound and outbound channels.

foreachは与えられたリソースひとつひとつに具体的な処理をしていくための関数。引数として各要素に行う処理内容とそのデータの型を受け取りIteratee[E,Unit]、つまり空のIterateeを返すのか…?

そしてmapは単純にIterateeの終了時に実行される処理を追加。具体的な処理内容である高階関数を引数とするIterateeは基本的にノンブロッキング故に常にopen。だから終了されるというこてゃ接続が切れたと捉えることができるのか。

def foreach[E](f: (E) ⇒ Unit)(implicit ec: ExecutionContext): Iteratee[E, Unit]
f ; the function, that should be executed for every chunk
returns ; an play.api.libs.iteratee.Iteratee which executes a provided function for every chunk. Returns Done on EOF.

Example:

// Get all chunks of input
def printChunks: Iteratee[String, Unit] = Iteratee.foreach[String]( s => println(s) )

Iterateeパッケージにあるsealed trait
Step[E, +A] extends AnyRefはIterateeの状態を表すためにある。このtraitは3つのサブクラスを持つ;Cont, Done, Error
Iteratee自体はそれを保持するためのfold関数を用意しており、その内部でstep関数を定義している。step関数はIterateeの結果である型とIterateeに入るInputを受け取りInputの種類によって挙動を変える。Input.EOF、つまりファイルの最後だという通知がきたらDone、Emptyなら単純に新しいContを作る、そしてElならば前回の状態を関数として値にいれそれを次の Contに引き継ぐために再帰を行っている。

  def fold[E, A](state: A)(f: (A, E) => A): Iteratee[E, A] = {
    def step(s: A)(i: Input[E]): Iteratee[E, A] = i match {

      case Input.EOF => Done(s, Input.EOF)
      case Input.Empty => Cont[E, A](i => step(s)(i))
      case Input.El(e) => { val s1 = f(s, e); Cont[E, A](i => step(s1)(i)) }
    }
    (Cont[E, A](i => step(state)(i)))
  }