Gary Godfrey wrote:
>      == SERVER ==
>  =  Virtual Host Splitter =
>
>  =  ldap ID     =    mysql ID  =
> =   TG Blog   =    TG  Blog  =
>
> OK, so we have two different web sites hosted virtually on a single
> WSGI Server.  The TG blog code needs to call either the LDAP ID
> mechanism or the mysql ID mechinism depending on which path was taken.
>  So, the "import Identity" used inside TG Blog needs to mean different
> things depending which one is called.  How would that work?

Pretty easy really. When the ID is called, it initializes the
thread-local. That way when you do import Identity from TG Blog, it
looks at the thread-local, which was setup by ID. When you setup each
ID, you of course tell it how its going to do the lookup, which it
saves. Then when its called, it looks at how it was initialized, loads
it up, sets the thread-local, and proceeds.

class ID(object):
    def __init__(self, app, auth_lookup='file'):
        self.app = app
        self.auth_scheme = auth_lookup

    def __call__(self, environ, start_response):
        # pull our self.auth_scheme, setup the thread-local, etc.
        return self.app(environ, start_response)

Then you wrap it...

    myapp = ID(myapp, auth_lookup='ldap')
etc.

So when you wrap the app, you configure its lookup. That way before it
calls your TG Blog, it sets up the same lookup scheme you initialized
it with. This is how most current middleware functions and remembers
its configuration during call.

> See, "thread-safe module globals" always scare me.  Every time you have
> to look up the current thread and map that to the right thread-safe
> value is a potential for screwing things up.  That should only be done
> rarely, ideally not by everyone who implements a feature.

Oh, its not just a thread-safe module global.... :)   Keep in mind that
your app might call a differently configured version of the same app
farther down the chain. That app would then blast away your thread-safe
module global, and when its done, the app farther in the chain would be
left using data that wasn't its own.

So not only does it need to be thread-safe, it needs to implement a
stack as well, so that you push your object on, and pop it off when
you're done. RhubarbTart got such a stacked thread-safe during the
PyCon sprint. I've talked with Ian about putting an object like this in
Paste, so that when you need it, you can use that one instead of making
your own version (which may or may not work). Also, a small bit of
middleware that ensures the object is pushed and popped off helps out.

The complex issues are taken care of, and using it becomes fairly easy.
Again, Paste already has something like this, so given the code in
RhubarbTart, and already in Paste, it should be fairly trivial to make
a GlobalRegistry style middleware you could use like so:

   app = GlobalRegistry(app)
   app = ID(app, lookup_auth='ldap')

Then in our ID, which we require the user to run underneath a
GlobalRegistry middleware:
#identity.py
from paste.globalregistry import StackedObject
myid = StackedObject()

class ID(object):
    def __init__(self, app, auth_lookup='file'):
        self.app = app
        self.auth_scheme = auth_lookup

    def __call__(self, environ, start_response):
        # pull our self.auth_scheme, setup the thread-local, etc.
        id = ConfigureAndSetupForIdentity()
        environ['paste.globalregistry'].register(myid, id)
        return self.app(environ, start_response)

So the GlobalRegistry takes care of pushing and popping your
thread-locals, and now you can 'from identity import myid' anywhere in
your webapp, and it has the current id object. You don't have to worry
about the WSGI and thread/request local nuances, and middleware takes
care of ensuring its all working right in a totally portable fashion.

I should also mention that putting things in environ doesn't solve this
problem. Just imagine the same scenario, only you're storing your ID
object in environ. If one of your apps down the chain uses ID as well,
it will blow the prior ID object in environ away.... so regardless of
if its a thread-local or in environ, it needs to be a stacked style
object.

Hopefully that helps clear this all up some. I'm looking over Paste
code now and hopefully will have some middleware along these lines
working tomorrow so we can play with it. :)

Cheers,
Ben


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"TurboGears" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/turbogears
-~----------~----~----~----~------~----~------~--~---

Reply via email to