redownload :: (MonadReader env m, HasHttpManager env, MonadIO m, MonadLogger m)
           => Request
           -> Path Abs File -- ^ destination
           -> m Bool
redownload req0 dest = do
    $logDebug $ "Downloading " <> decodeUtf8With lenientDecode (path req0)
    let destFilePath = toFilePath dest
        etagFilePath = destFilePath <.> "etag"

    metag <- liftIO $ handleIO (const $ return Nothing) $ fmap Just $
        withBinaryFile etagFilePath ReadMode $ \h ->
            sourceHandle h $$ CB.take 512

    let req1 =
            case metag of
                Nothing -> req0
                Just etag -> req0
                    { requestHeaders =
                        requestHeaders req0 ++
                        [("If-None-Match", L.toStrict etag)]
                    }
        req2 = req1 { checkResponse = \_ _ -> return () }
    env <- ask
    liftIO $ recoveringHttp drRetryPolicyDefault $ flip runReaderT env $
      withResponse req2 $ \res -> case () of
        ()
          | responseStatus res == status200 -> liftIO $ do
              createDirectoryIfMissing True $ takeDirectory destFilePath

              -- Order here is important: first delete the etag, then write the
              -- file, then write the etag. That way, if any step fails, it will
              -- force the download to happen again.
              handleIO (const $ return ()) $ removeFile etagFilePath

              let destFilePathTmp = destFilePath <.> "tmp"
              withBinaryFile destFilePathTmp WriteMode $ \h ->
                  responseBody res $$ sinkHandle h
              renameFile destFilePathTmp destFilePath

              forM_ (lookup "ETag" (responseHeaders res)) $ \e -> do
                  let tmp = etagFilePath <.> "tmp"
                  S.writeFile tmp e
                  renameFile tmp etagFilePath

              return True
          | responseStatus res == status304 -> return False
          | otherwise -> throwM $ RedownloadFailed req2 dest $ void res

-- | Download a JSON value and parse it using a 'FromJSON' instance.
redownload :: (MonadReader env m, HasHttpManager env, MonadIO m, MonadLogger m)
           => Request
           -> Path Abs File -- ^ destination
           -> m Bool
redownload req0 dest = do
    $logDebug $ "Downloading " <> decodeUtf8With lenientDecode (path req0)
    let destFilePath = toFilePath dest
        etagFilePath = destFilePath <.> "etag"

    metag <- liftIO $ handleIO (const $ return Nothing) $ fmap Just $
        withBinaryFile etagFilePath ReadMode $ \h ->
            sourceHandle h $$ CB.take 512

    let req1 =
            case metag of
                Nothing -> req0
                Just etag -> req0
                    { requestHeaders =
                        requestHeaders req0 ++
                        [("If-None-Match", L.toStrict etag)]
                    }
        req2 = req1 { checkResponse = \_ _ -> return () }
    env <- ask
    liftIO $ recoveringHttp drRetryPolicyDefault $ flip runReaderT env $
      withResponse req2 $ \res -> case () of
        ()
          | responseStatus res == status200 -> liftIO $ do
              createDirectoryIfMissing True $ takeDirectory destFilePath

              -- Order here is important: first delete the etag, then write the
              -- file, then write the etag. That way, if any step fails, it will
              -- force the download to happen again.
              handleIO (const $ return ()) $ removeFile etagFilePath

              let destFilePathTmp = destFilePath <.> "tmp"
              withBinaryFile destFilePathTmp WriteMode $ \h ->
                  responseBody res $$ sinkHandle h
              renameFile destFilePathTmp destFilePath

              forM_ (lookup "ETag" (responseHeaders res)) $ \e -> do
                  let tmp = etagFilePath <.> "tmp"
                  S.writeFile tmp e
                  renameFile tmp etagFilePath

              return True
          | responseStatus res == status304 -> return False
          | otherwise -> throwM $ RedownloadFailed req2 dest $ void res

-- | Download a JSON value and parse it using a 'FromJSON' instance.
redownload req0 dest = do
    $logDebug $ "Downloading " <> decodeUtf8With lenientDecode (path req0)
    let destFilePath = toFilePath dest
        etagFilePath = destFilePath <.> "etag"

    metag <- liftIO $ handleIO (const $ return Nothing) $ fmap Just $
        withBinaryFile etagFilePath ReadMode $ \h ->
            sourceHandle h $$ CB.take 512

    let req1 =
            case metag of
                Nothing -> req0
                Just etag -> req0
                    { requestHeaders =
                        requestHeaders req0 ++
                        [("If-None-Match", L.toStrict etag)]
                    }
        req2 = req1 { checkResponse = \_ _ -> return () }
    env <- ask
    liftIO $ recoveringHttp drRetryPolicyDefault $ flip runReaderT env $
      withResponse req2 $ \res -> case () of
        ()
          | responseStatus res == status200 -> liftIO $ do
              createDirectoryIfMissing True $ takeDirectory destFilePath

              -- Order here is important: first delete the etag, then write the
              -- file, then write the etag. That way, if any step fails, it will
              -- force the download to happen again.
              handleIO (const $ return ()) $ removeFile etagFilePath

              let destFilePathTmp = destFilePath <.> "tmp"
              withBinaryFile destFilePathTmp WriteMode $ \h ->
                  responseBody res $$ sinkHandle h
              renameFile destFilePathTmp destFilePath

              forM_ (lookup "ETag" (responseHeaders res)) $ \e -> do
                  let tmp = etagFilePath <.> "tmp"
                  S.writeFile tmp e
                  renameFile tmp etagFilePath

              return True
          | responseStatus res == status304 -> return False
          | otherwise -> throwM $ RedownloadFailed req2 dest $ void res

-- | Download a JSON value and parse it using a 'FromJSON' instance.