Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
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...
commit 26bf7a01267d1621886d049bed112e2d7a29b75a 1 parent d2ec29f
@Shadowfiend Shadowfiend authored
Showing with 47 additions and 0 deletions.
  1. +47 −0 web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala
View
47 web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala
@@ -500,6 +500,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
*/
class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
@@ -558,6 +567,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
*/
private val postPageLock = new Object
@@ -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) =>
Please sign in to comment.
Something went wrong with that request. Please try again.