1
1
module WebRow.Session where
2
2
3
3
import Prelude
4
+
4
5
import Data.Argonaut (Json )
5
6
import Data.Either (hush )
6
- import Data.Lazy (Lazy , defer )
7
7
import Data.Lazy (force ) as Lazy
8
8
import Data.Map (Map )
9
9
import Data.Maybe (fromMaybe )
10
10
import Data.Validation.Semigroup (toEither )
11
11
import Effect (Effect )
12
12
import Effect.Ref (Ref )
13
- import Effect.Ref (new , read , write ) as Ref
14
13
import HTTPure (empty ) as Headers
15
14
import Polyform.Validator.Dual.Pure (Dual , runSerializer , runValidator ) as Pure
16
- import Run (FProxy , Run , SProxy (..), liftEffect )
15
+ import Run (FProxy , Run , SProxy (..))
17
16
import Run (interpret , lift , liftEffect , on , send ) as Run
18
17
import Type.Row (type (+))
19
18
import WebRow.Contrib.Run (EffRow )
@@ -23,7 +22,7 @@ import WebRow.HTTP.Cookies (defaultAttributes, delete, lookup, lookupJson, set,
23
22
import WebRow.KeyValueStore.Types (Key )
24
23
import WebRow.Session.SessionStore (SessionStore )
25
24
import WebRow.Session.SessionStore (hoist ) as SessionStore
26
- import WebRow.Session.SessionStore.InMemory (lazy ) as SessionStore.InMemory
25
+ import WebRow.Session.SessionStore.InMemory (new ) as SessionStore.InMemory
27
26
28
27
data SessionF session a
29
28
= DeleteF (Boolean → a )
@@ -71,31 +70,39 @@ cookieName = "session"
71
70
72
71
runInStore ∷
73
72
∀ eff session .
74
- Lazy ( Effect (SessionStore (Run (Cookies + EffRow + eff )) session ) ) →
73
+ Effect (SessionStore (Run (Cookies + EffRow + eff )) session ) →
75
74
Run (Cookies + EffRow + Session session + eff )
76
75
~> Run (Cookies + EffRow + eff )
77
- runInStore store action = Run .interpret (Run .on _session (handleSession store) Run .send) action
78
- where
79
- handleSession ∷
80
- Lazy (Effect (SessionStore (Run (Cookies + EffRow + eff )) session )) →
81
- SessionF session ~> Run (Cookies + EffRow + eff )
82
- handleSession ss (DeleteF next) = do
83
- void $ Cookies .delete cookieName
84
- Run .liftEffect (Lazy .force ss) >>= _.delete >>= next >>> pure
85
-
86
- handleSession ss (FetchF next) = do
87
- ss' ← Run .liftEffect $ Lazy .force ss
88
- -- | TODO:
89
- -- | * Handle custom cookie attributes (expiration etc.).
90
- -- | * Should we raise here internalServerError when `set` returns `false`?
91
- -- | * Should we run testing cycle of test cookie setup?
92
- void $ Cookies .set cookieName { value: ss'.key, attributes: Cookies .defaultAttributes }
93
- ss'.fetch >>= next >>> pure
94
-
95
- handleSession ss (SaveF v next) = do
96
- ss' ← Run .liftEffect $ Lazy .force ss
97
- void $ Cookies .set cookieName { value: ss'.key, attributes: Cookies .defaultAttributes }
98
- ss'.save v >>= next >>> pure
76
+ runInStore store = runInRunStore (Run .liftEffect store)
77
+
78
+ runInRunStore ∷
79
+ ∀ eff session .
80
+ Run (Cookies + EffRow + eff ) (SessionStore (Run (Cookies + EffRow + eff )) session ) →
81
+ Run (Cookies + EffRow + Session session + eff )
82
+ ~> Run (Cookies + EffRow + eff )
83
+ runInRunStore store action = do
84
+ s ← store
85
+ let
86
+ handleSession ∷
87
+ SessionF session ~> Run (Cookies + EffRow + eff )
88
+ handleSession (DeleteF next) = do
89
+ void $ Cookies .delete cookieName
90
+ s.delete >>= next >>> pure
91
+
92
+ handleSession (FetchF next) = do
93
+ -- | TODO:
94
+ -- | * Handle custom cookie attributes (expiration etc.).
95
+ -- | * Should we raise here internalServerError when `set` returns `false`?
96
+ -- | * Should we run testing cycle of test cookie setup?
97
+ void $ Cookies .set cookieName { value: s.key, attributes: Cookies .defaultAttributes }
98
+ s.fetch >>= next >>> pure
99
+
100
+ handleSession (SaveF v next) = do
101
+ void $ Cookies .set cookieName { value: s.key, attributes: Cookies .defaultAttributes }
102
+ a ← s.save v
103
+ pure (next a)
104
+
105
+ Run .interpret (Run .on _session handleSession Run .send) action
99
106
100
107
runInMemoryStore ∷
101
108
∀ a eff session .
@@ -104,10 +111,11 @@ runInMemoryStore ∷
104
111
Run (Cookies + EffRow + Session session + eff ) a →
105
112
Run (Cookies + EffRow + eff ) a
106
113
runInMemoryStore ref defaultSession action = do
114
+ -- | This laziness is a myth let's drop this all together
107
115
lazySessionKey ← Cookies .lookup cookieName
108
116
let
109
- effSessionStore = SessionStore.InMemory .lazy ref defaultSession lazySessionKey
110
- runInStore (map ( SessionStore .hoist Run .liftEffect) <$> effSessionStore) action
117
+ effSessionStore = SessionStore.InMemory .new ref defaultSession ( Lazy .force lazySessionKey)
118
+ runInStore (SessionStore .hoist Run .liftEffect <$> effSessionStore) action
111
119
112
120
-- | The whole session is stored in a cookie value so visible in the browser.
113
121
-- | We don't need any key-value session store.
@@ -117,41 +125,38 @@ runInCookieValue ∷
117
125
Run (Cookies + EffRow + eff ) session →
118
126
Run (Cookies + EffRow + Session session + eff ) a →
119
127
Run (Cookies + EffRow + eff ) a
120
- runInCookieValue dual defaultSession action = do
121
- default ← defaultSession
128
+ runInCookieValue dual defaultSession =
122
129
let
123
- decode maybeRepr =
124
- fromMaybe default
125
- $ (maybeRepr >>= Pure .runValidator dual >>> toEither >>> hush)
126
- lazySession ← map decode <$> Cookies .lookupJson cookieName
127
- ref ← liftEffect $ Ref .new lazySession
128
- Run .interpret (Run .on _session (handleSession ref) Run .send) action
129
- where
130
- handleSession ∷
131
- Ref (Lazy session ) →
132
- SessionF session ~> Run (Cookies + EffRow + eff )
133
- handleSession ref (DeleteF next) = do
134
- void $ Cookies .delete cookieName
135
- default ← defaultSession
136
- liftEffect $ Ref .write (defer \_ → default) ref
137
- pure (next true )
138
-
139
- handleSession ref (FetchF next) = do
140
- lazySession ← liftEffect $ Ref .read ref
141
- let
142
- session = Lazy .force lazySession
143
-
144
- json = Pure .runSerializer dual session
145
- -- | TODO:
146
- -- | * Handle custom cookie attributes (expiration etc.).
147
- -- | * Should we raise here internalServerError when `set` returns `false`?
148
- -- | * Should we run testing cycle of test cookie setup?
149
- void $ Cookies .setJson cookieName { json, attributes: Cookies .defaultAttributes }
150
- pure $ next session
151
-
152
- handleSession ref (SaveF v next) = do
153
- lazySession ← liftEffect $ Ref .read ref
154
- let
155
- json = Pure .runSerializer dual v
156
- void $ Cookies .setJson cookieName { json, attributes: Cookies .defaultAttributes }
157
- pure (next true )
130
+ fetchFromCookie = do
131
+ default ← defaultSession
132
+ map (decode default) <$> Cookies .lookupJson cookieName
133
+ where
134
+ decode default maybeRepr =
135
+ fromMaybe default
136
+ $ (maybeRepr >>= Pure .runValidator dual >>> toEither >>> hush)
137
+
138
+ handleSession ∷ SessionF session ~> Run (Cookies + EffRow + eff )
139
+ handleSession (DeleteF next) = do
140
+ void $ Cookies .delete cookieName
141
+ pure (next true )
142
+
143
+ handleSession (FetchF next) = do
144
+ session ← Lazy .force <$> fetchFromCookie
145
+ let
146
+ json = Pure .runSerializer dual session
147
+ -- | TODO:
148
+ -- | * Handle custom cookie attributes (expiration etc.).
149
+ -- | * Should we raise here internalServerError when `set` returns `false`?
150
+ -- | * Should we run testing cycle of test cookie setup?
151
+ void $ Cookies .setJson cookieName { json, attributes: Cookies .defaultAttributes }
152
+ pure $ next session
153
+
154
+ handleSession (SaveF v next) = do
155
+ lazySession ← fetchFromCookie
156
+ let
157
+ json = Pure .runSerializer dual v
158
+ void $ Cookies .setJson cookieName { json, attributes: Cookies .defaultAttributes }
159
+ pure (next true )
160
+ in
161
+ Run .interpret (Run .on _session handleSession Run .send)
162
+
0 commit comments