[Twisted-Python] Assigning AMP box senders & receivers from the responder

Glyph glyph at twistedmatrix.com
Wed Jul 4 04:50:53 EDT 2012

Le Jul 4, 2012 à 12:39 AM, Laurens Van Houtven <_ at lvh.cc> a écrit :

> On 03 Jul 2012, at 23:53, Glyph wrote:
>> On Jul 3, 2012, at 12:08 AM, Laurens Van Houtven <_ at lvh.cc> wrote:
>>> I'm trying to implement a command called "Become" that allows a staff member to work as if he was the user himself. The most obvious way (to me at least) to do that  to create the customer API (an IBoxReceiver/amp.BoxDispatcher subclass) for that customer (that'd normally be the Realm's job -- but since we're already logged in as an administrator, we don't go through Cred again), and hook up the current connection with that box receiver. Yay, code reuse!
>> Why not just go through cred again?  (If you look for 'Preauthenticated' in the Divmod code base you'll find that this is actually something of a design pattern.)
> I haven't seen that class, I'll take a look.
> I didn't want to go through fred again because I don't see the benefit. I'm not trying to do any authentication (that part's already done), admins don't know the relevant password, so it'd pretty much be IRealm.requestAvatar. I don't understand why portal, credentials checkers... come into play.

Uh, hrm.  Well, hypothetically the checker might have some extra knowledge about how to map a publicly visible user name into an avatar ID; avatar IDs aren't necessarily user names and in fact in the future I hope we can make them a bit more opaque.

In many cases you're right though, it is the same.  Really, this should just be a basic facility of cred so that protocols which need to communicate between authenticated users (SMTP, SIP, IRC, XMPP) can look up the relevant avatars without even having to think about what the right way to do it is :).

>>> I don't see an obvious way to get a reference to the boxReceiver/boxSender from the responder method using documented APIs. Does this just mean I have to leak a reference to them all the way down? Am I doing something stupid?
>> This is why the lowest level of argument parsing is fromString*Proto* rather than just fromString.  You can write an Argument that doesn't actually look at the box and gives you any necessary properties from the protocol (or from the transport).  It was originally written so you can ask for the host and peer addresses for P2P stuff, but this is another possible use.
> So what would this custom Argument be? Right now I take the user id of the user I'm trying to be.

OK, I was definitely missing a couple of steps here.

The custom Argument, in fromBox, can get a value from the CommandLocator, which is the 'protocol' in this case, because it's the CommandLocator which does the (de-)serialization.  So it's not quite enough to just use that API.  The docs here could stand to be improved - they say that this argument is an L{AMP} which is obviously wrong in your case.

Basically you need to give your ComposedLocator knowledge of its BoxSender, which it needs to propagate to its component locators, so that you can ask for it later from the Argument.  Given that I can see you might not want to mess with __init__, you can make this a separate method.  (If you want to really continue in the spirit of AMP's component separation, make ComposedLocator be an IBoxReceiver as well - in fact, BoxDispatcher does what you want, so you can inherit from (or compose!) it; you automatically get a boxSender attribute, which will just so happen to point to the AMP instance whose boxReceiver you want to change.

So, now your ComposedLocator has a boxSender, you can propagate it that value to its components as a public attribute and they can just mess with it on 'self'.  But that's no fun, because now everybody in the whole system can just violate these layers whenever they want (although that is kind of what you want to do).

So, what I was originally suggesting is that you can make everyone who wants to mess with the transport explicitly declare their intentions with a special argument type (as I originally suggested) by propagating it as a private attribute which ComposedLocator's layer of the code knows about.  So, like this:

class ComposedLocator(object):
    def startReceivingBoxes(self, boxSender):
        for locator in self._locators:
            locator._secretlyYouKnowAboutAMP = boxSender
        return super(ComposedLocator, self).startReceivingBoxes(boxSender)
class ShowMeTheProtocol(Argument):
    def fromBox(self, name, strings, objects, componentLocator):
        objects[name] = componentLocator._secretlyYouKnowAboutAMP
class Become(Command):
    arguments = [('boxSender', ShowMeTheProtocol())]

Clear yet? :)

>> Sorry I don't have time to be more expansive at the moment, I hope that's enough to get you un-stuck,
> Afraid not :( That's okay, I have different tests to go fix :)

Don't we all.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://twistedmatrix.com/pipermail/twisted-python/attachments/20120704/a1e2542b/attachment-0001.htm 

More information about the Twisted-Python mailing list