Tommi Virtanen | 1 Jun 2005 22:44

Re: ReverseProxy subpath

Siegmund Fuehringer wrote:
> i would like to setup a reverse proxy, which serves the root of an 
> internal server as '/subpath' of the external server:
> http://external.org/subpath -> http://internal.org/
> but i can't get it to work.
> 
> my current setup requires that the internal server also serves the 
> content as '/subpath':
> 
> root.putChild( 'subpath', ReverseProxyResource( '127.0.0.1', 6080, 
> '/vhost/http/external.org:80/subpath' ) )
> 
> is there a way to achieve, what i would like to have?

The full URL needs to be passed to the internal server in order
for it to form correct URLs for redirects and such.

The /vhost/ trick passes scheme ("http"), host ("external.org") and
port (":80"), but not the path. So you need the /subpath there.

There has been talk about alternate ways of doing the same, but
that code does not exist yet.

Just use the /subpath.
Alexey Shamrin | 2 Jun 2005 01:46
Picon

Re: Livepage, ClientHandle and context

On 5/31/05, Donovan Preston <dp <at> ulaluma.com> wrote:

> In this branch, input handlers can also return javascript which will
> be executed as the response to the input event.

What do you mean? I don't understand...
Are you talking about javascript that will be executed without
round-trip to server?

> 
> I encourage anyone who is interested in livepage to take a look at
> this branch to see where it is going. Take a look at the examples to
> see what has changed, read the code, and experiment with it. Ask
> questions if you have any. I'll be trying to merge this branch into
> the mainline (after adding some backwards compatibility) in the next
> week.
> 
> I'll also be adding some LivePage docs. I think the API will settle
> down after this last round of changes.

1. nevow_insertNode from liveglue.js (and livepage.insert) is broken.
And (as far as I can see) it is not used anywhere in Nevow (including
examples). Remove?

2. I think you should have "nevow_" prefix for all things in liveglue.js.

3. What is the purpose of ClientHandle.transient?

4. Are these two equivalent?
onsubmit=livepage.server.handle(livepage.js.onSubmit, getValue('inputline'))
(Continue reading)

Donovan Preston | 2 Jun 2005 04:25

Re: Livepage, ClientHandle and context


Thank you very much for your feedback. Please, anyone else on this list who is using or attempting to use LivePage, let me know what you are doing with it or plan on doing with it. I want to take it from long-running experiment to solid, deployable code before the next release, and need to know how much API stability/backwards compatibility I should provide. I also need to know how people want to use LivePage, and if it has any usability shortcomings with this new design which I describe below. If there are any, I'd like to fix them before the next release.

On Jun 1, 2005, at 4:46 PM, Alexey Shamrin wrote:

On 5/31/05, Donovan Preston <dp <at> ulaluma.com> wrote:

In this branch, input handlers can also return javascript which will
be executed as the response to the input event.

What do you mean? I don't understand...
Are you talking about javascript that will be executed without
round-trip to server?

When a client-side event generates a trip to the server over the input conduit, the server-side handler method which is invoked can now return javascript stan. This return result is written as the response to the HTTP request which dispatched the event to the server, and the browser evals it. Previously, the server would arrange for the handler method to be called in the next reactor iteration and close the input HTTP request, writing nothing to it. The handler method would then call methods on the client handle which would generate javascript and buffer it or write it directly to the output conduit.

So yes, one (output conduit) round trip is eliminated, and it becomes easier to support normal AJaX style events (where the browser is the only thing initiating requests, and the server does no pushing), which I call input only mode.

I encourage anyone who is interested in livepage to take a look at
this branch to see where it is going. Take a look at the examples to
see what has changed, read the code, and experiment with it. Ask
questions if you have any. I'll be trying to merge this branch into
the mainline (after adding some backwards compatibility) in the next
week.

I'll also be adding some LivePage docs. I think the API will settle
down after this last round of changes.


