Tôi đang cố gắng hiểu các khái niệm I/O phản ứng của khung công tác Play 2.0. Để có được sự hiểu biết tốt hơn từ đầu, tôi quyết định bỏ qua các trình trợ giúp của khung công tác để xây dựng các loại lặp lại và viết Iteratee
tùy chỉnh từ đầu để được sử dụng bởi một số BodyParser
để phân tích cú pháp phần thân yêu cầu.Tại sao làm cho lỗi gọi điện thoại hoặc thực hiện trong một Iteratee của BodyParser yêu cầu treo trong Play Framework 2.0?
Bắt đầu với những thông tin có sẵn trong Iteratees và ScalaBodyParser tài liệu và hai bài thuyết trình về vở kịch phản ứng I/O này là những gì tôi đã đưa ra:
import play.api.mvc._
import play.api.mvc.Results._
import play.api.libs.iteratee.{Iteratee, Input}
import play.api.libs.concurrent.Promise
import play.api.libs.iteratee.Input.{El, EOF, Empty}
01 object Upload extends Controller {
02 def send = Action(BodyParser(rh => new SomeIteratee)) { request =>
03 Ok("Done")
04 }
05 }
06
07 case class SomeIteratee(state: Symbol = 'Cont, input: Input[Array[Byte]] = Empty, received: Int = 0) extends Iteratee[Array[Byte], Either[Result, Int]] {
08 println(state + " " + input + " " + received)
09
10 def fold[B](
11 done: (Either[Result, Int], Input[Array[Byte]]) => Promise[B],
12 cont: (Input[Array[Byte]] => Iteratee[Array[Byte], Either[Result, Int]]) => Promise[B],
13 error: (String, Input[Array[Byte]]) => Promise[B]
14 ): Promise[B] = state match {
15 case 'Done => { println("Done"); done(Right(received), Input.Empty) }
16 case 'Cont => cont(in => in match {
17 case in: El[Array[Byte]] => copy(input = in, received = received + in.e.length)
18 case Empty => copy(input = in)
19 case EOF => copy(state = 'Done, input = in)
20 case _ => copy(state = 'Error, input = in)
21 })
22 case _ => { println("Error"); error("Some error.", input) }
23 }
24 }
(Ghi chú: Tất cả những điều này là mới với tôi Vì vậy, xin vui lòng tha thứ nếu một cái gì đó về điều này là tổng số crap.) Iteratee là khá câm, nó chỉ đọc tất cả các khối, tổng hợp số lượng byte nhận được và in ra một số tin nhắn. Mọi thứ hoạt động như mong đợi khi tôi gọi hành động điều khiển với một số dữ liệu - tôi có thể quan sát tất cả các khối được nhận bởi Iteratee và khi tất cả dữ liệu được đọc, nó chuyển sang trạng thái được thực hiện và yêu cầu kết thúc.
Bây giờ tôi bắt đầu để chơi xung quanh với mã vì tôi muốn thấy những hành vi đối với hai trường hợp sau đây:
- Switching vào lỗi trạng thái trước khi tất cả các đầu vào được đọc.
- Chuyển sang trạng thái được thực hiện trước khi tất cả đầu vào được đọc và trả lại
Result
thay vìInt
.
Sự hiểu biết của tôi về tài liệu được đề cập ở trên là cả hai có thể thực hiện được nhưng thực tế tôi không thể hiểu hành vi được quan sát. Để kiểm tra trường hợp đầu tiên tôi đã thay đổi dòng 17 của mã trên thành:
17 case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Error else 'Cont, input = in, received = received + in.e.length)
Vì vậy, tôi vừa thêm điều kiện để chuyển sang trạng thái lỗi nếu nhận được hơn 10000 byte. Kết quả tôi nhận được là:
'Cont Empty 0
'Cont El([[email protected]) 8192
'Error El([[email protected]) 16384
Error
Error
Error
Error
Error
Error
Error
Error
Error
Error
Error
Sau đó, yêu cầu treo vĩnh viễn và không bao giờ kết thúc. Kỳ vọng của tôi từ các tài liệu được đề cập ở trên là khi tôi gọi hàm error
bên trong fold
của Iteratee, quá trình xử lý phải được dừng lại. Những gì đang xảy ra ở đây là phương pháp gấp của Iteratee được gọi nhiều lần sau khi error
được gọi - tốt và sau đó yêu cầu bị treo.
Khi tôi chuyển sang trạng thái đã hoàn thành trước khi đọc tất cả đầu vào, hành vi tương tự. Thay đổi dòng 15 để:
15 case 'Done => { println("Done with " + input); done(if (input == EOF) Right(received) else Left(BadRequest), Input.Empty) }
và dòng 17 để:
17 case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Done else 'Cont, input = in, received = received + in.e.length)
xuất ra như sau:
'Cont Empty 0
'Cont El([[email protected]) 8192
'Done El([[email protected]) 16384
Done with El([[email protected])
Done with El([[email protected])
Done with El([[email protected])
Done with El([[email protected])
và một lần nữa yêu cầu treo mãi mãi.
Câu hỏi chính của tôi là tại sao yêu cầu bị treo trong các trường hợp được đề cập ở trên. Nếu ai đó có thể làm sáng tỏ điều này, tôi sẽ đánh giá cao điều đó!
Cảm ơn bạn đã sửa chữa và các từ loại, sẽ cố gắng sửa chữa càng sớm càng tốt! – lost