[Twisted-Python] timeout using LivePage
![](https://secure.gravatar.com/avatar/6b33f40119f47dfe3fe5b4f445ae0129.jpg?s=120&d=mm&r=g)
Hi, Am very new to Twisted but am quickly finding that I like it. All my questions and comments involve Twisted 1.0.6 in combo with Python 2.3 on OS X. I've run into a problem while making a rough .rpy prototype of a mapping application (ala MapQuest) using the U of Minnesota MapServer's Python interface. I will need to have server-side handlers for javascript events to allow map zooming, panning, &c and so have been experimenting with LivePage. I intend that the code should render a map image, and upon clicking the image, we zoom into the map (changing model data), and redraw the map image. Unfortunately, browsers are unable to load the mapserv.rpy/?woven_hookupOutputConduitToThisFrame=1 URL that is generated by my instance of LivePage, and so the map is never redrawn as it should. The model data does get changed successfully, and when I manually reload the page, I do see the zoomed map image as I expect. What is this 'woven_hookupOutputConduitToThisFrame' all about? Do I need to set up another method to handle this URL? I know that it's not recommended to put so much logic in the .rpy file, but as I said, a quick and dirty prototype is what I'm after. Am attaching the source of mapserv.rpy here: -------------------------------------------------------------------- import os import time from twisted.web.woven import page, widgets, controller, model from mapscript import * base_mapfile = 'navtech_std.map' # Get map object from the session data if we can class MapModel(model.MethodModel): def wmfactory_mapobj(self, request): session_obj = request.getSession() try: session_mapobj = session_obj.mapobj except AttributeError: session_mapobj = mapObj(base_mapfile) session_obj.mapobj = session_mapobj return session_mapobj # Widget for creating a temp map image and a tag linking to it class MapImage(widgets.Widget): def setUp(self, request, node, data): mapobj = data node.tagName = "img" imgobj = mapobj.draw() tmp_file = '%s_%d_%d.%s' \ % (mapobj.name, time.time(), os.getpid(), imgobj.format.extension ) imgobj.save(os.path.join('/tmp', tmp_file)) map_url = os.path.join('/tmp', tmp_file) node.setAttribute('src', map_url) node.setAttribute('height', str(mapobj.height)) node.setAttribute('width', str(mapobj.width)) node.setAttribute('border', '1') # Widget for displaying the current scale of the map class MapScale(widgets.Widget): def setUp(self, request, node, data): text = 'Scale: 1:%d' % (data.scale) newNode = request.d.createTextNode(text) node.appendChild(newNode) # Template, using the web conduit glue template = """<html> <body> <img model="mapobj" view="map_image" controller="map_ctrl"/> <p model="mapobj" view="map_scale" /> <div view="webConduitGlue" /> </body> </html> """ # Zoom into the map in the event of a javascript onclick class MyEventHandler(controller.Controller): def handle(self, request): self.view.addEventHandler("onclick", self.onClick) def onClick(self, request, widget): # Get session map object (layers and spatial extents) session_obj = request.getSession() try: session_mapobj = session_obj.mapobj except AttributeError: session_mapobj = mapObj(base_mapfile) session_obj.mapobj = session_mapob # zoom in on the map w = session_mapobj.width h = session_mapobj.height pt = pointObj() pt.x, pt.y = w/2, h/2 session_mapobj.zoomPoint(2, pt, w, h, session_mapobj.extent, None) print session_mapobj.extent.minx, session_mapobj.extent.maxx print self, "Zoomed!!!" # There is a better way to redraw the map, certainly request.redirect('http://localhost:8084/mapserv.rpy/') request.finish() # Page class class MyPage(page.LivePage): def wcfactory_map_ctrl(self, request, node, model): return MyEventHandler(model) # Resource resource = MyPage(MapModel(), template=template) resource.setSubviewFactory("map_image", MapImage) resource.setSubviewFactory("map_scale", MapScale) ----------------------------------------------------------------------- looking forward to any insights into LivePage and also looking forward to getting enough experience with Twisted that I can begin to contribute to the list discussions. cheers, Sean -- Sean Gillies sgillies at frii dot com http://www.frii.com/~sgillies
![](https://secure.gravatar.com/avatar/74bde9dd414c74dc244c6a448e5decc6.jpg?s=120&d=mm&r=g)
On Monday, August 25, 2003, at 1:30 PM, Sean Gillies wrote:
Great! Always glad to have more users giving me feedback. If you are going to be using LivePage, you should probably track CVS instead of using a release, since LivePage is the one major area of woven I am still doing major work on. First, I want to clarify some terminology. LivePage is designed to allow two things: Client-To-Server Events: A JavaScript event handler in the browser is routed to the Twisted server and causes some code to run. This uses a channel I am calling the "InputConduit" Server-To-Client Events: Some event happened on the server (For example, new mail arrived, another player entered the room) and the server wants to "Push" some new HTML to the client. This uses a channel I am calling the "OutputConduit"
There are actually two unrelated issues here. The first is that the current implementation of LivePage in the Twisted CVS is geared towards the NewReality web client (NewReality is a multiuser text environment (game) written in Twisted) and thus the ability for the server to send events to the client is pretty important. You are connected and logged in using the web client, and someone else enters the room -- you want the web browser to display a notice about someone entering the room without having to refresh the browser manually or set up continual reloading. The output conduit is implemented in certain browsers (those lacking Flash and LiveConnect) by embedding an <iframe> tag whose src="?woven_hookupOutputConduitToThisFrame=1" in the page. When the browser attempts to load this iframe, it makes a request to the server, and twisted notices that the browser "wants to hook up the output conduit to this frame", and *never finishes sending this page to the client*. The Twisted server just holds this connection open forever, so that it can write data to the client on demand in response to events on the server, and this is why it appears your browser is unable to load this URL. Since with your application it sounds like you only want client-to-server events, you need to do a little bit of hacking to prevent Woven from including the output conduit HTML in your pages. This will get easier in future releases of Twisted; I just haven't had time to enumerate the possible ways people will want to use LivePage and come up with an easy way for the programmer to specify the features they want. If you look at the HTML fragment woven includes in your page when you specify the view directive "webConduitGlue" you will see it includes the following parts: <div> <script src="WebConduit2_js" language="javascript"></script> <iframe src="input_html" style="width: 0; height: 0" id="woven_inputConduit"></iframe> <iframe src="?woven_hookupOutputConduitToThisFrame=1" style="width: 100%" id="woven_outputConduit"></iframe> </div> Simply replace the view="webConduitGlue" node with the above fragment, sans the output conduit frame: <div> <script src="WebConduit2_js" language="javascript"></script> <iframe src="input_html" style="width: 0; height: 0" id="woven_inputConduit"></iframe> </div> After you have done this, your pages will actually appear to fully load and you should feel happier.
The second issue is that you are not notifying your models properly to tell them that they have changed. When a client-to-server event is sent from the browser to the server, the current version of Woven only sends the portions of the page which have actually changed, not the entire page, back to the browser. Again, this is something I would like the programmer to be able to control, because sometimes the changes are extensive enough that it makes more sense to send the entire page back. Your redirect hack is not a terrible solution, actually. I have used it before. See below for an example of how you can make your current controller code notify the model properly.
# Tell the browser that the model has changed, and # any widgets which rely on this model will have to be # rerendered, and the HTML sent to the browser widget.model.notify({'request': request}) # Delete the next three lines
By the way, addEventHandler takes additional arguments which are javascript strings which will be evaluated within the context of the browser, and the results will be sent as additional arguments to the server-side event handler. To take advantage of this, you have to know a bit about JavaScript, but for example, if you know about the IE global "event" object, you could use it to pass the current x, y position of the mouse to the server with something like this: self.view.addEventHandler("onclick", self.onClick, 'event.x', 'event.y') Then defining the event handler like this: def addEventHandler(self, request, widget, x, y): print "x, y", x, y Of course, doing this means knowing enough about javascript to do this properly, but those are problems with JavaScript and not Woven. I think Mozilla has different semantics for getting at the event object which may require changes in WebConduit2_js. I would consider it a bug if changes are required. I hope this helps! Donovan
![](https://secure.gravatar.com/avatar/6b33f40119f47dfe3fe5b4f445ae0129.jpg?s=120&d=mm&r=g)
On Monday, August 25, 2003, at 05:45 PM, Donovan Preston wrote:
Hi Donovan, Thanks for the reply. I can't wait to try out your recommendations. I had read in the docs about the extra args to addEventHandler, but appreciate seeing an example that's so close to my particular need. cheers, Sean -- Sean Gillies sgillies at frii dot com http://www.frii.com/~sgillies
![](https://secure.gravatar.com/avatar/6b33f40119f47dfe3fe5b4f445ae0129.jpg?s=120&d=mm&r=g)
On Monday, August 25, 2003, at 05:45 PM, Donovan Preston wrote:
Donovan, I am now using Twisted from CVS and have made the change to my template so that the webConduitGlue is not used. Have also made the change to my onclick event handler so that widget.model.notify is called. So far so good ... the model is being notified and the code in my custom MapImage widget's setUp medthod is being executed. I can tell because it is creating new map images in the app's temporary location and these new images are exactly as I expect. However, the document is not being rerendered properly: the HTML returned to my browser is unchanged, the <img /> tag still points to the old map image location. FWIW, I'm using Mozilla, Safari, and IE 5 on OS X and see the same issue with each of these. Will I need to edit WebConduit2_js? If so, can you suggest where I would start? cheers, Sean -- Sean Gillies sgillies at frii dot com http://www.frii.com/~sgillies
![](https://secure.gravatar.com/avatar/6b33f40119f47dfe3fe5b4f445ae0129.jpg?s=120&d=mm&r=g)
On Tuesday, August 26, 2003, at 11:11 AM, Sean Gillies wrote:
No problem with LivePage or the javascript in WebConduit2_js after all. After I changed my MapImage widget class to extend widget.Image, and wrote a proper setUp method, I get map zooming just as I need. Slick stuff, Donovan! cheers, Sean -- Sean Gillies sgillies at frii dot com http://www.frii.com/~sgillies
![](https://secure.gravatar.com/avatar/74bde9dd414c74dc244c6a448e5decc6.jpg?s=120&d=mm&r=g)
On Monday, August 25, 2003, at 1:30 PM, Sean Gillies wrote:
Great! Always glad to have more users giving me feedback. If you are going to be using LivePage, you should probably track CVS instead of using a release, since LivePage is the one major area of woven I am still doing major work on. First, I want to clarify some terminology. LivePage is designed to allow two things: Client-To-Server Events: A JavaScript event handler in the browser is routed to the Twisted server and causes some code to run. This uses a channel I am calling the "InputConduit" Server-To-Client Events: Some event happened on the server (For example, new mail arrived, another player entered the room) and the server wants to "Push" some new HTML to the client. This uses a channel I am calling the "OutputConduit"
There are actually two unrelated issues here. The first is that the current implementation of LivePage in the Twisted CVS is geared towards the NewReality web client (NewReality is a multiuser text environment (game) written in Twisted) and thus the ability for the server to send events to the client is pretty important. You are connected and logged in using the web client, and someone else enters the room -- you want the web browser to display a notice about someone entering the room without having to refresh the browser manually or set up continual reloading. The output conduit is implemented in certain browsers (those lacking Flash and LiveConnect) by embedding an <iframe> tag whose src="?woven_hookupOutputConduitToThisFrame=1" in the page. When the browser attempts to load this iframe, it makes a request to the server, and twisted notices that the browser "wants to hook up the output conduit to this frame", and *never finishes sending this page to the client*. The Twisted server just holds this connection open forever, so that it can write data to the client on demand in response to events on the server, and this is why it appears your browser is unable to load this URL. Since with your application it sounds like you only want client-to-server events, you need to do a little bit of hacking to prevent Woven from including the output conduit HTML in your pages. This will get easier in future releases of Twisted; I just haven't had time to enumerate the possible ways people will want to use LivePage and come up with an easy way for the programmer to specify the features they want. If you look at the HTML fragment woven includes in your page when you specify the view directive "webConduitGlue" you will see it includes the following parts: <div> <script src="WebConduit2_js" language="javascript"></script> <iframe src="input_html" style="width: 0; height: 0" id="woven_inputConduit"></iframe> <iframe src="?woven_hookupOutputConduitToThisFrame=1" style="width: 100%" id="woven_outputConduit"></iframe> </div> Simply replace the view="webConduitGlue" node with the above fragment, sans the output conduit frame: <div> <script src="WebConduit2_js" language="javascript"></script> <iframe src="input_html" style="width: 0; height: 0" id="woven_inputConduit"></iframe> </div> After you have done this, your pages will actually appear to fully load and you should feel happier.
The second issue is that you are not notifying your models properly to tell them that they have changed. When a client-to-server event is sent from the browser to the server, the current version of Woven only sends the portions of the page which have actually changed, not the entire page, back to the browser. Again, this is something I would like the programmer to be able to control, because sometimes the changes are extensive enough that it makes more sense to send the entire page back. Your redirect hack is not a terrible solution, actually. I have used it before. See below for an example of how you can make your current controller code notify the model properly.
# Tell the browser that the model has changed, and # any widgets which rely on this model will have to be # rerendered, and the HTML sent to the browser widget.model.notify({'request': request}) # Delete the next three lines
By the way, addEventHandler takes additional arguments which are javascript strings which will be evaluated within the context of the browser, and the results will be sent as additional arguments to the server-side event handler. To take advantage of this, you have to know a bit about JavaScript, but for example, if you know about the IE global "event" object, you could use it to pass the current x, y position of the mouse to the server with something like this: self.view.addEventHandler("onclick", self.onClick, 'event.x', 'event.y') Then defining the event handler like this: def addEventHandler(self, request, widget, x, y): print "x, y", x, y Of course, doing this means knowing enough about javascript to do this properly, but those are problems with JavaScript and not Woven. I think Mozilla has different semantics for getting at the event object which may require changes in WebConduit2_js. I would consider it a bug if changes are required. I hope this helps! Donovan
![](https://secure.gravatar.com/avatar/6b33f40119f47dfe3fe5b4f445ae0129.jpg?s=120&d=mm&r=g)
On Monday, August 25, 2003, at 05:45 PM, Donovan Preston wrote:
Hi Donovan, Thanks for the reply. I can't wait to try out your recommendations. I had read in the docs about the extra args to addEventHandler, but appreciate seeing an example that's so close to my particular need. cheers, Sean -- Sean Gillies sgillies at frii dot com http://www.frii.com/~sgillies
![](https://secure.gravatar.com/avatar/6b33f40119f47dfe3fe5b4f445ae0129.jpg?s=120&d=mm&r=g)
On Monday, August 25, 2003, at 05:45 PM, Donovan Preston wrote:
Donovan, I am now using Twisted from CVS and have made the change to my template so that the webConduitGlue is not used. Have also made the change to my onclick event handler so that widget.model.notify is called. So far so good ... the model is being notified and the code in my custom MapImage widget's setUp medthod is being executed. I can tell because it is creating new map images in the app's temporary location and these new images are exactly as I expect. However, the document is not being rerendered properly: the HTML returned to my browser is unchanged, the <img /> tag still points to the old map image location. FWIW, I'm using Mozilla, Safari, and IE 5 on OS X and see the same issue with each of these. Will I need to edit WebConduit2_js? If so, can you suggest where I would start? cheers, Sean -- Sean Gillies sgillies at frii dot com http://www.frii.com/~sgillies
![](https://secure.gravatar.com/avatar/6b33f40119f47dfe3fe5b4f445ae0129.jpg?s=120&d=mm&r=g)
On Tuesday, August 26, 2003, at 11:11 AM, Sean Gillies wrote:
No problem with LivePage or the javascript in WebConduit2_js after all. After I changed my MapImage widget class to extend widget.Image, and wrote a proper setUp method, I get map zooming just as I need. Slick stuff, Donovan! cheers, Sean -- Sean Gillies sgillies at frii dot com http://www.frii.com/~sgillies
participants (2)
-
Donovan Preston
-
Sean Gillies