1. nevow_insertNode from liveglue.js (and livepage.insert) is broken.
And (as far as I can see) it is not used anywhere in Nevow (including
examples). Remove?

I think I might fix it rather than removing it. I'll also write a test for it, since livetest can now reliably test livepage apps.

2. I think you should have "nevow_" prefix for all things in liveglue.js.

I agree, except I think I want the new "server" object to keep that name. It will be much easier for people to understand and use livepage if they know that calling server.handle('foo') in javascript invokes the handle_foo method on the server. Are there other things in there that aren't prefixed with nevow_?

3. What is the purpose of ClientHandle.transient?

ClientHandle.transient and LivePage.locateHandler (whose default implementation looks for handle_* methods) are the new, easier to understand and use replacements for the handler decorator. Previously, there was a problem with handler because it registered the callable you gave it in a dictionary which lived for as long as the LivePage instance it was associated with. This means if you had a really, really long lived LivePage (which LivePage is designed to allow) you would leak more and more closures that the client can't ever call again (because you replaced the client-side dom that referenced those server-side closures with something else)

Now, if you provide a handle_foo method, the client can always call server.handle('foo') as many times as it wants. However, it is still useful to register closures on the server and give the client the capability to call it. To avoid the aforementioned garbage problem, transient allows you to do this, but only allows the client to call it once, then pops the registration.

This avoids the garbage problem well; if the client closes the browser, LivePage guarantees that the ClientHandle will die no more than 90 seconds later, taking the transient closure registration dictionary with it. If you are, for example, putting an "ok/cancel" dialog on the user's screen, you can register a single transient which gets called by either the ok or cancel button, ensuring that the transient will be popped when the client no longer has the capability to call it (because the UI has gone away, by the user clicking either ok or cancel)

4. Are these two equivalent?
onsubmit=livepage.server.handle(livepage.js.onSubmit, getValue('inputline'))
onsubmit=livepage.server.handle('onSubmit', getValue('inputline'))

No, because the client-side javascript "handle" function takes a string. The first would render down to:

server.handle(onSubmit, getValue('inputline'))

The second would render down to:

server.handle('onSubmit', getValue('inputLine'))

The first would barf because the global name onSubmit doesn't exist.

The livepage.js object is like a stan.Tag for javascript; it creates literal javascript. For example:

livepage.js.foo -> foo
livepage.js.foo('1') -> foo('1')
livepage.js('any string') -> any string
livepage.js['1'] -> ['1']
livepage.js.foo['1'] -> foo['1']

There are a bunch of other js objects in the module now, such as window, document, this, server, set, append, alert, etc. They are really convenient for making your python code much shorter.

I have an incredible LivePage app I wrote recently I am calling "Pavel". I will be cleaning it up soon and I will create a new open source project for it (rather than including it as a nevow example). I think it really showcases the power of LivePage and I'm excited to show it to people, but for now it is somewhat of a secret :-)

P.S. At this time I have only read the code and checked new
examples... I will try to experiment with it soon. But I must say your
javascript "constructor" looks interesting (livepage.assign,
livepage.var etc.)

assign and var are two experiments to get around the fact that python has no assignment overloading. Here are examples of usage:

var(js.x, 5) -> var x = 5
assign(js.x, 10) -> x = 10

One other thing while I am discussing stan for javascript. This is a pain once you start using it, but I don't think there is any way around it other than education. You need to terminate your statements, since the javascript flatteners have no idea where it is appropriate to put newlines in javascript. So if you were sending the following:

client.send([
    livepage.alert('hello'),
    livepage.set('name', 'Donovan Preston')])

You would need to terminate each statement, otherwise the javascript won't be correct. The above example would render as:

alert('hello')set('name', 'Donovan Preston')

Right now, you need to do:

client.send([
    livepage.alert('hello'), livepage.eol,
    livepage.set('name', 'Donovan Preston')])

Which will render down to:

alert('hello')
set('name', 'Donovan Preston')

