Re: 2.0.4-scala

193 views
Skip to first unread message

Nick Fisher

unread,
Oct 17, 2012, 8:05:30 AM10/17/12
to play-fr...@googlegroups.com
try something like this(not tested, but should be close enough):

def wsExample = Action {
val writer = new FileOutputStream("example.pdf")  

Async {
  val wsStream = new Enumerator[Array[Byte]] { 
     def apply[A](iteratee: Iteratee[Array[Byte], A]) = { 
       WS.url("http://example.org/papers/example.pdf").get(_ => iteratee) 
     } 
   }

   wsStream.apply(Iteratee.foreach(bytes => writer write bytes)) map {
     writer.close()
     Ok("OK")
   }
}
}

Nick Fisher

unread,
Oct 17, 2012, 8:38:35 PM10/17/12
to play-fr...@googlegroups.com
try this(again, not tested):

def wsExample = Action {
    Async {
      val writer = new java.io.FileOutputStream("/opt/example.pdf")


      val wsStream = new Enumerator[Array[Byte]] {
        def apply[A](iteratee: Iteratee[Array[Byte], A]) = {
          WS.url("http://example.org/papers/example.pdf").get(_ => iteratee)
        }
      }

      val promise = wsStream.apply(Iteratee.foreach(bytes => writer write bytes))

      promise.onComplete {
        case _ => writer.close()
      }

      promise.map {
        iteratee => {
          Ok("OK")
        }
      }
    }
  }

Nick Fisher

unread,
Oct 18, 2012, 1:55:25 PM10/18/12
to play-fr...@googlegroups.com
Sorry about the onComplete with Promise, I'm working with 2.1, which does away with Play's Promise in favor of the scala.concurrent.Promise, which has onComplete instead of onRedeem.  I have a few other ideas on this, I'll give them a try later tonight and see if I can get some working code for you.  Do you happen to have an example of a sufficiently large file that is publicly available, so I can test it out?

Nick Fisher

unread,
Oct 18, 2012, 7:09:04 PM10/18/12
to play-fr...@googlegroups.com
The code below allowed me to download all 575 MB and closes the FileOutputStream correctly:

package controllers

import play.api.mvc._
import play.api.Play.current
import play.api.libs.iteratee._
import play.api.libs.ws.WS._
import concurrent.ExecutionContext.Implicits.global
import java.io.FileOutputStream

object TestController extends Controller {
  def example = Action {
    val writer = new FileOutputStream("%s/tears_of_steel_1080p.mkv".format(System.getProperty("user.home")))

    val asyncResult = Async {
      url("http://arcagenis.org/mirror/mango/ToS/tears_of_steel_1080p.mkv").withTimeout(12000000).get {_ =>
        Iteratee.foreach[Array[Byte]](chunk => writer write chunk)
      } map { _ => Ok("OK") }
    }

    asyncResult.result onComplete {
      case _ =>
        println("Closing writer")
        writer.close()
    }

    asyncResult
  }
}


Again, this is on Play 2.1, so you'll have to substitute the onComplete for onRedeem.  Also note the very long timeout set on the http request.  WS.url defaults to a 2 minute timeout, which may be why the previous examples did not work.  I got a timeout and could not finish downloading when I tried this code without the withTimeout method.

Nick Fisher

unread,
Oct 19, 2012, 6:32:10 PM10/19/12
to play-fr...@googlegroups.com
In 2.0.4, try setting the ws.timeout value in your configuration file, since the withTimeout method is not exposed.  If this works correctly, I would point to the SimpleHTTPServer as being the problem, not Play.  I'm not familiar with SimpleHTTPServer, but being a simple implementation, it's probably not well suited to serving large files and may have a default response timeout that is killing your connection mid-download.  If you want to test on a local server, try apache, nginx, lighttpd, etc... and see if those work correctly.

Nick Fisher

unread,
Oct 21, 2012, 9:46:07 AM10/21/12
to play-fr...@googlegroups.com
when the download fails to complete, are you getting any error messages from the Play logs, or in the nginx logs?
Reply all
Reply to author
Forward
0 new messages