/framework/src/play/src/main/scala/play/api/libs/iteratee/Concurrent.scala

https://github.com/julienrf/playframework · Scala · 232 lines · 177 code · 54 blank · 1 comment · 8 complexity · b39ae122d9d9621760512b6536f24c35 MD5 · raw file

  1. package play.api.libs.iteratee
  2. import play.api.libs.concurrent._
  3. object Concurrent {
  4. def dropInputIfNotReady[E](duration: Long, unit: java.util.concurrent.TimeUnit = java.util.concurrent.TimeUnit.MILLISECONDS): Enumeratee[E,E] = new Enumeratee[E,E] {
  5. def applyOn[A](it: Iteratee[E,A]): Iteratee[E,Iteratee[E,A]] = {
  6. def step(inner: Iteratee[E,A])(in:Input[E]):Iteratee[E,Iteratee[E,A]] = {
  7. in match {
  8. case Input.EOF =>
  9. Done(inner,Input.Empty)
  10. case in =>
  11. val readyOrNot: Promise[Either[Iteratee[E,Iteratee[E,A]],Unit]] = inner.pureFold[Iteratee[E,Iteratee[E,A]]](
  12. (a,e) => Done(Done(a,e),Input.Empty),
  13. k => Cont{ in =>
  14. val next = k(in)
  15. Cont(step(next))
  16. },
  17. (msg,e) => Done(Error(msg,e),Input.Empty)).orTimeout((),duration,unit)
  18. Iteratee.flatten( readyOrNot.map {
  19. case Left(ready) => Iteratee.flatten(ready.feed(in))
  20. case Right(_) => Cont(step(inner))
  21. })
  22. }
  23. }
  24. Cont(step(it))
  25. }
  26. }
  27. trait Hub[E] {
  28. def getPatchCord(): Enumerator[E]
  29. def noCords(): Boolean
  30. def close()
  31. }
  32. def hub[E](e: Enumerator[E], interestIsDownToZero: () => Unit = () => ()): Hub[E] = {
  33. import scala.concurrent.stm._
  34. val iteratees: Ref[List[(Iteratee[E, _], Redeemable[Iteratee[E, _]])]] = Ref(List())
  35. var closeFlag = false
  36. def step(in: Input[E]): Iteratee[E, Unit] = {
  37. val interested: List[(Iteratee[E, _], Redeemable[Iteratee[E, _]])] = iteratees.single.swap(List())
  38. val commitReady: Ref[List[(Int, (Iteratee[E, _], Redeemable[Iteratee[E, _]]))]] = Ref(List())
  39. val commitDone: Ref[List[Int]] = Ref(List())
  40. val ready = interested.zipWithIndex.map {
  41. case (t, index) =>
  42. val p = t._2
  43. t._1.fold(
  44. (a, e) => {
  45. p.redeem(Done(a, e))
  46. commitDone.single.transform(_ :+ index)
  47. Promise.pure(())
  48. },
  49. k => {
  50. val next = k(in)
  51. next.pureFold(
  52. (a, e) => {
  53. p.redeem(Done(a, e))
  54. commitDone.single.transform(_ :+ index)
  55. },
  56. k => commitReady.single.transform(_ :+ (index, (Cont(k), p))),
  57. (msg, e) => {
  58. p.redeem(Error(msg, e))
  59. commitDone.single.transform(_ :+ index)
  60. })
  61. },
  62. (msg, e) => {
  63. p.redeem(Error(msg, e))
  64. commitDone.single.transform(_ :+ index)
  65. Promise.pure(())
  66. })
  67. }.fold(Promise.pure()) { (s, p) => s.flatMap(_ => p) }
  68. Iteratee.flatten(ready.map { _ =>
  69. val (hanging, downToZero) = atomic { implicit txn =>
  70. val responsive = (commitReady().map(_._1) ++ commitDone()).toSet
  71. val hangs = interested.zipWithIndex.collect { case (e, i) if !responsive.contains(i) => e }
  72. //send EOF to hanging
  73. val ready = commitReady().toMap
  74. iteratees.transform(commitReady().map(_._2) ++ _)
  75. (hangs, (interested.length > 0 && iteratees().length <= 0))
  76. }
  77. hanging.map {
  78. case (h, p) => h.feed(Input.EOF).extend1 {
  79. case Redeemed(it) => p.redeem(it)
  80. case Thrown(e) => p.redeem(throw e)
  81. }
  82. }
  83. if (downToZero) interestIsDownToZero()
  84. if (in == Input.EOF || closeFlag) Done((), Input.Empty) else Cont(step)
  85. })
  86. }
  87. e |>> Cont(step)
  88. new Hub[E] {
  89. def noCords() = iteratees.single().isEmpty
  90. def close() {
  91. closeFlag = true
  92. }
  93. def getPatchCord() = new Enumerator[E] {
  94. def apply[A](it: Iteratee[E, A]): Promise[Iteratee[E, A]] = {
  95. val result = Promise[Iteratee[E, A]]()
  96. iteratees.single.transform(_ :+ ((it, result.asInstanceOf[Redeemable[Iteratee[E, _]]])))
  97. result
  98. }
  99. }
  100. }
  101. }
  102. trait PatchPanel[E] {
  103. def patchIn(e: Enumerator[E]): Boolean
  104. def closed(): Boolean
  105. }
  106. def patchPanel[E](patcher: PatchPanel[E] => Unit): Enumerator[E] = new Enumerator[E] {
  107. import scala.concurrent.stm._
  108. def apply[A](it: Iteratee[E, A]): Promise[Iteratee[E, A]] = {
  109. val result = Promise[Iteratee[E, A]]()
  110. var isClosed: Boolean = false
  111. result.onRedeem(_ => isClosed = true);
  112. def refIteratee(ref: Ref[Iteratee[E, Option[A]]]): Iteratee[E, Option[A]] = {
  113. val next = Promise[Iteratee[E, Option[A]]]()
  114. val current = ref.single.swap(Iteratee.flatten(next))
  115. current.pureFlatFold(
  116. (a, e) => {
  117. a.foreach(aa => result.redeem(Done(aa, e)))
  118. next.redeem(Done(a, e))
  119. Done(a, e)
  120. },
  121. k => {
  122. next.redeem(current)
  123. Cont(step(ref))
  124. },
  125. (msg, e) => {
  126. result.redeem(Error(msg, e))
  127. next.redeem(Error(msg, e))
  128. Error(msg, e)
  129. })
  130. }
  131. def step(ref: Ref[Iteratee[E, Option[A]]])(in: Input[E]): Iteratee[E, Option[A]] = {
  132. val next = Promise[Iteratee[E, Option[A]]]()
  133. val current = ref.single.swap(Iteratee.flatten(next))
  134. current.pureFlatFold(
  135. (a, e) => {
  136. next.redeem(Done(a, e))
  137. Done(a, e)
  138. },
  139. k => {
  140. val n = k(in)
  141. next.redeem(n)
  142. n.pureFlatFold(
  143. (a, e) => {
  144. a.foreach(aa => result.redeem(Done(aa, e)))
  145. Done(a, e)
  146. },
  147. k => Cont(step(ref)),
  148. (msg, e) => {
  149. result.redeem(Error(msg, e))
  150. Error(msg, e)
  151. })
  152. },
  153. (msg, e) => {
  154. next.redeem(Error(msg, e))
  155. Error(msg, e)
  156. })
  157. }
  158. patcher(new PatchPanel[E] {
  159. val ref: Ref[Ref[Iteratee[E, Option[A]]]] = Ref(Ref(it.map(Some(_))))
  160. def closed() = isClosed
  161. def patchIn(e: Enumerator[E]): Boolean = {
  162. !(closed() || {
  163. val newRef = atomic { implicit txn =>
  164. val enRef = ref()
  165. val it = enRef.swap(Done(None, Input.Empty))
  166. val newRef = Ref(it)
  167. ref() = newRef
  168. newRef
  169. }
  170. e |>> refIteratee(newRef) //TODO maybe do something if the enumerator is done, maybe not
  171. false
  172. })
  173. }
  174. })
  175. result
  176. }
  177. }
  178. }