It occurs to me that it may be possible for Nevow to just infer that a newline is required between each element of a list or a tuple while in JavascriptContext. I will have to experiment and see whether this causes any inadvertent problems. If not, the requirement to manually insert newline characters will go away (horray!)

Donovan

_______________________________________________
Twisted-web mailing list
Twisted-web <at> twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
Christopher Zorn | 2 Jun 2005 15:07
Picon

Re: Livepage, ClientHandle and context

On 6/1/05, Donovan Preston <dp <at> ulaluma.com> wrote:
> 
> Thank you very much for your feedback. Please, anyone else on this list who
> is using or attempting to use LivePage, let me know what you are doing with
> it or plan on doing with it.

I use it for http://punjab.thetofu.com 

It is not stable yet. You can get the code at http://punjab.sf.net

<snip>
Garth T Kidd | 3 Jun 2005 14:06
Picon

Re: Livepage, ClientHandle and context

> Thank you very much for your feedback. Please, anyone else on this list who
> is using or attempting to use LivePage, let me know what you are doing with
> it or plan on doing with it. 

I'm planning to re-implement parts or all of the iPodder GUI in
LivePage to overcome difficulties we're experiencing with the wxPython
framework. I'll probably also roll it into PyDS.

Regards,
Garth.
Alexey Shamrin | 6 Jun 2005 18:24
Picon

Re: Livepage, ClientHandle and context

Hello!

Thank you for good explanations! As far as I can see you have already
commited good docstrings and backward-compatibility code into your
branch (r1545). It looks good!

On 6/2/05, Donovan Preston <dp <at> ulaluma.com> wrote:
> I also need to know how people want to use LivePage, 
> and if it has any usability shortcomings with this new 
> design which I describe below.

As you ask to describe how people use LivePage, here is my small example.

In a smaill project I am doing I use LivePage as follows (simplified
extract from the working code -- I haven't tested it...):

# example.py
from nevow import loaders, livepage, rend, tags as T

def get_teachers_list():
     # some code that returns the list of teachers goes here
     pass

class Editor(rend.Page):
    """Base class providing template for all pages"""
    addSlash=True

    docFactory = loaders.stan(T.html[T.body[T.directive('main_area')]])

class TeachersEditor(Editor,livepage.LivePage):
    """This page is exposed to the web"""

    def render_main_area(self, ctx, data):
        return livepage.glue, TeachersList(get_teachers_list())

class TeachersList(rend.Fragment):
    docFactory = loaders.stan([
        T.ul(render=rend.sequence, id='teachers_list')[
                T.li(pattern='item', render=T.directive('teacher_item'))[
                    T.a(render=T.directive('teacher_link'), href='#')[
                        T.slot(name='teacher_name')]]],
        T.div(id='teacher_details')])

    def render_teacher_item(self, ctx, teacher):
        return ctx.tag(id='teacher_%d' % teacher.id)

    def render_teacher_link(self, ctx, teacher):
         <at> livepage.handler
        def show_teacher(client):
            client.set('teacher_details',TeacherDetails(teacher))

        ctx.fillSlots('teacher_name', teacher.name)
        return ctx.tag(onclick=show_teacher, id='teacher_link_%d' % teacher.id)

class TeacherDetails(rend.Fragment):
      # this rend.Fragment also has  <at> livepage.handler-ed closures
      pass

# end of example.py

As you can see, I use LivePage from inside rend.Fragment's subclasses
(TeacherDetails and TeachersList). But only the main rend.Page
subclass (TeacherEditor) is a subclass of livepage.LivePage. I also
use livepage.handler's as closures (TeachersList.render_teacher_link).

There were two problems with your branch and my code:

1. Backward compatible code didn't work for me (I don't remember what
was the reason. If you need details, I can make a better, working,
example.).

2. I tried to use new LivePage api, but I couldn't figure out how to
translate my code using it. For example, your ClientHandler.transient
seems to provide the ability to make browser-callable functions as
closures, but I am confused about the limitation of one-time calling.
Is it really necessary for a solution of garbage problem you mention?

