Upon a GET request, my Scotty webapp will run some computation and store its result in a temporary file, which it sends as the response using file
.
Now I would like to run some cleanup (i.e. delete the temporary file) after the file has been sent. Scotty does not seem to include a way for doing so.
Is there is any functionality in WAI for achieving this?
wai gives us a function responseStream
responseStream :: Status -> ResponseHeaders -> StreamingBody -> Response
that constructs a Response
out of a StreamingBody
, which is actually a function
type StreamingBody = (Builder -> IO ()) -> IO () -> IO ()
that, given a "write" action, and a "flush" action, finds some bytes somewhere and performs all the writing and flushing.
wai also provides us with a ready-made responseFile
function:
responseFile :: Status -> ResponseHeaders -> FilePath -> Maybe FilePart -> Response
but it doesn't delete the file at the end. Could we modify it in some way? It seems that we can, with the help of the responseToStream auxiliary function
responseToStream :: Response -> (Status, ResponseHeaders, (StreamingBody -> IO a) -> IO a)
that "opens up" an already constructed Response
, allowing us to tweak things.
Like this:
import Network.Wai
import Network.HTTP.Types.Status (status200)
import System.Directory (removeFile)
responseFileDeleting' :: FilePath -> Response
responseFileDeleting' filepath =
let (status,header,streamer) =
responseToStream $ responseFile status200 [] filepath Nothing
in responseStream status header (\write flush ->
-- this would be a good place to put a bracket, if needed
do streamer (\body -> body write flush)
removeFile filepath)
(Note: the type of streamer
is a bit mind-twisting because of all the higher-orderness.)
This solution has the disadvantage that requests have to wait until the file is deleted in order to complete. Another option could be to send filepaths to some kind of concurrent queue that performed the deletions in another thread.