playframework - Scala: Read some data of an Enumerator[T] and return the remaining Enumerator[T] -


i using asynchronous i/o library of playframework uses iteratees , enumerators. have iterator[t] data sink (for simplification it's iterator[byte] stores content file). iterator[byte] passed function handles writing.

but before writing want add statistical information @ file begin (for simplification it's 1 byte), transfer iterator following way before passing write function:

def write(value: byte, output: iteratee[byte]): iteratee[byte] =     iteratee.flatten(output.feed(input.el(value))) 

when read stored file disk, enumerator[byte] it. @ first want read , remove additional data , want pass rest of enumerator[byte] function handles reading. need transform enumerator:

def read(input: enumerator[byte]): (byte, enumerator[byte]) = {    val firstenumeratorentry = ...    val remainingenumerator = ...    (firstenumeratorentry, remainingenumerator) } 

but have no idea, how this. how can read bytes enumerator , remaining enumerator?

replacing iteratee[byte] outputstream , enumerator[byte] inputstream, easy:

def write(value: byte, output: outputstream) = {     output.write(value)     output } def read(input: inputstream) = (input.read,input) 

but need asynchronous i/o of play framework.

here 1 way achieve folding within iteratee , appropriate (kind-of) state accumulator (a tuple here)

i go read routes file, first byte read char , other appended string utf-8 bytestrings.

  def index = action {     /*let's asyncly*/     async {       /*for comprehension read-friendly*/       (         <- read; /*read file */         (r:(option[char], string)) <- i.run /*"create" related promise , run it*/       ) yield ok("first : " + r._1.get + "\n" + "rest" + r._2) /* map promised result in correct request's result*/     }   }     def read = {     //get routes file in enumerator     val file: enumerator[array[byte]] = enumerator.fromfile(play.getfile("/conf/routes"))      //apply enumerator iteratee folds data wished     file(iteratee.fold((none, ""):(option[char], string)) { (acc, b) =>        acc._1 match {          /*on first chunk*/ case none => (some(b(0).tochar), acc._2 + new string(b.tail, charset.forname("utf-8")))          /*on other chunks*/ case x => (x, acc._2 + new string(b, charset.forname("utf-8")))        }     })    } 

edit

i found yet way using enumeratee needs create 2 enumerator s (one short lived). bit more elegant. use "kind-of" enumeratee traversal 1 works @ finer level enumeratee (chunck level). use take 1 take 1 byte , close stream. on other one, use drop drops first byte (because we're using enumerator[array[byte]])

furthermore, read2 has signature more closer wished, because returns 2 enumerators (not far promise, enumerator)

def index = action {   async {     val (first, rest) = read2     val enee = enumeratee.map[array[byte]] {bs => new string(bs, charset.forname("utf-8"))}      def useenee(enumor:enumerator[array[byte]]) = iteratee.flatten(enumor &> enee |>> iteratee.consume[string]()).run.asinstanceof[promise[string]]      {       f <- useenee(first);       r <- useenee(rest)     } yield ok("first : " + f + "\n" + "rest" + r)   } }  def read2 = {   def create = enumerator.fromfile(play.getfile("/conf/routes"))    val file: enumerator[array[byte]] = create   val file2: enumerator[array[byte]] = create    (file &> traversable.take[array[byte]](1), file2 &> traversable.drop[array[byte]](1))  } 

Comments

Popular posts from this blog

django - How can I change user group without delete record -

java - Need to add SOAP security token -

java - EclipseLink JPA Object is not a known entity type -