Notes on using comet with Seaside
Issue #1: Page never appears to finish loading
I was able to get basic comet up and running rather quickly, but I noticed when I loaded the page, the browser would continue to appear as if the page was constantly loading. This was because of the way that the Seaside book instructs you to add the comet script to your page. The book example code looks like:
html script: (html comet pusher: self class pusher; connect)
MyComponent class>>#pusher ^pusher ifNil: [ pusher := CTPusher new ]
html document addLoadScript: (html comet pusher: self class pusher; connect)
This causes the browser to start up the comet streaming connection when the page has finished loading, and in the background. Thus the page will appear to the end user as if it is completely loaded, even though the streaming comet connection is open.
Issue #2: Using comet with a custom session
I still haven’t solved this error yet, but hopefully I will soon, so while I wait to hear back from the Seaside mailing list, I’ll describe the kludge I put in to make it work right.
For my application, I needed a custom subclass of WASession to hold on to information about the logged in user. Unfortunately, when I used this session class with comet, things broke. On the first request of a new session, I would constantly get stacktraces like:
It appears as if the parent of my custom session was never being set to the WAApplication instance that it should have been. It only happened on the first request of the session, and all subsequent comet interactions worked as expected. I thought I could fix this problem by overriding initialize in my custom session, but that did not work:
initialize ^super initialize
So, I posted my question to the Seaside mailing list and am still awaiting a response. In the meantime, I have added a “patch” to CTHandler>>notifySession to change it from:
notifySession self session application cache notifyRetrieved: self session key: self session key
notifySession [self session application cache notifyRetrieved: self session key: self session key] on: MessageNotUnderstood do: [:error | ]
This basically attempts to run the old notifySession code, but when the MessageNotUnderstood error is raised, it simply ignores it and continues on with execution. I know this is not the best practice, but it does make the application work as expected.
But this actually causes the div to be updated twice in rapid succession, both to the same thing. It was completely unnoticeable on the client side, but it was extra overhead being executed on the client browser as well as extra unnecessary data being sent over the wire.
Thanks to the fantastic debugger built into Pharo, I was able to trace down the problem and rewrite the above code as follows:
Issue #4: Conditionally pushing to clients
In my application, I have regular users and administrators. They are defined as such based on what type of object is attached to the custom session I wrote for the project. There are certain elements on my pages that only appear for regular users and certain elements that only appear for administrators, as well as a large number of elements that appear in both. I wanted to use a single comet pusher to be able to push to both regular users as well as administrators, to reduce connection overhead in the final deployed version of the application. Having a separate CTPusher for regular users and a separate one for administrators would have worked, but would have been painful. I wanted something a little cleaner. So I did some hacking on the comet source that comes with seaside and this is what I came up with (added):
push: aString forHandlers: aBlock "Push aString to handlers which when passed as the argument to aBlock causes it to return true." | pushHandlers | pushHandlers := handlers select: aBlock. self mutex critical: [ pushHandlers do: [ :each | each push: aString ] ]
I do realize that this does not do exactly what the plain CTHandler>>#push message does. Namely, it does not prune down the handlers list to ensure that only the connected ones continue to receive updates from the server, but in my application I do mostly regular pushes with only a few requiring the handlers block, so I feel like I am pretty much safe for now. So now, using the code I added, if I want to update the div on the page with id ‘peanut’ to contain the text ‘butter’ for regular users, but to ‘jelly’ for administrators, its quite simple:
So those are my notes on using comet with Seaside thus far. Overall its been a lot of fun watching something really complex come together in such a short period of time. Next, when I get time, I’ll post about how I was able to get custom basic authentication working using LDAP in Seaside.