gsession_session.go 10 KB

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