1
1
{-# LANGUAGE DeriveGeneric #-}
2
2
{-# LANGUAGE DuplicateRecordFields #-}
3
3
{-# LANGUAGE OverloadedStrings #-}
4
- {-# LANGUAGE TemplateHaskell #-}
5
4
6
5
module Main where
7
6
@@ -19,6 +18,7 @@ import Data.Functor.Identity
19
18
import Data.Maybe (fromMaybe )
20
19
import qualified Data.Text as DataText
21
20
import GHC.Generics
21
+ import GHC.IO.Encoding (setLocaleEncoding )
22
22
import GHC.Int
23
23
import Lib
24
24
import Network.HTTP.Req
@@ -33,18 +33,14 @@ import System.Environment
33
33
import System.FilePath
34
34
import System.IO
35
35
import System.IO.Temp
36
- import GHC.IO.Encoding (setLocaleEncoding )
37
36
38
37
-- | Entrypoint to our application
39
38
main :: IO ()
40
39
main = do
41
40
-- 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.
44
42
--
45
43
-- If we have the argument "sanity", immediately exit
46
- -- If we have no arguments, run the server
47
- -- Otherwise, error out
48
44
setLocaleEncoding utf8
49
45
args <- getArgs
50
46
case args of
@@ -54,7 +50,7 @@ main = do
54
50
-- Run our application (defined below) on port 5000 with cors enabled
55
51
run 5000 $ cors (const devCorsPolicy) app
56
52
[restUrl, " stage" ] -> do
57
- logStdOut " Launching DataHandler with dev profile"
53
+ logStdOut " Launching DataHandler with stage profile"
58
54
-- Run our application (defined below) on port 5000 with cors enabled
59
55
run 5000 $ cors (const devCorsPolicy) app
60
56
[restUrl, " prod" ] -> do
@@ -72,8 +68,8 @@ app req send =
72
68
[" data" , " upload" , id ] -> upload req send
73
69
[" data" , " download" ] -> download req send
74
70
[" 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
77
73
[" data" , " health" ] -> health req send
78
74
-- anything else: 404
79
75
missingEndpoint ->
@@ -164,6 +160,7 @@ download :: Application
164
160
download req send = do
165
161
let headers = requestHeaders req
166
162
queryParam = getDownloadQuery $ queryString req
163
+ redirectOnError = True -- todo: make this a query param or something
167
164
case queryParam of
168
165
Nothing ->
169
166
send $
@@ -175,8 +172,8 @@ download req send = do
175
172
restUrl <- getRestUrl
176
173
logStdOut " download"
177
174
(responseBody, responseStatusCode, responseStatusMessage, fileNameHeader) <- getApi headers param restUrl
178
- case responseStatusCode of
179
- 200 -> do
175
+ case ( responseStatusCode, redirectOnError) of
176
+ ( 200 , _) -> do
180
177
let d = (eitherDecode $ L. fromStrict responseBody) :: (Either String [RestResponseFile ])
181
178
case d of
182
179
Left err ->
@@ -200,18 +197,18 @@ download req send = do
200
197
]
201
198
path
202
199
Nothing
203
- xs ->
200
+ files ->
204
201
withSystemTempFile " FileFighterFileHandler.zip" $
205
202
\ tmpFileName handle ->
206
203
do
207
204
let nameOfTheFolder = fromMaybe " Files" fileNameHeader
208
205
let ss =
209
206
mapM
210
207
( \ 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))
213
210
)
214
- xs
211
+ files
215
212
createArchive tmpFileName ss
216
213
send $
217
214
responseFile
@@ -221,7 +218,24 @@ download req send = do
221
218
]
222
219
tmpFileName
223
220
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 ) ->
225
239
send $
226
240
responseLBS
227
241
(HttpTypes. mkStatus responseStatusCode responseStatusMessage)
@@ -242,59 +256,69 @@ getApi allHeaders param restUrl = runReq (defaultHttpConfig {httpConfigCheckResp
242
256
liftIO $ logStdOut $ show (getOneHeader allHeaders " Cookie" )
243
257
return (responseBody r, responseStatusCode r, responseStatusMessage r, responseHeader r " X-FF-NAME" )
244
258
245
-
246
-
247
- preview :: Application
259
+ preview :: Application
248
260
preview req send = do
249
261
let headers = requestHeaders req
250
262
id = pathInfo req !! 2
263
+ redirectOnError = True -- todo: make this a query param or something
251
264
restUrl <- getRestUrl
252
265
(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
255
269
let decoded = (eitherDecode $ L. fromStrict responseBody) :: (Either String RestResponseFile )
256
270
case decoded of
257
271
Left err ->
258
- send $
259
- responseLBS
272
+ send $
273
+ responseLBS
260
274
HttpTypes. status500
261
275
[(" Content-Type" , " application/json; charset=utf-8" )]
262
276
(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 ) ->
275
303
send $
276
304
responseLBS
277
305
(HttpTypes. mkStatus responseStatusCode responseStatusMessage)
278
306
[(" Content-Type" , " application/json; charset=utf-8" )]
279
307
(L. fromStrict responseBody)
280
-
281
-
282
-
283
308
284
309
previewApi :: [HttpTypes. Header ] -> DataText. Text -> String -> IO (S8. ByteString , Int , S8. ByteString )
285
310
previewApi allHeaders id restUrl = runReq (defaultHttpConfig {httpConfigCheckResponse = httpConfigDontCheckResponse}) $ do
286
311
r <-
287
312
req
288
313
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
290
315
-- (http (DataText.pack restUrl) /: "v1" /: "filesystem" /: id /: "info" ) -- safe by construction URL
291
316
NoReqBody -- use built-in options or add your own
292
317
bsResponse -- specify how to interpret response
293
318
(header " Cookie" (getOneHeader allHeaders " Cookie" ) <> port 8080 ) -- PORT !!
294
319
-- mempty -- query params, headers, explicit port number, etc.
295
- liftIO $ logStdOut $ show (getOneHeader allHeaders " Cookie " )
320
+ liftIO $ logStdOut " Requested fileinfo "
296
321
return (responseBody r, responseStatusCode r, responseStatusMessage r)
297
-
298
322
299
323
delete :: Application
300
324
delete req send = do
@@ -340,14 +364,12 @@ deleteApi allHeaders restUrl fileId = runReq (defaultHttpConfig {httpConfigCheck
340
364
health :: Application
341
365
health req send = do
342
366
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 " ." ))
346
368
actualFilesSize <- sum <$> mapM getFileSize files
347
369
348
370
let response =
349
371
object
350
- [ " version" .= (" 0.2.0 " :: String ),
372
+ [ " version" .= (" 0.2.1 " :: String ),
351
373
" deploymentType" .= deploymentType,
352
374
" actualFilesSize" .= actualFilesSize,
353
375
" fileCount" .= length files
0 commit comments