Here's an (untested) example of using PlayServiceCall to parse multipart/form-data files. This example doesn't buffer the file in memory (like your example does), but rather writes it straight to disk, so there's no risk of running out of memory (though there is a risk of running out of disk, but Play's built in multipart/form-data parser has a configurable limit to how much data it will write to disk per request). Using fully qualified classes to make it clear.
def myServiceCall: ServiceCall[NotUsed, SomeResult] = PlayServiceCall { wrapCall =>
// Create a Play action, and give it the multipartFormData body parser to parse the body
play.api.mvc.Action(play.api.mvc.BodyParsers.parse.multipartFormData({ fileInfo =>
// This is a file part handler, it will be invoked once for each file part that
// the request contains, passing in the fileInfo which gives you access to things
// like the name of the field they entered it into, the name of the file on their
// machine, and the files content type. You're expected to return an accumulator
// (wrapper for an Akka streams Sink) that will be used to consume the file, for
// example, that will write it to disk. The result of the accumulator will then
// be accessible below once all files have been uploaded. In this case, since
// we're generating a random file name, we'll map the accumulator to return that
// file name, so we can then do further processing on the file.
val file = new File(s"data/wakefield/uploads/${UUID.randomUUID()}.xlsx")
val sink = akka.stream.scaladsl.FileIO.toPath(file.toPath)
play.api.libs.streams.Accumulator(sink).map {
case akka.stream.IOResult(bytesWritten, status) =>
// Check if status.success is true if you want, or whatever. In this case,
// we'll just return the file that was written.
file
}
}) { request =>
// request is a play.api.mvc.Request[play.api.mvc.MultipartFormData[File]]
// You could just directly handle the request here, and generate a Play Result,
// but if you want Lagom to handle serializing the result of the ServiceCall,
// then you can use wrapCall to convert a ServiceCall that returns SomeResult
// into an action, and then invoke that action.
val wrappedAction = wrapCall(ServiceCall { _ =>
// Here's all the uploaded files, you can do with them what you want. If
// you returned something other than File from the file part handler, then
// the type parameter to FilePart would be the type of that thing that you
// returned.
val files: Seq[FilePart[File]] = request.body.files
// Create the result, can be whatever you want, will be serialized by Lagom.
val someResult = ....
Future.successful(someResult)
})
wrappedAction.apply(request).run()
}
}