Loader.purs 4.02 KB
Newer Older
1 2
module Gargantext.Components.NgramsTable.Loader where

3 4
import Gargantext.Prelude

5
import Affjax (Error(..))
6
import Data.Either (Either(..))
7
import Data.Maybe (Maybe(..), maybe, isJust)
8
import Effect (Effect)
9
import Effect.Aff (Aff, launchAff_, throwError)
10
import Effect.Class (liftEffect)
11
import Effect.Exception (error)
12
import Gargantext.Components.LoadingSpinner (loadingSpinner)
13
import Gargantext.Components.NgramsTable.Core (Version, Versioned(..))
14
import Gargantext.Config.REST (RESTError(..))
15
import Gargantext.Utils.CacheAPI as GUC
16 17 18
import Reactix as R
import Simple.JSON as JSON
import Toestand as T
19

20
cacheName :: String
21 22 23 24 25 26 27
cacheName = "ngrams-cache-api-loader"


clearCache :: Unit -> Aff Unit
clearCache _ = GUC.delete $ GUC.CacheName cacheName


28
type LoaderWithCacheAPIProps path res ret = (
29 30
    cacheEndpoint  :: path -> Aff (Either RESTError Version)
  , errorHandler   :: RESTError -> Effect Unit
31
  , handleResponse :: Versioned res -> ret
32 33 34
  , mkRequest      :: path -> GUC.Request
  , path           :: path
  , renderer       :: ret -> R.Element
35 36 37
  )


38
useLoaderWithCacheAPI :: forall path res ret. Eq path => JSON.ReadForeign res => Eq ret =>
39 40
                         Record (LoaderWithCacheAPIProps path res ret)
                      -> R.Hooks R.Element
41
useLoaderWithCacheAPI { cacheEndpoint, errorHandler, handleResponse, mkRequest, path, renderer } = do
42 43 44
  state <- T.useBox Nothing
  state' <- T.useLive T.unequal state

45
  useCachedAPILoaderEffect { cacheEndpoint
46
                           , errorHandler
47 48 49 50
                           , handleResponse
                           , mkRequest
                           , path
                           , state }
51
  pure $ maybe (loadingSpinner {}) renderer state'
52 53

type LoaderWithCacheAPIEffectProps path res ret = (
54
    cacheEndpoint  :: path -> Aff (Either RESTError Version)
55
  , errorHandler   :: RESTError -> Effect Unit
56
  , handleResponse :: Versioned res -> ret
57 58 59
  , mkRequest      :: path -> GUC.Request
  , path           :: path
  , state          :: T.Box (Maybe ret)
60 61
  )

62
useCachedAPILoaderEffect :: forall path res ret. Eq path => JSON.ReadForeign res => Eq ret =>
63 64 65
                            Record (LoaderWithCacheAPIEffectProps path res ret)
                         -> R.Hooks Unit
useCachedAPILoaderEffect { cacheEndpoint
66
                         , errorHandler
67 68 69
                         , handleResponse
                         , mkRequest
                         , path
70
                         , state: state } = do
71
  oPath <- R.useRef path
72
  state' <- T.useLive T.unequal state
73 74 75 76 77 78 79 80 81 82 83 84

  R.useEffect' $ do
    if (R.readRef oPath == path) && (isJust state') then
      pure unit
    else do
      R.setRef oPath path

      let req = mkRequest path
      -- log2 "[useCachedLoader] mState" mState
      launchAff_ $ do
        cache <- GUC.openCache $ GUC.CacheName cacheName
        -- TODO Parallelize?
85
        vr@(Versioned { version }) <- GUC.cachedJson cache req
86 87
        eCacheReal <- cacheEndpoint path
        case eCacheReal of
88
          Left err -> liftEffect $ errorHandler err
89 90 91 92 93 94 95 96 97 98 99
          Right cacheReal -> do
            val <- if version == cacheReal then
              pure vr
            else do
              -- liftEffect $ do
              --   log "[useCachedAPILoaderEffect] versions dont match"
              --   log2 "[useCachedAPILoaderEffect] cached version" version
              --   log2 "[useCachedAPILoaderEffect] real version" cacheReal
              _ <- GUC.deleteReq cache req
              vr'@(Versioned { version: version', data: _ }) <- GUC.cachedJson cache req
              if version' == cacheReal then
100 101 102 103
                pure vr'
              else do
                liftEffect $ errorHandler $ SendResponseError $ RequestContentError $ "[useCachedAPILoaderEffect] Fetched clean cache but hashes don't match: " <> show version <> " != " <> show cacheReal
                throwError $ error  $"[useCachedAPILoaderEffect] Fetched clean cache but hashes don't match: " <> show version <> " != " <> show cacheReal
104 105
            liftEffect $ do
              T.write_ (Just $ handleResponse val) state