I also can't see a way to use handler_* methods, because this methods
must be inside a rend.Fragment subclass in my case.

How can use the new api in my application?

> 2. I think you should have "nevow_" prefix for all things in liveglue.js.
> I agree, except I think I want the new "server" object to keep that name. It
> will be much easier for people to understand and use livepage if they know
> that calling server.handle('foo') in javascript invokes the handle_foo
> method on the server. Are there other things in there that aren't prefixed
> with nevow_?

Lot's of them. Just look inside liveglue.js... createRequest, connect,
auto_load, listener etc.

Or you can you preuso object-oriented approach like in Prototype
(http://prototype.conio.net/) or dojo.

> I have an incredible LivePage app I wrote recently I am calling "Pavel". I
> will be cleaning it up soon and I will create a new open source project for
> it (rather than including it as a nevow example). I think it really
> showcases the power of LivePage and I'm excited to show it to people, but
> for now it is somewhat of a secret :-)

I am looking forward for that!

> So if you were sending the following:
> 
> client.send([
> ��� livepage.alert('hello'),
> ��� livepage.set('name', 'Donovan Preston')])
> 
> You would need to terminate each statement, otherwise the javascript won't
> be correct. The above example would render as:
> 
> alert('hello')set('name', 'Donovan Preston')
> 
> Right now, you need to do:
> 
> client.send([
> ��� livepage.alert('hello'), livepage.eol,
> ��� livepage.set('name', 'Donovan Preston')])
> 
> Which will render down to:
> 
> alert('hello')
> set('name', 'Donovan Preston')
> 
> It occurs to me that it may be possible for Nevow to just infer that a
> newline is required between each element of a list or a tuple while in
> JavascriptContext. I will have to experiment and see whether this causes
> any�inadvertent problems. If not, the requirement to manually insert newline
> characters will go away (horray!)

I am not sure, but may be something like livepage.do would do the job
a little better?

client.send(livepage.do[
    livepage.alert('hello'),
    livepage.set('name', 'Donovan Preston')])

(or even livepage.progn...)

--

-- 
Alexey
_______________________________________________
Twisted-web mailing list
Twisted-web <at> twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
Siegmund Fuehringer | 7 Jun 2005 04:52

problem with livepage-completion-notification-3 branche

hi!

livepage doesn't work, when i return a LivePage instance from 
a childFactory.

eg:
class Test( livepage.LivePage ):
...
class Root( rend.Page ):
    def childFactory( self, ctx, name ):
	return Test( )   <---- doesn't work

    child_muh = Test( )  <---- works

it works in nevow trunk though.

bye - sifu
Donovan Preston | 7 Jun 2005 19:22

Re: problem with livepage-completion-notification-3 branche


On Jun 6, 2005, at 7:52 PM, Siegmund Fuehringer wrote:

> hi!
>
> livepage doesn't work, when i return a LivePage instance from
> a childFactory.
>
> eg:
> class Test( livepage.LivePage ):
> ...
> class Root( rend.Page ):
>     def childFactory( self, ctx, name ):
>     return Test( )   <---- doesn't work
>
>     child_muh = Test( )  <---- works
>
>
> it works in nevow trunk though.

Yes. This is correct. This gives the developer the correct amount of  
control over the lifetime of all ClientHandle instances associated  
with a LivePage.

If you want to build your LivePage in a childFactory method, just  
build it and cache it somewhere (self, for example) that will live  
for the appropriate lifetime for your application (which may be the  
entire lifetime of the application). Then, return the same instance  
out of this cache the next time it is requested. In this way, all  
LivePage requests go through the same LivePage instance, and thus  
through the same clientHandleFactory, and thus the correct  
ClientHandle instances can be located.

This allows you to do things like have one LivePage per person, using  
guard, or share the same LivePage between everybody, by always  
returning the same instance for the same URL.

