Permalink
Browse files

Add tracking for AJAX requests in LiftSession.

Request info consists of three things:
 - The request version.
 - A future for the response to the request, satisfied by the first
   request for this version when the response is ready.
 - A lastSeen timestamp, used to expire the entry after the usual
   function lifespan.

LiftSession.withAjaxRequests exposes the request list, which is a Map
mapping a page version to the list of AjaxRequestInfos currently being
tracked for that page. AjaxRequestInfos are cleaned up according to
their lastSeen timestamp, which is updated the same way as those of
functions on the page.
  • Loading branch information...
1 parent d2ec29f commit 26bf7a01267d1621886d049bed112e2d7a29b75a @Shadowfiend Shadowfiend committed Sep 24, 2012
Showing with 47 additions and 0 deletions.
  1. +47 −0 web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala
@@ -499,6 +499,15 @@ private final case class PostPageFunctions(renderVersion: String,
}
+/**
+ * The responseFuture will be satisfied by the original request handling
+ * thread when the response has been calculated. Retries will wait for the
+ * future to be satisfied in order to return the proper response.
+ */
+private[http] final case class AjaxRequestInfo(requestVersion:Int,
+ responseFuture:LAFuture[Box[LiftResponse]],
+ lastSeen: Long)
+
/**
* The LiftSession class containg the session state information
*/
@@ -557,6 +566,20 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
*/
private var postPageFunctions: Map[String, PostPageFunctions] = Map()
+ /**
+ * A list of AJAX requests that may or may not be pending for this
+ * session. There is an entry for every AJAX request we don't *know*
+ * has completed successfully or been discarded by the client.
+ *
+ * See LiftServlet.handleAjax for how we determine we no longer need
+ * to hold a reference to an AJAX request.
+ */
+ private var ajaxRequests = scala.collection.mutable.Map[String,List[AjaxRequestInfo]]()
+
+ private[http] def withAjaxRequests[T](fn: (scala.collection.mutable.Map[String, List[AjaxRequestInfo]]) => T) = {
+ ajaxRequests.synchronized { fn(ajaxRequests) }
+ }
+
/**
* The synchronization lock for the postPageFunctions
*/
@@ -834,6 +857,22 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
}
}
+ withAjaxRequests { currentAjaxRequests =>
+ for {
+ (version, requestInfos) <- currentAjaxRequests
+ } {
+ val remaining =
+ requestInfos.filter { info =>
+ (now - info.lastSeen) <= LiftRules.unusedFunctionsLifeTime
+ }
+
+ if (remaining.length > 0)
+ currentAjaxRequests += (version -> remaining)
+ else
+ currentAjaxRequests -= version
+ }
+ }
+
synchronized {
messageCallback.foreach {
case (k, f) =>
@@ -961,6 +1000,14 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
} postPageFunctions += (ownerName -> funcInfo.updateLastSeen)
}
+ withAjaxRequests { currentAjaxRequests =>
+ currentAjaxRequests.get(ownerName).foreach { requestInfos =>
+ val updated = requestInfos.map(_.copy(lastSeen = time))
+
+ currentAjaxRequests += (ownerName -> updated)
+ }
+ }
+
synchronized {
(0 /: messageCallback)((l, v) => l + (v._2.owner match {
case Full(owner) if (owner == ownerName) =>

0 comments on commit 26bf7a0

Please sign in to comment.