11{-# LANGUAGE DeriveGeneric #-}
22{-# LANGUAGE DuplicateRecordFields #-}
33{-# LANGUAGE OverloadedStrings #-}
4- {-# LANGUAGE TemplateHaskell #-}
54
65module Main where
76
@@ -19,6 +18,7 @@ import Data.Functor.Identity
1918import Data.Maybe (fromMaybe )
2019import qualified Data.Text as DataText
2120import GHC.Generics
21+ import GHC.IO.Encoding (setLocaleEncoding )
2222import GHC.Int
2323import Lib
2424import Network.HTTP.Req
@@ -33,18 +33,14 @@ import System.Environment
3333import System.FilePath
3434import System.IO
3535import System.IO.Temp
36- import GHC.IO.Encoding (setLocaleEncoding )
3736
3837-- | Entrypoint to our application
3938main :: IO ()
4039main = do
4140 -- For ease of setup, we want to have a "sanity" command line
42- -- argument. We'll see how this is used in the Dockerfile
43- -- later. Desired behavior:
41+ -- argument.
4442 --
4543 -- If we have the argument "sanity", immediately exit
46- -- If we have no arguments, run the server
47- -- Otherwise, error out
4844 setLocaleEncoding utf8
4945 args <- getArgs
5046 case args of
@@ -54,7 +50,7 @@ main = do
5450 -- Run our application (defined below) on port 5000 with cors enabled
5551 run 5000 $ cors (const devCorsPolicy) app
5652 [restUrl, " stage" ] -> do
57- logStdOut " Launching DataHandler with dev profile"
53+ logStdOut " Launching DataHandler with stage profile"
5854 -- Run our application (defined below) on port 5000 with cors enabled
5955 run 5000 $ cors (const devCorsPolicy) app
6056 [restUrl, " prod" ] -> do
@@ -72,8 +68,8 @@ app req send =
7268 [" data" , " upload" , id ] -> upload req send
7369 [" data" , " download" ] -> download req send
7470 [" data" , " delete" , id ] -> delete req send
75- [" data" ," preview" ,id ] -> preview req send
76- [" data" ," preview" ,id ,_] -> preview req send
71+ [" data" , " preview" , id ] -> preview req send
72+ [" data" , " preview" , id , _] -> preview req send
7773 [" data" , " health" ] -> health req send
7874 -- anything else: 404
7975 missingEndpoint ->
@@ -164,6 +160,7 @@ download :: Application
164160download req send = do
165161 let headers = requestHeaders req
166162 queryParam = getDownloadQuery $ queryString req
163+ redirectOnError = True -- todo: make this a query param or something
167164 case queryParam of
168165 Nothing ->
169166 send $
@@ -175,8 +172,8 @@ download req send = do
175172 restUrl <- getRestUrl
176173 logStdOut " download"
177174 (responseBody, responseStatusCode, responseStatusMessage, fileNameHeader) <- getApi headers param restUrl
178- case responseStatusCode of
179- 200 -> do
175+ case ( responseStatusCode, redirectOnError) of
176+ ( 200 , _) -> do
180177 let d = (eitherDecode $ L. fromStrict responseBody) :: (Either String [RestResponseFile ])
181178 case d of
182179 Left err ->
@@ -200,18 +197,18 @@ download req send = do
200197 ]
201198 path
202199 Nothing
203- xs ->
200+ files ->
204201 withSystemTempFile " FileFighterFileHandler.zip" $
205202 \ tmpFileName handle ->
206203 do
207204 let nameOfTheFolder = fromMaybe " Files" fileNameHeader
208205 let ss =
209206 mapM
210207 ( \ file -> do
211- inZipPath <- mkEntrySelector $ fromMaybe (name file) (path file)
212- loadEntry Store inZipPath (getPathFromFileId (show $ fileSystemId file))
208+ inZipPath <- mkEntrySelector $ fromMaybe (name file) (path file) -- either take the filename or path
209+ loadEntry Deflate inZipPath (getPathFromFileId (show $ fileSystemId file))
213210 )
214- xs
211+ files
215212 createArchive tmpFileName ss
216213 send $
217214 responseFile
@@ -221,7 +218,24 @@ download req send = do
221218 ]
222219 tmpFileName
223220 Nothing
224- _ ->
221+ (_, True ) -> do
222+ let decoded = (eitherDecode $ L. fromStrict responseBody) :: (Either String RestApiStatus )
223+ case decoded of
224+ Left err ->
225+ send $
226+ responseLBS
227+ HttpTypes. status500
228+ [(" Content-Type" , " application/json; charset=utf-8" )]
229+ (encode $ RestApiStatus err " Internal Server Error" )
230+ Right status ->
231+ let location =
232+ " /error?dest="
233+ <> HttpTypes. urlEncode True (rawPathInfo req)
234+ <> HttpTypes. urlEncode True (rawQueryString req)
235+ <> " &message="
236+ <> HttpTypes. urlEncode True (S8. pack $ message status)
237+ in send $ responseLBS HttpTypes. status303 [(" Location" , location)] " "
238+ (_, False ) ->
225239 send $
226240 responseLBS
227241 (HttpTypes. mkStatus responseStatusCode responseStatusMessage)
@@ -242,59 +256,69 @@ getApi allHeaders param restUrl = runReq (defaultHttpConfig {httpConfigCheckResp
242256 liftIO $ logStdOut $ show (getOneHeader allHeaders " Cookie" )
243257 return (responseBody r, responseStatusCode r, responseStatusMessage r, responseHeader r " X-FF-NAME" )
244258
245-
246-
247- preview :: Application
259+ preview :: Application
248260preview req send = do
249261 let headers = requestHeaders req
250262 id = pathInfo req !! 2
263+ redirectOnError = True -- todo: make this a query param or something
251264 restUrl <- getRestUrl
252265 (responseBody, responseStatusCode, responseStatusMessage) <- previewApi headers id restUrl
253- case responseStatusCode of
254- 200 -> do
266+ logStdOut $ S8. unpack responseStatusMessage
267+ case (responseStatusCode, redirectOnError) of
268+ (200 , _) -> do
255269 let decoded = (eitherDecode $ L. fromStrict responseBody) :: (Either String RestResponseFile )
256270 case decoded of
257271 Left err ->
258- send $
259- responseLBS
272+ send $
273+ responseLBS
260274 HttpTypes. status500
261275 [(" Content-Type" , " application/json; charset=utf-8" )]
262276 (encode $ RestApiStatus err " Internal Server Error" )
263- Right file -> do
264- let fileID = fileSystemId file
265- fileMimeType = fromMaybe " application/octet-stream" (mimeType file)
266- path = getPathFromFileId $ show fileID
267- send $
268- responseFile
269- HttpTypes. status200
270- [ (" Content-Type" , S8. pack fileMimeType)
271- ]
272- path
273- Nothing
274- _ ->
277+ Right file ->
278+ let fileID = fileSystemId file
279+ fileMimeType = fromMaybe " application/octet-stream" (mimeType file)
280+ path = getPathFromFileId $ show fileID
281+ in send $
282+ responseFile
283+ HttpTypes. status200
284+ [(" Content-Type" , S8. pack fileMimeType)]
285+ path
286+ Nothing
287+ (_, True ) -> do
288+ let decoded = (eitherDecode $ L. fromStrict responseBody) :: (Either String RestApiStatus )
289+ case decoded of
290+ Left err ->
291+ send $
292+ responseLBS
293+ HttpTypes. status500
294+ [(" Content-Type" , " application/json; charset=utf-8" )]
295+ (encode $ RestApiStatus err " Internal Server Error" )
296+ Right status ->
297+ let location =
298+ " /error?dest=" <> HttpTypes. urlEncode True (rawPathInfo req)
299+ <> " &message="
300+ <> HttpTypes. urlEncode True (S8. pack $ message status)
301+ in send $ responseLBS HttpTypes. status303 [(" Location" , location)] " "
302+ (_, False ) ->
275303 send $
276304 responseLBS
277305 (HttpTypes. mkStatus responseStatusCode responseStatusMessage)
278306 [(" Content-Type" , " application/json; charset=utf-8" )]
279307 (L. fromStrict responseBody)
280-
281-
282-
283308
284309previewApi :: [HttpTypes. Header ] -> DataText. Text -> String -> IO (S8. ByteString , Int , S8. ByteString )
285310previewApi allHeaders id restUrl = runReq (defaultHttpConfig {httpConfigCheckResponse = httpConfigDontCheckResponse}) $ do
286311 r <-
287312 req
288313 GET -- method
289- (http (DataText. pack restUrl) /: " api" /: " v1" /: " filesystem" /: id /: " info" ) -- safe by construction URL
314+ (http (DataText. pack restUrl) /: " api" /: " v1" /: " filesystem" /: id /: " info" ) -- safe by construction URL
290315 -- (http (DataText.pack restUrl) /: "v1" /: "filesystem" /: id /: "info" ) -- safe by construction URL
291316 NoReqBody -- use built-in options or add your own
292317 bsResponse -- specify how to interpret response
293318 (header " Cookie" (getOneHeader allHeaders " Cookie" ) <> port 8080 ) -- PORT !!
294319 -- mempty -- query params, headers, explicit port number, etc.
295- liftIO $ logStdOut $ show (getOneHeader allHeaders " Cookie " )
320+ liftIO $ logStdOut " Requested fileinfo "
296321 return (responseBody r, responseStatusCode r, responseStatusMessage r)
297-
298322
299323delete :: Application
300324delete req send = do
@@ -340,14 +364,12 @@ deleteApi allHeaders restUrl fileId = runReq (defaultHttpConfig {httpConfigCheck
340364health :: Application
341365health req send = do
342366 deploymentType <- getDeploymentType
343- foldersIO <- fmap (filterM doesDirectoryExist) (listDirectory " ." )
344- folders <- foldersIO
345- files <- concat <$> mapM listDirectoryRelative folders
367+ files <- concat <$> (mapM listDirectoryRelative =<< (filterM doesDirectoryExist =<< listDirectory " ." ))
346368 actualFilesSize <- sum <$> mapM getFileSize files
347369
348370 let response =
349371 object
350- [ " version" .= (" 0.2.0 " :: String ),
372+ [ " version" .= (" 0.2.1 " :: String ),
351373 " deploymentType" .= deploymentType,
352374 " actualFilesSize" .= actualFilesSize,
353375 " fileCount" .= length files
0 commit comments