Donovan
Andrea Soong | 8 Jun 2005 09:33
Picon
Favicon

Need help getting started...

Hello, 
 
I'm taking a class in which we're supposed to be implementing a pseudo-proxy server that does some text parsing on web pages before passing them back to the client.  The proxy is supposed to be accessed via the URL and port that the server is running on, using an .rpy file.
 
I've looked through all of the available Twisted documentation, but just can't seem to get a handle on how to get started.  It's mostly setup questions - what code should go in which files?  How do I run it?  How do I test it?  There are a lot of code examples available, but very little information on how they interact and call each other.  It doesn't help that I am not too familiar with the OO-style API documentation.
 
I know that I need to be creating a subclass of HTTPClient, and creating a resource in the .rpy file.  I'm guessing that the .rpy file should create an instance of the HTTPClient subclass and use it to retrieve the requested URL (we have to get it line by line), but I don't understand how to create the instance.
 
A single good example that creates a web proxy server which simply retrieves the data line by line and displays it to the screen, plus the shell commands needed to run/test would be extremely helpful.  I am completely confused as to how the web server and .rpy file would interact.
 
I hope someone has the time and know-how to help me out.
THANKS

Discover Yahoo!
Stay in touch with email, IM, photo sharing & more. Check it out!
_______________________________________________
Twisted-web mailing list
Twisted-web <at> twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
Matt Goodall | 8 Jun 2005 17:56

Re: Need help getting started...

Andrea Soong wrote:
> Hello, 
>  
> I'm taking a class in which we're supposed to be implementing a
> pseudo-proxy server that does some text parsing on web pages before
> passing them back to the client.  The proxy is supposed to be accessed
> via the URL and port that the server is running on, using an .rpy file.
>  
> I've looked through all of the available Twisted documentation, but just
> can't seem to get a handle on how to get started.  It's mostly setup
> questions - what code should go in which files?

I understand you are restricted to deploying a single .rpy script, so
all your code will have to be contained in that file. That's not a good
way to deploy a Twisted web app but you have no choice here.

>  How do I run it?  

Create and run a web.tap that serves files from the directory containing
your .rpy script.

> How do I test it?

Request the .rpy using your browser.

> There are a lot of code examples available, but very
> little information on how they interact and call each other.  It doesn't
> help that I am not too familiar with the OO-style API documentation.
>  
> I know that I need to be creating a subclass of HTTPClient, and creating
> a resource in the .rpy file.  I'm guessing that the .rpy file should
> create an instance of the HTTPClient subclass and use it to retrieve the
> requested URL (we have to get it line by line), but I don't understand
> how to create the instance.

Typically, you add a client protocol factory to the reactor, giving it a
host and port. However, the twisted.web.client module has some
convenient functions that will make things easier for you. See getPage
in that module for more detail.

> A single good example that creates a web proxy server which simply
> retrieves the data line by line and displays it to the screen, plus the
> shell commands needed to run/test would be extremely helpful.  I am
> completely confused as to how the web server and .rpy file would interact.

Everything you need is in the "Using twisted.web" HOWTO which can be
found at http://twistedmatrix.com/projects/web/documentation/howto/.
Points of interest are:

  * .rpy (resource) scripts
  * creating and running a web.tap server
  * the twisted.web.client module
  * deferred resource rendering

>  
> I hope someone has the time and know-how to help me out.
> THANKS

I realise that this reply is a little terse but I suspect part of the
class is working out how to put all this together ;-).

Good luck!

Cheers, Matt

--

-- 
     __
    /  \__     Matt Goodall, Pollenation Internet Ltd
    \__/  \    w: http://www.pollenation.net
  __/  \__/    e: matt <at> pollenation.net
 /  \__/  \    t: +44 (0)113 2252500
 \__/  \__/
 /  \	       Any views expressed are my own and do not necessarily
 \__/          reflect the views of my employer.

Gmane