github.com/gogf/gf@v1.16.9/os/gsession/gsession_session.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gsession 8 9 import ( 10 "context" 11 "github.com/gogf/gf/errors/gcode" 12 "github.com/gogf/gf/errors/gerror" 13 "github.com/gogf/gf/internal/intlog" 14 "time" 15 16 "github.com/gogf/gf/container/gmap" 17 "github.com/gogf/gf/container/gvar" 18 "github.com/gogf/gf/os/gtime" 19 ) 20 21 // Session struct for storing single session data, which is bound to a single request. 22 // The Session struct is the interface with user, but the Storage is the underlying adapter designed interface 23 // for functionality implements. 24 type Session struct { 25 id string // Session id. 26 ctx context.Context // Context for current session, note that: one session one context. 27 data *gmap.StrAnyMap // Session data. 28 dirty bool // Used to mark session is modified. 29 start bool // Used to mark session is started. 30 manager *Manager // Parent manager. 31 32 // idFunc is a callback function used for creating custom session id. 33 // This is called if session id is empty ever when session starts. 34 idFunc func(ttl time.Duration) (id string) 35 } 36 37 // init does the lazy initialization for session. 38 // It here initializes real session if necessary. 39 func (s *Session) init() { 40 if s.start { 41 return 42 } 43 var err error 44 if s.id != "" { 45 // Retrieve memory session data from manager. 46 if r, _ := s.manager.sessionData.Get(s.id); r != nil { 47 s.data = r.(*gmap.StrAnyMap) 48 intlog.Print(s.ctx, "session init data:", s.data) 49 } 50 // Retrieve stored session data from storage. 51 if s.manager.storage != nil { 52 if s.data, err = s.manager.storage.GetSession(s.ctx, s.id, s.manager.ttl, s.data); err != nil && err != ErrorDisabled { 53 intlog.Errorf(s.ctx, "session restoring failed for id '%s': %v", s.id, err) 54 panic(err) 55 } 56 } 57 } 58 // Use custom session id creating function. 59 if s.id == "" && s.idFunc != nil { 60 s.id = s.idFunc(s.manager.ttl) 61 } 62 // Use default session id creating function of storage. 63 if s.id == "" { 64 s.id, err = s.manager.storage.New(s.ctx, s.manager.ttl) 65 if err != nil && err != ErrorDisabled { 66 intlog.Errorf(s.ctx, "create session id failed: %v", err) 67 panic(err) 68 } 69 } 70 // Use default session id creating function. 71 if s.id == "" { 72 s.id = NewSessionId() 73 } 74 if s.data == nil { 75 s.data = gmap.NewStrAnyMap(true) 76 } 77 s.start = true 78 79 } 80 81 // Close closes current session and updates its ttl in the session manager. 82 // If this session is dirty, it also exports it to storage. 83 // 84 // NOTE that this function must be called ever after a session request done. 85 func (s *Session) Close() { 86 if s.start && s.id != "" { 87 size := s.data.Size() 88 if s.manager.storage != nil { 89 if s.dirty { 90 if err := s.manager.storage.SetSession(s.ctx, s.id, s.data, s.manager.ttl); err != nil { 91 panic(err) 92 } 93 } else if size > 0 { 94 if err := s.manager.storage.UpdateTTL(s.ctx, s.id, s.manager.ttl); err != nil { 95 panic(err) 96 } 97 } 98 } 99 if s.dirty || size > 0 { 100 s.manager.UpdateSessionTTL(s.id, s.data) 101 } 102 } 103 } 104 105 // Set sets key-value pair to this session. 106 func (s *Session) Set(key string, value interface{}) error { 107 s.init() 108 if err := s.manager.storage.Set(s.ctx, s.id, key, value, s.manager.ttl); err != nil { 109 if err == ErrorDisabled { 110 s.data.Set(key, value) 111 } else { 112 return err 113 } 114 } 115 s.dirty = true 116 return nil 117 } 118 119 // Sets batch sets the session using map. 120 // Deprecated, use SetMap instead. 121 func (s *Session) Sets(data map[string]interface{}) error { 122 return s.SetMap(data) 123 } 124 125 // SetMap batch sets the session using map. 126 func (s *Session) SetMap(data map[string]interface{}) error { 127 s.init() 128 if err := s.manager.storage.SetMap(s.ctx, s.id, data, s.manager.ttl); err != nil { 129 if err == ErrorDisabled { 130 s.data.Sets(data) 131 } else { 132 return err 133 } 134 } 135 s.dirty = true 136 return nil 137 } 138 139 // Remove removes key along with its value from this session. 140 func (s *Session) Remove(keys ...string) error { 141 if s.id == "" { 142 return nil 143 } 144 s.init() 145 for _, key := range keys { 146 if err := s.manager.storage.Remove(s.ctx, s.id, key); err != nil { 147 if err == ErrorDisabled { 148 s.data.Remove(key) 149 } else { 150 return err 151 } 152 } 153 } 154 s.dirty = true 155 return nil 156 } 157 158 // Clear is alias of RemoveAll. 159 func (s *Session) Clear() error { 160 return s.RemoveAll() 161 } 162 163 // RemoveAll deletes all key-value pairs from this session. 164 func (s *Session) RemoveAll() error { 165 if s.id == "" { 166 return nil 167 } 168 s.init() 169 if err := s.manager.storage.RemoveAll(s.ctx, s.id); err != nil { 170 if err == ErrorDisabled { 171 s.data.Clear() 172 } else { 173 return err 174 } 175 } 176 s.dirty = true 177 return nil 178 } 179 180 // Id returns the session id for this session. 181 // It creates and returns a new session id if the session id is not passed in initialization. 182 func (s *Session) Id() string { 183 s.init() 184 return s.id 185 } 186 187 // SetId sets custom session before session starts. 188 // It returns error if it is called after session starts. 189 func (s *Session) SetId(id string) error { 190 if s.start { 191 return gerror.NewCode(gcode.CodeInvalidOperation, "session already started") 192 } 193 s.id = id 194 return nil 195 } 196 197 // SetIdFunc sets custom session id creating function before session starts. 198 // It returns error if it is called after session starts. 199 func (s *Session) SetIdFunc(f func(ttl time.Duration) string) error { 200 if s.start { 201 return gerror.NewCode(gcode.CodeInvalidOperation, "session already started") 202 } 203 s.idFunc = f 204 return nil 205 } 206 207 // Map returns all data as map. 208 // Note that it's using value copy internally for concurrent-safe purpose. 209 func (s *Session) Map() map[string]interface{} { 210 if s.id != "" { 211 s.init() 212 data, err := s.manager.storage.GetMap(s.ctx, s.id) 213 if err != nil && err != ErrorDisabled { 214 intlog.Error(s.ctx, err) 215 } 216 if data != nil { 217 return data 218 } 219 return s.data.Map() 220 } 221 return nil 222 } 223 224 // Size returns the size of the session. 225 func (s *Session) Size() int { 226 if s.id != "" { 227 s.init() 228 size, err := s.manager.storage.GetSize(s.ctx, s.id) 229 if err != nil && err != ErrorDisabled { 230 intlog.Error(s.ctx, err) 231 } 232 if size >= 0 { 233 return size 234 } 235 return s.data.Size() 236 } 237 return 0 238 } 239 240 // Contains checks whether key exist in the session. 241 func (s *Session) Contains(key string) bool { 242 s.init() 243 return s.Get(key) != nil 244 } 245 246 // IsDirty checks whether there's any data changes in the session. 247 func (s *Session) IsDirty() bool { 248 return s.dirty 249 } 250 251 // Get retrieves session value with given key. 252 // It returns `def` if the key does not exist in the session if `def` is given, 253 // or else it returns nil. 254 func (s *Session) Get(key string, def ...interface{}) interface{} { 255 if s.id == "" { 256 return nil 257 } 258 s.init() 259 v, err := s.manager.storage.Get(s.ctx, s.id, key) 260 if err != nil && err != ErrorDisabled { 261 intlog.Error(s.ctx, err) 262 } 263 if v != nil { 264 return v 265 } 266 if v := s.data.Get(key); v != nil { 267 return v 268 } 269 if len(def) > 0 { 270 return def[0] 271 } 272 return nil 273 } 274 275 func (s *Session) GetVar(key string, def ...interface{}) *gvar.Var { 276 return gvar.New(s.Get(key, def...), true) 277 } 278 279 func (s *Session) GetString(key string, def ...interface{}) string { 280 return s.GetVar(key, def...).String() 281 } 282 283 func (s *Session) GetBool(key string, def ...interface{}) bool { 284 return s.GetVar(key, def...).Bool() 285 } 286 287 func (s *Session) GetInt(key string, def ...interface{}) int { 288 return s.GetVar(key, def...).Int() 289 } 290 291 func (s *Session) GetInt8(key string, def ...interface{}) int8 { 292 return s.GetVar(key, def...).Int8() 293 } 294 295 func (s *Session) GetInt16(key string, def ...interface{}) int16 { 296 return s.GetVar(key, def...).Int16() 297 } 298 299 func (s *Session) GetInt32(key string, def ...interface{}) int32 { 300 return s.GetVar(key, def...).Int32() 301 } 302 303 func (s *Session) GetInt64(key string, def ...interface{}) int64 { 304 return s.GetVar(key, def...).Int64() 305 } 306 307 func (s *Session) GetUint(key string, def ...interface{}) uint { 308 return s.GetVar(key, def...).Uint() 309 } 310 311 func (s *Session) GetUint8(key string, def ...interface{}) uint8 { 312 return s.GetVar(key, def...).Uint8() 313 } 314 315 func (s *Session) GetUint16(key string, def ...interface{}) uint16 { 316 return s.GetVar(key, def...).Uint16() 317 } 318 319 func (s *Session) GetUint32(key string, def ...interface{}) uint32 { 320 return s.GetVar(key, def...).Uint32() 321 } 322 323 func (s *Session) GetUint64(key string, def ...interface{}) uint64 { 324 return s.GetVar(key, def...).Uint64() 325 } 326 327 func (s *Session) GetFloat32(key string, def ...interface{}) float32 { 328 return s.GetVar(key, def...).Float32() 329 } 330 331 func (s *Session) GetFloat64(key string, def ...interface{}) float64 { 332 return s.GetVar(key, def...).Float64() 333 } 334 335 func (s *Session) GetBytes(key string, def ...interface{}) []byte { 336 return s.GetVar(key, def...).Bytes() 337 } 338 339 func (s *Session) GetInts(key string, def ...interface{}) []int { 340 return s.GetVar(key, def...).Ints() 341 } 342 343 func (s *Session) GetFloats(key string, def ...interface{}) []float64 { 344 return s.GetVar(key, def...).Floats() 345 } 346 347 func (s *Session) GetStrings(key string, def ...interface{}) []string { 348 return s.GetVar(key, def...).Strings() 349 } 350 351 func (s *Session) GetInterfaces(key string, def ...interface{}) []interface{} { 352 return s.GetVar(key, def...).Interfaces() 353 } 354 355 func (s *Session) GetTime(key string, format ...string) time.Time { 356 return s.GetVar(key).Time(format...) 357 } 358 359 func (s *Session) GetGTime(key string, format ...string) *gtime.Time { 360 return s.GetVar(key).GTime(format...) 361 } 362 363 func (s *Session) GetDuration(key string, def ...interface{}) time.Duration { 364 return s.GetVar(key, def...).Duration() 365 } 366 367 func (s *Session) GetMap(key string, tags ...string) map[string]interface{} { 368 return s.GetVar(key).Map(tags...) 369 } 370 371 func (s *Session) GetMapDeep(key string, tags ...string) map[string]interface{} { 372 return s.GetVar(key).MapDeep(tags...) 373 } 374 375 func (s *Session) GetMaps(key string, tags ...string) []map[string]interface{} { 376 return s.GetVar(key).Maps(tags...) 377 } 378 379 func (s *Session) GetMapsDeep(key string, tags ...string) []map[string]interface{} { 380 return s.GetVar(key).MapsDeep(tags...) 381 } 382 383 func (s *Session) GetStruct(key string, pointer interface{}, mapping ...map[string]string) error { 384 return s.GetVar(key).Struct(pointer, mapping...) 385 } 386 387 func (s *Session) GetStructs(key string, pointer interface{}, mapping ...map[string]string) error { 388 return s.GetVar(key).Structs(pointer, mapping...) 389 }