Skip to content

Add FileDownloadDelegate for simple file downloads #275

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

Merged
merged 19 commits into from
Sep 10, 2020
Merged

Add FileDownloadDelegate for simple file downloads #275

merged 19 commits into from
Sep 10, 2020

Conversation

MaxDesiatov
Copy link
Member

A simple test is included, let me know if you'd like it to be more sophisticated.

Copy link
Collaborator

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this!

I'm not best placed to decide if this feature is in-scope or not, so I decided to review this as though it were in scope. I'll let others decide if the feature itself is worth adding.

@MaxDesiatov
Copy link
Member Author

As a quick note, I'd like to get more opinions on whether the feature itself should be included before I address the technical feedback provided by Cory.


public func didFinishRequest(task: HTTPClient.Task<Response>) throws -> Response {
self.writeFuture?.whenComplete { [weak self] _ in
try! self?.handle.close()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should crash if the close fails

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made it try! based on this suggestion from @weissi in the Swift Server Slack (#async-http-client channel):

and you want to try! the close. The only reason for the close to fail is that you have already closed it. If you have already closed it, then that's a serious programmer error that need fixing.

@MaxDesiatov
Copy link
Member Author

Hi @artemredkin, do you think that this feature makes sense overall in AsyncHTTPClient? Just wondering if it's worth updating the PR to address the feedback, otherwise I'd close it.

@artemredkin
Copy link
Collaborator

@MaxDesiatov Hi! Sorry I missed your question. I do think this feature would be useful

@ktoso ktoso changed the base branch from master to main August 20, 2020 01:30
@ktoso
Copy link
Contributor

ktoso commented Aug 20, 2020

Just as a heads up, the main development branch has been changed to main, following the Swift policy on this.

This PR has been re-targeted to main and should just work. However when performing rebases etc please keep this in mind -- you may want to fetch the main branch and rebase onto the main branch from now on since master is not up-to-date anymore and is going to be deleted shortly.

reportHeaders: ((HTTPHeaders) -> Void)? = nil,
reportProgress: ((_ totalBytes: Int?, _ receivedBytes: Int) -> Void)? = nil
) throws {
self.handle = try NIOFileHandle(path: path, mode: .write, flags: .allowFileCreation())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is annoying, but open is technically a blocking operation. We should consider making the handle available by a future using self.io.openFile(path:mode:flags:).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I've also created apple/swift-nio#1630 to make this more clear in NIOFaileHandle doc comments.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Lukasa BTW, there's no such thing as openFile(path:mode:flags:), there's only openFile(path:mode:flags:eventLoop:), where would you like the event loop in the initializer to come from?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll need to be the event loop that the delegate callbacks fire on.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The event loop for delegate callbacks is passed to every callback separately as an argument, do you think there's a way to get access to that event loop in the initializer? Whoever creates the delegate doesn't have access to that event loop too, it's internal and owned by the HTTPClient instance, to which the delegate doesn't have any direct access to (or even an indirect one, as far as I understand).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's possible that open may have to be delayed until the first operation on the file occurs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a great idea, I've implemented it and it's now ready for review.

}
}

func handlerAdded(context: ChannelHandlerContext) {
guard context.channel.isActive else {
self.failTaskAndNotifyDelegate(error: HTTPClientError.remoteConnectionClosed, self.delegate.didReceiveError)
self.errorCaught(context: context, error: HTTPClientError.remoteConnectionClosed)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a bunch of changes in this file that don't seem well motivated: what are they there for?

Copy link
Member Author

@MaxDesiatov MaxDesiatov Sep 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These appeared after the base branch was changed from master to main, sorry about that, I'll clean it up.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm changing the base branch back from main to master, because main is outdated compared to master in this repo.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ktoso What happened with the migration to main here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something's wrong... I have it noted that we completed the work here but seems master still was the main thing, wat?

Please do not target master @MaxDesiatov, please keep targeting main.
I'll bring main up to date again and re-do the steps about branch protection.
CI is also ticked off to have been changed but I can't confirm that since no admin rights there.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems we/I missed to change the default branch so a few PRs were made against master and merged. I've brought main up to date again, fixed that, re targeted this at main and removed master.

Please keep using main from now-on, it should be exactly the same as master just was (it was behind a few commits indeed).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I've rebased it on top of main. @Lukasa now ready for review.

@MaxDesiatov MaxDesiatov changed the base branch from main to master September 7, 2020 08:40
@MaxDesiatov MaxDesiatov requested a review from Lukasa September 7, 2020 08:40
Lukasa pushed a commit to apple/swift-nio that referenced this pull request Sep 7, 2020
This was noted in review  of swift-server/async-http-client#275, but I don't think that this was clearly stated in the documentation.
@ktoso ktoso closed this Sep 8, 2020
@ktoso ktoso reopened this Sep 8, 2020
@ktoso ktoso changed the base branch from master to main September 8, 2020 02:57
Copy link
Collaborator

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, I think this looks really good! I've left a few notes in the diff.

self.fileHandleFuture = nil
}

public func didFinishRequest(task: HTTPClient.Task<Response>) throws -> Response {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a test on the error path? I think we're missing cleanup in the didReceiveError case.

@@ -531,7 +552,8 @@ internal final class HttpBinHandler: ChannelInboundHandler {
context.writeAndFlush(wrapOutboundOut(.head(HTTPResponseHead(version: HTTPVersion(major: 1, minor: 1), status: .ok))), promise: nil)
return
case "/events/10/1": // TODO: parse path
context.write(wrapOutboundOut(.head(HTTPResponseHead(version: HTTPVersion(major: 1, minor: 1), status: .ok))), promise: nil)
let headers = HTTPHeaders([("Content-Length", "50")])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the behaviour of this endpoint (it previously automatically sent chunked encoding, now it doesn't). I don't think any of the tests rely on that behaviour, but as it's fairly cheap to add new endpoints I think I'd rather we added a new one of these.

We can keep the common code by factoring this out into a method that conditionally adds content-length if we want.

@MaxDesiatov MaxDesiatov requested a review from Lukasa September 8, 2020 17:27
Copy link
Collaborator

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice, I like it a lot!

@Lukasa Lukasa merged commit 49a0d30 into swift-server:main Sep 10, 2020
@MaxDesiatov MaxDesiatov deleted the file-download-delegate branch September 10, 2020 08:21
MaxDesiatov added a commit to swiftwasm/carton that referenced this pull request Dec 1, 2020
`FileDownloadDelegate` was introduced in swift-server/async-http-client#275, which almost directly mirrors the implementation in `carton`. Now that it's available in a released version of AHC, let's delete some code here and replace it with the version from that package.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants