Skip to content

Instantly share code, notes, and snippets.

@Shadowfiend
Created May 10, 2011 19:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Shadowfiend/965176 to your computer and use it in GitHub Desktop.
Save Shadowfiend/965176 to your computer and use it in GitHub Desktop.
ReloadOnSessionLoss.setup can be run in Boot.scala
package bootstrap.liftweb {
import net.liftweb.common._
import net.liftweb.http._
import js._
import LiftRules._
import net.liftweb.util.Helpers._
/**
* Provides automatic reloading of the client on session loss.
*
* Lift keeps tweaking how they do this, but this is our tried-and-true
* approach for now. It's suggested that we keep monitoring Lift changes to
* how they do things so that we can adjust if they come up with a better
* strategy. One key difference is, at last check, Lift redirects the user to
* a set location (e.g., /) configured in LiftRules, whereas we reload the
* current page.
*
* Call ReloadOnSessionLoss.setup to install.
*/
object ReloadOnSessionLoss {
def dispatch : DispatchPF = {
case req if firstSeenCometRequest_?(req) => () => Full(responseForFirstCometRequest(req))
}
// Returns true if we should send an empty response for a comet request,
// false otherwise. This is used to ensure we don't send multiple
// window.location redirects in the event of a server restart in response
// to comet requests. Sending multiple ones can send Firefox into an
// infinite request loop that quickly consumes JVM resources and slows
// down the browser itself.
//
// It should only return true if this is the first time in this session
// that we see a comet request and meet the criteria for Lift sending
// back a window.location redirect to LiftRules.noCometSessionPage. Code
// for determining whether the actor list is empty was borrowed directly
// from LiftServlet.java.
def actorsForCometRequest(req:Req) : Box[List[(LiftCometActor, Long)]] = {
req.path.wholePath match {
case prefix :: tail if prefix == LiftRules.cometPath && (tail.length != 2 || tail(1) != LiftRules.cometScriptName()) =>
Full(
req.params.toList.flatMap {
case (name, when) =>
S.session.open_!.getAsyncComponent(name).toList.map(c => (c, toLong(when)))
}
)
case _ => Empty
}
}
def firstSeenCometRequest_?(req:Req) = {
(for {
actors <- actorsForCometRequest(req)
} yield {
actors.isEmpty
}) openOr (
false
)
}
def responseForFirstCometRequest(req:Req) = {
JsCommands(List(new JE.JsRaw("lift_toWatch = {}; window.location.reload();") with JsCmd)).toResponse
}
def setup {
// It's important to do this in order to control our own session loss
// scenario.
LiftRules.redirectAjaxOnSessionLoss = false
LiftRules.dispatch.append(dispatch)
}
}
}
@serioga
Copy link

serioga commented Jul 24, 2011

Is line 61 redundant?
It looks like val redirectLoc is not used anywhere.

@Shadowfiend
Copy link
Author

In fact you're absolutely right, redirectLoc is a leftover from a slightly different approach to reloading that we had been using. Thanks for pointing that out!

@Shadowfiend
Copy link
Author

I've updated the gist accordingly. Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment