Opened 2 years ago

Closed 2 years ago

#8875 enhancement closed duplicate (duplicate)

Allow processing of protocol in ClientService, before returning it in whenConnected

Reported by: Tom Prince Owned by:
Priority: normal Milestone:
Component: core Keywords:
Cc: Branch:


ClientService should accept a callable that gets passed a protocol and returns a deferred, and call it when the connection is connected, and pass the result of that function as the result of whenConnected.

Change History (2)

comment:1 Changed 2 years ago by Tom Prince

Some discussion from IRC on 2016-04-19 regarding this:

<dreid> glyph: Hrmm… this is not the whenConnected I was looking for.
<glyph> dreid: What about it?
<dreid> I specified a use case for a callable that could act on the protocol before it was given to subscribers.
<dreid> I guess… maybe you can do what I want with composition… except you need to be able to tell if the protocol you've got is new or not.
<glyph> dreid: doesn't "new" just mean "you showed up at the right place in the composition"?
<dreid> glyph: No because Protocols are stateful.
<glyph> dreid: at the right _time_ in the composition, then :). I'm not sure I know what you mean.
<glyph> trying to do more fast blogging
<dreid> glyph: Ok, so say you want a persistent authenticated connection to an IMAP server.
<dreid> glyph: You can't just call whenConnected() then authenticate. Because authenticating on an already authenticated protocol is probably an error. And there is no way to check that the protocol is authenticated to know if you can authenticate.
<dreid> glyph: So… the closest composition is to hand ClientService a Factory that wraps the protocol and authenticates after connectionMade. But authentication returns a deferred, so you also have to wrap ClientService so you can block whenConnected calls on the authentication deferred as opposed to the endpoint connect deferred.
<dreid> Or I guess you can also wrap the endpoint?
<dreid> And not the ClientService.
<dreid> Yeah I guess you can do it by just wrapping the endpoint.
<dreid> Feels harder than ClientService exposing the hook though.
<glyph> dreid: Ah, I get what you're saying.
<glyph> dreid: Can you file a new issue?
<glyph> dreid: This is totally worth having; you should be able to share whenConnected() with other interested objects for doing stuff post-authentication.
<glyph> Or...
<glyph> dreid: You don't have to wrap the endpoint. You can just pass the other stuff a *different* callable besides whenConnected.
<dreid> the caller of whenConnected doesn't know if the protocol is pristine though.
<dreid> Only the endpoint does.
<idnar> You have to assume some stuff about the protocol, otherwise it might not even be an IMAP protocol.
<dreid> What specifically are you proposing one assume about the protocol it gets from whenConnected?
<idnar> dreid: I would expect an IMAP endpoint to be specified to either 1) do authentication for you and thus hand you an authenticated connection, or 2) not do any authentication, leaving it up to you; I wouldn't expect there to be a 3) maybe do 1) or 2) without any way for you to know
<idnar> err, I haven't had enough coffee, I guess it's the factory not the endpoint
<idnar> dreid: so to put this differently; when you call whenConnected on the ClientService, you know it's an IMAP protocol because you called some thing that makes IMAP protocols; it seems like in this scenario, you (as the programmer) should know whether the thing that makes IMAP protocols also does authentication for you or not
<dreid> Your code that just fetches some messages should not have to know if the protocol is authenticated. On that I think we agree.
<dreid> But the factory can't be the responsible party because authentication returns a deferred.
<dreid> And ClientService can't guarantee that the protocol is authenticated unless it can wait on that deferred.
<dreid> But the only connection related deferred it has is the one from the endpoint.
<dreid> To write code that CAN assume the protocol is authenticated you have to have some code somewhere else to do the authentication.
<dreid> At exactly the right time. And only once.
<idnar> I guess the problem is that getting an authenticated connection involves both the endpoint and the factory, so there's no obvious thing to wrap
<idnar> in the case of something like TLS, you get a brand new transport out at the end
<idnar> you could make a factory that wraps the protocol, but ClientService is already wrapping the protocol to do its thing, so it's pretty tricky to do it right
<idnar> to avoid the problem you described earlier, what you need to do is delay the connectionMade call that ClientService sees until authentication has happened
<idnar> while we're talking about things you could wrap, you could even wrap the whole ClientService, but that's also annoying
<glyph> I kinda want to put all this scrollback into a ticket :)
<dreid> If ClientService implements it, this is just adding a callback before unwait.

comment:2 Changed 2 years ago by Tom Prince

Resolution: duplicate
Status: newclosed

This is a duplicate of #8375.

Note: See TracTickets for help on using tickets.