-
Notifications
You must be signed in to change notification settings - Fork 541
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extensible DispatchHandler #1338
Conversation
I don't really see what this brings other than maybe better ergonomics? The dispatcher interface is already quite extensible? Could this live outside as an npm package? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the need for better ergonomics for this, however I would not add any new globals for this. Could this be a feature of Agent instead?
At the end of the day, this is simply a proposal.
I expect some back and forth before a final revision.
Personally, I'm not happy with the shape of the API, but I'm happy to take
suggestions.
Additionally, I'm considering switching to a DispatcherDecorator model,
with a AgentBuilder for setting the global dispatcher.
…On Thu, 14 Apr 2022, 15:08 Matteo Collina, ***@***.***> wrote:
***@***.**** requested changes on this pull request.
I see the need for better ergonomics for this, however I would not add any
new globals for this. Could this be a feature of Agent instead?
—
Reply to this email directly, view it on GitHub
<#1338 (review)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA46MLIICLNLN3DLSUXB6S3VE675FANCNFSM5TLXQTAQ>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Also, I'm having trouble coming up with an API that would not create a
breaking change on a raw Client, whilst also extracting out the
RedirectHandler.
…On Sat, 16 Apr 2022, 02:53 Aron Tsang, ***@***.***> wrote:
At the end of the day, this is simply a proposal.
I expect some back and forth before a final revision.
Personally, I'm not happy with the shape of the API, but I'm happy to take
suggestions.
Additionally, I'm considering switching to a DispatcherDecorator model,
with a AgentBuilder for setting the global dispatcher.
On Thu, 14 Apr 2022, 15:08 Matteo Collina, ***@***.***>
wrote:
> ***@***.**** requested changes on this pull request.
>
> I see the need for better ergonomics for this, however I would not add
> any new globals for this. Could this be a feature of Agent instead?
>
> —
> Reply to this email directly, view it on GitHub
> <#1338 (review)>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AA46MLIICLNLN3DLSUXB6S3VE675FANCNFSM5TLXQTAQ>
> .
> You are receiving this because you authored the thread.Message ID:
> ***@***.***>
>
|
How would the DispatcherDecorator work? |
@mcollina Here is another commit showing what I mean arontsang@d54794f?diff=unified In effect we add to the constructor of Dispatcher Where We then reduce the array of |
Codecov Report
@@ Coverage Diff @@
## main #1338 +/- ##
==========================================
- Coverage 94.95% 94.67% -0.29%
==========================================
Files 51 53 +2
Lines 4816 4862 +46
==========================================
+ Hits 4573 4603 +30
- Misses 243 259 +16
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
I've just noticed that ProxyAgent could be replaced with a DispatchInterceptor quite trivially. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work! Could you run the benchmarks before/after? Could you document this new feature?
Add documentation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work!
docs/api/DispatchInterceptor.md
Outdated
'use strict' | ||
|
||
const clearHeadersInterceptor = dispatch => { | ||
const DecoratorHandler = require('undici/lib/handler/decorator') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an internal library, let's not document it. If it needs to be exposed, please use the module entry point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mcollina I would prefer this to be exposed. I am actually trying to add support for NTLM undici, which doesn't seem like a great fit for being in mainline.
The only reason I am working on this is the fact that node.js has terrible support for socket based Auth. The socket is abstracted away completely.
Additionally, I suspect opening this up will allow for lots of extensions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've also noticed that http headers being of type ByteArray means that each extension is likely to be to decode utf8 once each...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go ahead and expose it in this PR.
I've also noticed that http headers being of type ByteArray means that each extension is likely to be to decode utf8 once each...
What do you mean? Can you make an example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kibertoad this needs fixing, we should not be deep-requiring.
@ronag PTAL |
I'll have. A look next week. |
Thanks
…On Sat, 30 Apr 2022, 00:54 Robert Nagy, ***@***.***> wrote:
I'll have. A look next week.
—
Reply to this email directly, view it on GitHub
<#1338 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA46MLIK5FZFIM4M43CUDGLVHQH23ANCNFSM5TLXQTAQ>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
I think this can be achieved without modifying existing internals and I think I would maybe prefer that, i.e. implement a const client = undici.intercept(new Client('https://localhost:3000', [
dispatch => function insertHeader(opts, handler){
opts.headers.push('Authorization', 'Bearer [Some token]')
return dispatch(opts, handler)
}
]) |
Or maybe: const client = undici.compose(
() => new Client('https://localhost:3000',
dispatch => function insertHeader(opts, handler){
opts.headers.push('Authorization', 'Bearer [Some token]')
return dispatch(opts, handler)
}
) |
undici.request(url, {
decorate: [insertHeaders({ foo: 'bar' }, redirect({ maxRetries: 3 )]
}) |
This might need a few iterations and since it doesn't require any internal modifications we should consider whether or not we should first have it as an external package. Not saying we should. Just to consider. |
This would not work for my use case. I NEED to apply the decorator AT the client level of an Agent. The decorator needs to be scoped to a single TCP connection to be able to implement NTLM authentication. |
This works, but it would require an inordinate amount of boiler plate to bring up a full Agent with decorators at the right levels, Agent, Pool, Client etc... |
@arontsang Can you provide any details on
? I can't find where in the code this is happening |
docs/api/DispatchInterceptor.md
Outdated
'use strict' | ||
|
||
const clearHeadersInterceptor = dispatch => { | ||
const DecoratorHandler = require('undici/lib/handler/decorator') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kibertoad this needs fixing, we should not be deep-requiring.
docs/api/Pool.md
Outdated
@@ -19,6 +19,7 @@ Extends: [`ClientOptions`](Client.md#parameter-clientoptions) | |||
|
|||
* **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Client(origin, opts)` | |||
* **connections** `number | null` (optional) - Default: `null` - The number of `Client` instances to create. When set to `null`, the `Pool` instance will create an unlimited amount of `Client` instances. | |||
* **interceptors.Pool** `Array<DispatchInterceptor>` - Default: `[]` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not clear this is { interceptors: { Pool: [] } }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed in all docs
@mcollina Comments addressed! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would avoid introducing any more global settings, could you avoid them? Thanxk
lib/proxy-agent.js
Outdated
@@ -42,7 +62,7 @@ class ProxyAgent extends DispatcherBase { | |||
|
|||
const connect = buildConnector({ ...opts.proxyTls }) | |||
this[kConnectEndpoint] = buildConnector({ ...opts.requestTls }) | |||
this[kClient] = new Client({ origin: opts.origin, connect }) | |||
this[kClient] = new Agent({ origin: opts.origin, connect }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const Client = require('./agent')
const Agent = require('./agent')
Naming was confusing, they were exactly same thing. Am I missing anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems more like the import was incorrect?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I'll fix it then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@mcollina Do you mean new options for Client/Agent/Pool? Where would you place them instead? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, that text was a leftover from a previous half-botched review
Does this support async logic in interceptors? For example, read credentials from the disk in a request interceptor and then add them to request headers. |
Also I find it annoying when extending request headers in a request interceptor, the |
I would need help with some of this.
I am a dotnet Dev by trade, so a lot of it isn't my wheelhouse, for
example, I don't know the Jest library inside and out...
Would it be better if we put this into a branch?
…On Tue, 28 Jun 2022, 00:01 Matteo Collina, ***@***.***> wrote:
Let's go ahead and land. The code seems reasonable to me so far, minus all
the comments.
I'm 100% ok with semver-major changes on this one.
Maybe we could classify interceptors as experimental?
Could you address them @arontsang <https://github.com/arontsang>? Sorry
for the long wait.
—
Reply to this email directly, view it on GitHub
<#1338 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA46MLL6GODF7EIVJEFHAKDVRHF7HANCNFSM5TLXQTAQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
It can, but, that would get very complicated when we get to the point of
having half a dozen of these things
…On Sat, 30 Apr 2022, 02:07 Robert Nagy, ***@***.***> wrote:
I think this can be achieved without modifying existing internals and I
think I would maybe prefer that, i.e. implement a
compose/decorate/intercept (or other name) function that implements a
compose dispatcher that applies this logic. So it would essentially be
possible to do the following without any modification of existing code:
const insertHeaderInterceptor = dispatch => {
return function InterceptedDispatch(opts, handler){
opts.headers.push('Authorization', 'Bearer [Some token]')
return dispatch(opts, handler)
}}
const client = undici.intercept(new Client('https://localhost:3000', [ insertHeaderInterceptor ])
—
Reply to this email directly, view it on GitHub
<#1338 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA46MLNQYNHYTC7F5R6PARTVHQQNLANCNFSM5TLXQTAQ>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
* Create DispatchInterceptors * Add Unit Tests, fix DispatchHandler typescript Add documentation * Switch to simple null check and shortcircuit bind * Add typescript test for Dispatcher events * Move build intecepted dispatch to top level * Restore lost method * Fix TS error * Address code review comments * Fix linting * Type improvements * Fix TS tests * Address code review comments * Fix TS test * Fix types * Address comments * Fix client construction Co-authored-by: Igor Savin <iselwin@gmail.com>
* Create DispatchInterceptors * Add Unit Tests, fix DispatchHandler typescript Add documentation * Switch to simple null check and shortcircuit bind * Add typescript test for Dispatcher events * Move build intecepted dispatch to top level * Restore lost method * Fix TS error * Address code review comments * Fix linting * Type improvements * Fix TS tests * Address code review comments * Fix TS test * Fix types * Address comments * Fix client construction Co-authored-by: Igor Savin <iselwin@gmail.com>
This adds a plugin system that allows decorators to be added to the DispatchHandler as part of a pipeline.
I expect to see in future plugins such as (but not limited to):
This should support #491