Re: [web-devel] Upgrading to warp 2

On 2014-02-25 05:49, Michael Snoyman wrote:
On Mon, Feb 24, 2014 at 11:00 PM, Bardur Arantsson
wrote:
(I've taken the liberty of CC'ing the list.)
Hi all,
[--snip--]
When I try this I get:
src/Handlers.hs:96:54: No instance for (MonadResource IO) arising from a use of `sourceFileRange' Possible fix: add an instance declaration for (MonadResource IO) In the second argument of `($)', namely `sourceFileRange sfp (Just l') (Just n)' In the expression: mapOutput (Chunk . fromByteString) $ sourceFileRange sfp (Just l') (Just n) In an equation for `src': src = mapOutput (Chunk . fromByteString) $ sourceFileRange sfp (Just l') (Just n)
... which I guess kinda makes sense -- you'd need a ResourceT (or similar) in the monad stack. I'm just not sure how or where to introduce the ResourceT to get this working.
If I introduce an explicit type signature for "src",
src :: forall m . MonadResource m => Source m (Flush Builder)
then that line compiles, but I get the equivalent error at the usage site of "src" in the third argument to "responseSource" (which again also makes sense).
Anyone got any pointers?
Regards,
Firstly, why aren't you just using responseFile[1]? That will be more efficient than using a Source directly, since Warp is able to use the sendfile system call, not to mention all of Kazu's fancy fd-caching logic. Even on a non-Warp backend, the functionality can simply degrade to being the same as using a Source. Also, not sure if it's relevant, but Warp can automatically handle range requests for you, so if you simply return a responseFile and the user requests part of the file, Warp will automatically generate the 206 response.
ResponseFile is broken for some clients (with Linux host at least), specifically my type of client, a PlayStation 3 (UPnP media player). There was a Thread of Doom(TM) about it on haskell-cafe, but it caused FD leaks, though we never found out quite *why* it was broken that way. (Things may have changed since this was in February 2010, but frankly I don't even care to spend the time to find out -- I don't need the performance anyway. I think I remember testing the WAI/Warp sendfile equivalent in pre-2.0 WAI/Warp and finding that it still had the same problem.)
Anyway, the issue here is that in WAI 2.0, we removed ResourceT from the WAI stack for efficiency reasons.
Yup, I noticed that ;)
That makes the cases where you *do* need to safely allocate scarce resources like a file handle a bit trickier. In this case, I wouldn't bother with ResourceT at all, but instead explicitly use the bracket pattern, via responseSourceBracket, openFile, and closeFile. This would look like:
serveFile :: Integer -> [(Maybe Integer, Maybe Integer)] -> IO Response serveFile fsz [(l,h)] = do let l' = maybe 0 id l let h' = maybe (fsz-1) id h let n = (h' - l' + 1) let src h = mapOutput (Chunk . fromByteString) $ sourceHandleRange h (Just l') (Just n) sfp = "foo.hs" responseSourceBracket (IO.openFile sfp IO.ReadMode) (IO.hClose) $ \h -> return (partialContent206, [], src h)
[1] http://hackage.haskell.org/package/wai-2.0.0/docs/Network-Wai.html#v:respons...
Ah, yes, this works! I had noticed responseSourceBracket, but (stupidly) didn't actually try it. Thank you very much. Regards,

Thanks for keeping the mailing list involved. It's pretty quiet, but those
of us that develop on the many Haskell web frameworks highly appreciate it.
=)
Regards,
Tyler Huffman
On Tue, Feb 25, 2014 at 12:43 PM, Bardur Arantsson
On 2014-02-25 05:49, Michael Snoyman wrote:
On Mon, Feb 24, 2014 at 11:00 PM, Bardur Arantsson
(I've taken the liberty of CC'ing the list.)
Hi all,
[--snip--]
When I try this I get:
src/Handlers.hs:96:54: No instance for (MonadResource IO) arising from a use of `sourceFileRange' Possible fix: add an instance declaration for (MonadResource IO) In the second argument of `($)', namely `sourceFileRange sfp (Just l') (Just n)' In the expression: mapOutput (Chunk . fromByteString) $ sourceFileRange sfp (Just l') (Just n) In an equation for `src': src = mapOutput (Chunk . fromByteString) $ sourceFileRange sfp (Just l') (Just n)
... which I guess kinda makes sense -- you'd need a ResourceT (or similar) in the monad stack. I'm just not sure how or where to introduce the ResourceT to get this working.
If I introduce an explicit type signature for "src",
src :: forall m . MonadResource m => Source m (Flush Builder)
then that line compiles, but I get the equivalent error at the usage site of "src" in the third argument to "responseSource" (which again also makes sense).
Anyone got any pointers?
Regards,
Firstly, why aren't you just using responseFile[1]? That will be more efficient than using a Source directly, since Warp is able to use the sendfile system call, not to mention all of Kazu's fancy fd-caching logic. Even on a non-Warp backend, the functionality can simply degrade to being the same as using a Source. Also, not sure if it's relevant, but Warp can automatically handle range requests for you, so if you simply return a responseFile and the user requests part of the file, Warp will automatically generate the 206 response.
ResponseFile is broken for some clients (with Linux host at least), specifically my type of client, a PlayStation 3 (UPnP media player). There was a Thread of Doom(TM) about it on haskell-cafe, but it caused FD leaks, though we never found out quite *why* it was broken that way.
(Things may have changed since this was in February 2010, but frankly I don't even care to spend the time to find out -- I don't need the performance anyway. I think I remember testing the WAI/Warp sendfile equivalent in pre-2.0 WAI/Warp and finding that it still had the same problem.)
Anyway, the issue here is that in WAI 2.0, we removed ResourceT from the WAI stack for efficiency reasons.
Yup, I noticed that ;)
That makes the cases where you *do* need to safely allocate scarce resources like a file handle a bit trickier. In this case, I wouldn't bother with ResourceT at all, but instead explicitly use the bracket pattern, via responseSourceBracket, openFile, and closeFile. This would look like:
serveFile :: Integer -> [(Maybe Integer, Maybe Integer)] -> IO Response serveFile fsz [(l,h)] = do let l' = maybe 0 id l let h' = maybe (fsz-1) id h let n = (h' - l' + 1) let src h = mapOutput (Chunk . fromByteString) $ sourceHandleRange h (Just l') (Just n) sfp = "foo.hs" responseSourceBracket (IO.openFile sfp IO.ReadMode) (IO.hClose) $ \h -> return (partialContent206, [], src h)
[1]
http://hackage.haskell.org/package/wai-2.0.0/docs/Network-Wai.html#v:respons...
Ah, yes, this works! I had noticed responseSourceBracket, but (stupidly) didn't actually try it. Thank you very much.
Regards,
_______________________________________________ web-devel mailing list web-devel@haskell.org http://www.haskell.org/mailman/listinfo/web-devel
participants (2)
-
Bardur Arantsson
-
Tyler Huffman