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  }