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

refactor(server): file streaming logic #3103

Merged
merged 1 commit into from
Jul 13, 2023
Merged

Conversation

mertalev
Copy link
Contributor

@mertalev mertalev commented Jul 3, 2023

Description

Switching to Express's sendFile results in much cleaner code that sets appropriate headers automatically. The current approach is too manual and error-prone in the absence of a good reason for it.

Fixes #3097

How Has This Been Tested?

Tested on web by scrolling, hovering on videos and live photos and switching between content in the expanded view. All content is shown as expected and no errors are reported in the server.

@vercel
Copy link

vercel bot commented Jul 3, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Ignored Deployment
Name Status Preview Comments Updated (UTC)
immich ⬜️ Ignored (Inspect) Jul 13, 2023 4:15pm

@mertalev mertalev changed the title Fix/premature-close refactor(server): file streaming logic Jul 3, 2023
@mertalev mertalev requested a review from jrasm91 July 3, 2023 18:05
@alextran1502
Copy link
Contributor

The issue I encountered was on Android. The media player required those range properties to be sent. Can you please test on Android and make sure that you can stream the video?

@mertalev
Copy link
Contributor Author

mertalev commented Jul 3, 2023

I don't have an Android phone, but sendFile should handle ranges if they're sent in the request header.

@alextran1502
Copy link
Contributor

I can help testing later

Copy link
Member

@uhthomas uhthomas left a comment

Choose a reason for hiding this comment

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

This is great, thank you for doing this.

server/src/immich/api-v1/asset/asset.controller.ts Outdated Show resolved Hide resolved
server/src/immich/api-v1/asset/asset.service.ts Outdated Show resolved Hide resolved
server/src/immich/api-v1/asset/asset.service.ts Outdated Show resolved Hide resolved
server/src/immich/api-v1/asset/asset.service.ts Outdated Show resolved Hide resolved
@mertalev
Copy link
Contributor Author

mertalev commented Jul 3, 2023

Alright, so Nest-style exceptions don't work at all when passthrough is disabled. They leave everything up to you, so throwing an exception actually crashes the server. On the other hand, enabling it also doesn't work because the response is already sent and there's nothing to passthrough. I'm not sure if there's a good way to fix this. I'm all ears if there is, but otherwise I'll have to shelve this.

@jrasm91
Copy link
Contributor

jrasm91 commented Jul 3, 2023

Maybe we can use a custom interceptor for these types of requests. Basically automatically catch the exception and map it to a valid response.

I think you can get the http adapter and call reply potentially..

In the controller we probably want to add a .catch(...) and handle the error either via @Next() or httpAdapter.reply()

@mertalev
Copy link
Contributor Author

mertalev commented Jul 4, 2023

Adding an interceptor or filter seems to just get ignored. But adding .catch to the call gets the job done:

this.assetService.serveFile(authUser, id, query, res).catch((err: Error) => {
  let status = 500;
  let body = err.message;
  if (err instanceof HttpException) {
    status = err.getStatus();
    body = JSON.stringify(err.getResponse());
  }
  return res.status(status).end(body);
});

@jrasm91
Copy link
Contributor

jrasm91 commented Jul 4, 2023

This is probably good enough for now. We're basically copying the implementation of the default/base nestjs exception filter here though. Might be worth seeing if it is possible to call the filter.catch method manually though, instead of duplicating the logic.

@mertalev
Copy link
Contributor Author

mertalev commented Jul 4, 2023

Exception handling works now without hacks. I.. I just needed to return...

@alextran1502
Copy link
Contributor

Hello, can you help me resolve the merge conflict?

@mertalev mertalev force-pushed the fix/premature-close branch from 43f6927 to 3da2d9e Compare July 9, 2023 04:21
@mertalev
Copy link
Contributor Author

mertalev commented Jul 9, 2023

Rebased

Copy link
Contributor

@alextran1502 alextran1502 left a comment

Choose a reason for hiding this comment

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

I tested on Android device Samsung S9 and the video file cannot be played. The same issue I encountered originally thus the implementation of setResRange

Edit: Actually S8 is ancient and something cause the video cannot be played on main as well. @jrasm91 Do you mind help me test this on your Android phone?

@jrasm91
Copy link
Contributor

jrasm91 commented Jul 9, 2023

I can test it tomorrow.

@jrasm91 jrasm91 force-pushed the fix/premature-close branch from 81678da to fc97089 Compare July 13, 2023 16:15
@jrasm91 jrasm91 dismissed uhthomas’s stale review July 13, 2023 16:19

cwd is always /usr/src/app

Copy link
Contributor

@jrasm91 jrasm91 left a comment

Choose a reason for hiding this comment

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

Tested on the web and mobile. Everything looks good.

  • Videos return 206 with byte ranges
  • Seeking/buffer works
  • Images and thumbnails are served
  • premature close warning is gone from the logs

@alextran1502 alextran1502 merged commit 2fb85f4 into main Jul 13, 2023
@alextran1502 alextran1502 deleted the fix/premature-close branch July 13, 2023 21:02
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.

immich is not a compliant byte range server
4 participants