Skip to content
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

feat(handler, s3store): implement ServerDataStore for direct content serving #1208

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

pcfreak30
Copy link

@pcfreak30 pcfreak30 commented Oct 20, 2024

  • Add ContentServerDataStore interface
  • Update handlers to use ContentServerDataStore when available
  • Implement range request handling for s3upload
  • Add tests for new ContentServerDataStore functionality
  • Update Go version to 1.22.1

Closes #1064

@pcfreak30
Copy link
Author

Please note I tried to avoid changing the go version, but go mod tidy seems to automatically do it.

This is a draft to get feedback.

@Acconut

@Acconut Acconut changed the title feat(handler, s3store): implement ServerDataStore for direct content serving, closes #1064 feat(handler, s3store): implement ServerDataStore for direct content serving Oct 21, 2024
Copy link
Member

@Acconut Acconut left a comment

Choose a reason for hiding this comment

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

Thank you very much for working on this! I left a few comments but the direction where this is heading is looking good.

var _ handler.ServerDataStore = &S3Store{}

func (store S3Store) AsServableUpload(upload handler.Upload) handler.ServableUpload {
return &S3ServableUpload{
Copy link
Member

Choose a reason for hiding this comment

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

If we implement ServeContent directly on s3Upload, we do not have to introduce another struct S3ServableUpload. This is already what we do for AsTerminatableUpload:

tusd/pkg/s3store/s3store.go

Lines 367 to 369 in 9779a84

func (store S3Store) AsTerminatableUpload(upload handler.Upload) handler.TerminatableUpload {
return upload.(*s3Upload)
}

Copy link
Author

Choose a reason for hiding this comment

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

I can change this, though I did see value in it.

upload *s3Upload
}

func (su *S3ServableUpload) ServeContent(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
Copy link
Member

Choose a reason for hiding this comment

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

Before merging, we should move these functions down in the file as they are not the most important ones. Maybe place the logic next to the other optional interfaces that S3Store implements.

Copy link
Author

Choose a reason for hiding this comment

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

👍

@@ -1249,3 +1335,95 @@ func (store S3Store) releaseUploadSemaphore() {
store.uploadSemaphore.Release()
store.uploadSemaphoreDemandMetric.Dec()
}

func (store S3Store) copyToResponseWriter(w http.ResponseWriter, r io.Reader) (int64, error) {
Copy link
Member

Choose a reason for hiding this comment

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

Can you explain what the benefit of this is over io.Copy?

Copy link
Author

Choose a reason for hiding this comment

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

TBH, I rely on AI for development and a lot of this I was able to complete due to its effort. The data copy and range logic is the most complicated parts, and as I did not have a good reason to remove them based on what I saw, I just ensured it was all valid.

If needed, I can replace with io.Copy and move on.

return err
}

func (su *S3ServableUpload) handleRangeRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, info handler.FileInfo, input *s3.GetObjectInput, rangeHeader string) error {
Copy link
Member

Choose a reason for hiding this comment

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

I'm wonder whether dedicated handling for range requests is necessary. If the request includes the Range header we can add it to GetObject without parsing the ranges and let S3 deal with it. Afterwards we just copy the Content-Range, Content-Length and ETag header from S3's response to tusd's response and copy the body.

The advantage is that we don't have to parse the header (and possibly introduce subtle bugs) and don't have to construct the Content-Range and Content-Length headers on our own.

We would also not need a dedicated handleRangeRequest function as this could all live in ServeContent.

What do you think?

Copy link
Author

Choose a reason for hiding this comment

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

I believe given that multiple ranges are possible, it made since to check it ourselves. and due to the complexity of the range checking, its why I had a unit test for the range logic made.

I can punt it all to be forwarded to s3, but I also think it is valid to verify at-least the ranges earlier in the s3 impl.

@@ -14,6 +14,8 @@ type StoreComposer struct {
Concater ConcaterDataStore
UsesLengthDeferrer bool
LengthDeferrer LengthDeferrerDataStore
Server ServerDataStore
Copy link
Member

Choose a reason for hiding this comment

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

As mentioned in #1064 (comment), I am not sure on my own whether Server is a good name as it does have a different meaning in the HTTP-land. How about ContentServer as an alternative?

We would then have StoreComposer.ContentServer, StoreComposer.UsesContentServer, StoreComposer.UseContentServer, and tusd.ContentServerDataStore.

Copy link
Author

Choose a reason for hiding this comment

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

works for me, I don't really care :P.

…ontent serving, closes tus#1064

- Add ServerDataStore interface
- Update handlers to use ContentServerDataStore when available
- Implement range request handling for s3upload
- Add tests for new ContentServerDataStore functionality
- Update Go version to 1.22.1
@pcfreak30
Copy link
Author

@Acconut changes have been made. kudos.

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.

handler: support HTTP range requests in GET /:upload
2 participants