Mercurial > gemma
comparison pkg/auth/store.go @ 513:b6796cd91604
Simplified the function channel inside the session store.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Fri, 24 Aug 2018 18:06:24 +0200 |
parents | 22e1bf563a04 |
children | 4a637b333417 |
comparison
equal
deleted
inserted
replaced
512:7474e9922ed5 | 513:b6796cd91604 |
---|---|
15 var Sessions *SessionStore | 15 var Sessions *SessionStore |
16 | 16 |
17 type SessionStore struct { | 17 type SessionStore struct { |
18 storage *bolt.DB | 18 storage *bolt.DB |
19 sessions map[string]*Session | 19 sessions map[string]*Session |
20 cmds chan func(*SessionStore) | 20 cmds chan func() |
21 } | 21 } |
22 | 22 |
23 var sessionsBucket = []byte("sessions") | 23 var sessionsBucket = []byte("sessions") |
24 | 24 |
25 func NewSessionStore(filename string) (*SessionStore, error) { | 25 func NewSessionStore(filename string) (*SessionStore, error) { |
26 | 26 |
27 pcp := &SessionStore{ | 27 ss := &SessionStore{ |
28 sessions: make(map[string]*Session), | 28 sessions: make(map[string]*Session), |
29 cmds: make(chan func(*SessionStore)), | 29 cmds: make(chan func()), |
30 } | 30 } |
31 if err := pcp.openStorage(filename); err != nil { | 31 if err := ss.openStorage(filename); err != nil { |
32 return nil, err | 32 return nil, err |
33 } | 33 } |
34 go pcp.run() | 34 go ss.run() |
35 return pcp, nil | 35 return ss, nil |
36 } | 36 } |
37 | 37 |
38 // openStorage opens a storage file. | 38 // openStorage opens a storage file. |
39 func (pcp *SessionStore) openStorage(filename string) error { | 39 func (ss *SessionStore) openStorage(filename string) error { |
40 | 40 |
41 // No file, nothing to restore/persist. | 41 // No file, nothing to restore/persist. |
42 if filename == "" { | 42 if filename == "" { |
43 return nil | 43 return nil |
44 } | 44 } |
60 for k, v := c.First(); k != nil; k, v = c.Next() { | 60 for k, v := c.First(); k != nil; k, v = c.Next() { |
61 var session Session | 61 var session Session |
62 if err := session.deserialize(bytes.NewReader(v)); err != nil { | 62 if err := session.deserialize(bytes.NewReader(v)); err != nil { |
63 return err | 63 return err |
64 } | 64 } |
65 pcp.sessions[string(k)] = &session | 65 ss.sessions[string(k)] = &session |
66 } | 66 } |
67 | 67 |
68 return nil | 68 return nil |
69 }) | 69 }) |
70 | 70 |
71 if err != nil { | 71 if err != nil { |
72 db.Close() | 72 db.Close() |
73 return err | 73 return err |
74 } | 74 } |
75 | 75 |
76 pcp.storage = db | 76 ss.storage = db |
77 return nil | 77 return nil |
78 } | 78 } |
79 | 79 |
80 func (pcp *SessionStore) run() { | 80 func (ss *SessionStore) run() { |
81 for { | 81 for { |
82 select { | 82 select { |
83 case cmd := <-pcp.cmds: | 83 case cmd := <-ss.cmds: |
84 cmd(pcp) | 84 cmd() |
85 case <-time.After(time.Minute * 5): | 85 case <-time.After(time.Minute * 5): |
86 pcp.cleanToken() | 86 ss.cleanToken() |
87 } | 87 } |
88 } | 88 } |
89 } | 89 } |
90 | 90 |
91 func (pcp *SessionStore) cleanToken() { | 91 func (ss *SessionStore) cleanToken() { |
92 now := time.Now() | 92 now := time.Now() |
93 for token, session := range pcp.sessions { | 93 for token, session := range ss.sessions { |
94 expires := time.Unix(session.ExpiresAt, 0) | 94 expires := time.Unix(session.ExpiresAt, 0) |
95 if expires.Before(now) { | 95 if expires.Before(now) { |
96 delete(pcp.sessions, token) | 96 delete(ss.sessions, token) |
97 pcp.remove(token) | 97 ss.remove(token) |
98 } | 98 } |
99 } | 99 } |
100 } | 100 } |
101 | 101 |
102 func (pcp *SessionStore) remove(token string) { | 102 func (ss *SessionStore) remove(token string) { |
103 if pcp.storage == nil { | 103 if ss.storage == nil { |
104 return | 104 return |
105 } | 105 } |
106 err := pcp.storage.Update(func(tx *bolt.Tx) error { | 106 err := ss.storage.Update(func(tx *bolt.Tx) error { |
107 b := tx.Bucket(sessionsBucket) | 107 b := tx.Bucket(sessionsBucket) |
108 return b.Delete([]byte(token)) | 108 return b.Delete([]byte(token)) |
109 }) | 109 }) |
110 if err != nil { | 110 if err != nil { |
111 log.Printf("error: %v\n", err) | 111 log.Printf("error: %v\n", err) |
112 } | 112 } |
113 } | 113 } |
114 | 114 |
115 func (pcp *SessionStore) Delete(token string) bool { | 115 func (ss *SessionStore) Delete(token string) bool { |
116 res := make(chan bool) | 116 res := make(chan bool) |
117 pcp.cmds <- func(pcp *SessionStore) { | 117 ss.cmds <- func() { |
118 if _, found := pcp.sessions[token]; !found { | 118 if _, found := ss.sessions[token]; !found { |
119 res <- false | 119 res <- false |
120 return | 120 return |
121 } | 121 } |
122 delete(pcp.sessions, token) | 122 delete(ss.sessions, token) |
123 pcp.remove(token) | 123 ss.remove(token) |
124 res <- true | 124 res <- true |
125 } | 125 } |
126 return <-res | 126 return <-res |
127 } | 127 } |
128 | 128 |
129 func (pcp *SessionStore) store(token string, session *Session) { | 129 func (ss *SessionStore) store(token string, session *Session) { |
130 if pcp.storage == nil { | 130 if ss.storage == nil { |
131 return | 131 return |
132 } | 132 } |
133 err := pcp.storage.Update(func(tx *bolt.Tx) error { | 133 err := ss.storage.Update(func(tx *bolt.Tx) error { |
134 b := tx.Bucket(sessionsBucket) | 134 b := tx.Bucket(sessionsBucket) |
135 var buf bytes.Buffer | 135 var buf bytes.Buffer |
136 if err := session.serialize(&buf); err != nil { | 136 if err := session.serialize(&buf); err != nil { |
137 return err | 137 return err |
138 } | 138 } |
141 if err != nil { | 141 if err != nil { |
142 log.Printf("error: %v\n", err) | 142 log.Printf("error: %v\n", err) |
143 } | 143 } |
144 } | 144 } |
145 | 145 |
146 func (pcp *SessionStore) Add(token string, session *Session) *Session { | 146 func (ss *SessionStore) Add(token string, session *Session) { |
147 res := make(chan *Session) | 147 res := make(chan struct{}) |
148 | 148 |
149 pcp.cmds <- func(cp *SessionStore) { | 149 ss.cmds <- func() { |
150 s := pcp.sessions[token] | 150 defer close(res) |
151 s := ss.sessions[token] | |
151 if s == nil { | 152 if s == nil { |
152 s = session | 153 s = session |
153 pcp.sessions[token] = session | 154 ss.sessions[token] = session |
154 } | 155 } |
155 s.touch() | 156 s.touch() |
156 pcp.store(token, s) | 157 ss.store(token, s) |
157 res <- s | 158 } |
158 } | 159 |
159 | 160 <-res |
160 s := <-res | 161 } |
161 return s | 162 |
162 } | 163 func (ss *SessionStore) Renew(token string) (string, error) { |
163 | |
164 func (pcp *SessionStore) Renew(token string) (string, error) { | |
165 | 164 |
166 type result struct { | 165 type result struct { |
167 newToken string | 166 newToken string |
168 err error | 167 err error |
169 } | 168 } |
170 | 169 |
171 resCh := make(chan result) | 170 resCh := make(chan result) |
172 | 171 |
173 pcp.cmds <- func(cp *SessionStore) { | 172 ss.cmds <- func() { |
174 session := pcp.sessions[token] | 173 session := ss.sessions[token] |
175 if session == nil { | 174 if session == nil { |
176 resCh <- result{err: ErrNoSuchToken} | 175 resCh <- result{err: ErrNoSuchToken} |
177 } else { | 176 } else { |
178 delete(pcp.sessions, token) | 177 delete(ss.sessions, token) |
179 pcp.remove(token) | 178 ss.remove(token) |
180 newToken := GenerateSessionKey() | 179 newToken := GenerateSessionKey() |
181 // TODO: Ensure that this is not racy! | 180 // TODO: Ensure that this is not racy! |
182 session.ExpiresAt = time.Now().Add(maxTokenValid).Unix() | 181 session.ExpiresAt = time.Now().Add(maxTokenValid).Unix() |
183 pcp.sessions[newToken] = session | 182 ss.sessions[newToken] = session |
184 pcp.store(newToken, session) | 183 ss.store(newToken, session) |
185 resCh <- result{newToken: newToken} | 184 resCh <- result{newToken: newToken} |
186 } | 185 } |
187 } | 186 } |
188 | 187 |
189 r := <-resCh | 188 r := <-resCh |
190 return r.newToken, r.err | 189 return r.newToken, r.err |
191 } | 190 } |
192 | 191 |
193 func (pcp *SessionStore) Session(token string) *Session { | 192 func (ss *SessionStore) Session(token string) *Session { |
194 res := make(chan *Session) | 193 res := make(chan *Session) |
195 pcp.cmds <- func(pcp *SessionStore) { | 194 ss.cmds <- func() { |
196 session := pcp.sessions[token] | 195 session := ss.sessions[token] |
197 if session == nil { | 196 if session == nil { |
198 res <- nil | 197 res <- nil |
199 } else { | 198 } else { |
200 session.touch() | 199 session.touch() |
201 pcp.store(token, session) | 200 ss.store(token, session) |
202 res <- session | 201 res <- session |
203 } | 202 } |
204 } | 203 } |
205 return <-res | 204 return <-res |
206 } | 205 } |
207 | 206 |
208 func (pcp *SessionStore) Logout(user string) { | 207 func (ss *SessionStore) Logout(user string) { |
209 pcp.cmds <- func(pcp *SessionStore) { | 208 ss.cmds <- func() { |
210 for token, session := range pcp.sessions { | 209 for token, session := range ss.sessions { |
211 if session.User == user { | 210 if session.User == user { |
212 delete(pcp.sessions, token) | 211 delete(ss.sessions, token) |
213 pcp.remove(token) | 212 ss.remove(token) |
214 } | 213 } |
215 } | 214 } |
216 } | 215 } |
217 } | 216 } |
218 | 217 |
219 func (pcp *SessionStore) Shutdown() error { | 218 func (ss *SessionStore) Shutdown() error { |
220 if db := pcp.storage; db != nil { | 219 if db := ss.storage; db != nil { |
221 log.Println("info: shutdown persistent connection pool.") | 220 log.Println("info: shutdown persistent connection pool.") |
222 pcp.storage = nil | 221 ss.storage = nil |
223 return db.Close() | 222 return db.Close() |
224 } | 223 } |
225 log.Println("info: shutdown in-memory connection pool.") | 224 log.Println("info: shutdown in-memory connection pool.") |
226 return nil | 225 return nil |
227 } | 226 } |