Loader.purs 4.22 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.Config.REST (RESTError(..), AffRESTError)
14
import Gargantext.Core.NgramsTable.Types (Version, Versioned(..))
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
    cacheEndpoint  :: path -> AffRESTError Version
30
  , errorHandler   :: RESTError -> Effect Unit
31
  , handleResponse :: Versioned res -> ret
32 33 34
  , mkRequest      :: path -> GUC.Request
  , path           :: path
  , renderer       :: ret -> R.Element
35
  , spinnerClass   :: Maybe String
36 37 38
  )


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

52
  useCachedAPILoaderEffect { cacheEndpoint
53
                           , errorHandler
54 55 56 57
                           , handleResponse
                           , mkRequest
                           , path
                           , state }
58
  pure $ maybe (loadingSpinner { additionalClass: spinnerClass }) renderer state'
59 60

type LoaderWithCacheAPIEffectProps path res ret = (
61
    cacheEndpoint  :: path -> AffRESTError Version
62
  , errorHandler   :: RESTError -> Effect Unit
63
  , handleResponse :: Versioned res -> ret
64 65 66
  , mkRequest      :: path -> GUC.Request
  , path           :: path
  , state          :: T.Box (Maybe ret)
67 68
  )

69
useCachedAPILoaderEffect :: forall path res ret. Eq path => JSON.ReadForeign res => Eq ret =>
70 71 72
                            Record (LoaderWithCacheAPIEffectProps path res ret)
                         -> R.Hooks Unit
useCachedAPILoaderEffect { cacheEndpoint
73
                         , errorHandler
74 75 76
                         , handleResponse
                         , mkRequest
                         , path
77
                         , state: state } = do
78
  oPath <- R.useRef path
79
  state' <- T.useLive T.unequal state
80 81 82 83 84 85 86 87 88 89 90 91

  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?
92
        vr@(Versioned { version }) <- GUC.cachedJson cache req
93 94
        eCacheReal <- cacheEndpoint path
        case eCacheReal of
95
          Left err -> liftEffect $ errorHandler err
96 97 98 99 100 101 102 103 104 105 106
          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
107 108 109 110
                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
111 112
            liftEffect $ do
              T.write_ (Just $ handleResponse val) state