You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

virtual.go 5.1 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package session
  5. import (
  6. "container/list"
  7. "encoding/json"
  8. "fmt"
  9. "sync"
  10. "github.com/go-macaron/session"
  11. couchbase "github.com/go-macaron/session/couchbase"
  12. memcache "github.com/go-macaron/session/memcache"
  13. mysql "github.com/go-macaron/session/mysql"
  14. nodb "github.com/go-macaron/session/nodb"
  15. postgres "github.com/go-macaron/session/postgres"
  16. redis "github.com/go-macaron/session/redis"
  17. )
  18. // VirtualSessionProvider represents a shadowed session provider implementation.
  19. type VirtualSessionProvider struct {
  20. lock sync.RWMutex
  21. maxlifetime int64
  22. rootPath string
  23. provider session.Provider
  24. }
  25. // Init initializes the cookie session provider with given root path.
  26. func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error {
  27. var opts session.Options
  28. if err := json.Unmarshal([]byte(config), &opts); err != nil {
  29. return err
  30. }
  31. // Note that these options are unprepared so we can't just use NewManager here.
  32. // Nor can we access the provider map in session.
  33. // So we will just have to do this by hand.
  34. // This is only slightly more wrong than modules/setting/session.go:23
  35. switch opts.Provider {
  36. case "memory":
  37. o.provider = &MemProvider{list: list.New(), data: make(map[string]*list.Element)}
  38. case "file":
  39. o.provider = &session.FileProvider{}
  40. case "redis":
  41. o.provider = &redis.RedisProvider{}
  42. case "mysql":
  43. o.provider = &mysql.MysqlProvider{}
  44. case "postgres":
  45. o.provider = &postgres.PostgresProvider{}
  46. case "couchbase":
  47. o.provider = &couchbase.CouchbaseProvider{}
  48. case "memcache":
  49. o.provider = &memcache.MemcacheProvider{}
  50. case "nodb":
  51. o.provider = &nodb.NodbProvider{}
  52. default:
  53. return fmt.Errorf("VirtualSessionProvider: Unknown Provider: %s", opts.Provider)
  54. }
  55. return o.provider.Init(gclifetime, opts.ProviderConfig)
  56. }
  57. // Read returns raw session store by session ID.
  58. func (o *VirtualSessionProvider) Read(sid string) (session.RawStore, error) {
  59. o.lock.RLock()
  60. defer o.lock.RUnlock()
  61. if o.provider.Exist(sid) {
  62. return o.provider.Read(sid)
  63. }
  64. kv := make(map[interface{}]interface{})
  65. kv["_old_uid"] = "0"
  66. return NewVirtualStore(o, sid, kv), nil
  67. }
  68. // Exist returns true if session with given ID exists.
  69. func (o *VirtualSessionProvider) Exist(sid string) bool {
  70. return true
  71. }
  72. // Destory deletes a session by session ID.
  73. func (o *VirtualSessionProvider) Destory(sid string) error {
  74. o.lock.Lock()
  75. defer o.lock.Unlock()
  76. return o.provider.Destory(sid)
  77. }
  78. // Regenerate regenerates a session store from old session ID to new one.
  79. func (o *VirtualSessionProvider) Regenerate(oldsid, sid string) (session.RawStore, error) {
  80. o.lock.Lock()
  81. defer o.lock.Unlock()
  82. return o.provider.Regenerate(oldsid, sid)
  83. }
  84. // Count counts and returns number of sessions.
  85. func (o *VirtualSessionProvider) Count() int {
  86. o.lock.RLock()
  87. defer o.lock.RUnlock()
  88. return o.provider.Count()
  89. }
  90. // GC calls GC to clean expired sessions.
  91. func (o *VirtualSessionProvider) GC() {
  92. o.provider.GC()
  93. }
  94. func init() {
  95. session.Register("VirtualSession", &VirtualSessionProvider{})
  96. }
  97. // VirtualStore represents a virtual session store implementation.
  98. type VirtualStore struct {
  99. p *VirtualSessionProvider
  100. sid string
  101. lock sync.RWMutex
  102. data map[interface{}]interface{}
  103. }
  104. // NewVirtualStore creates and returns a virtual session store.
  105. func NewVirtualStore(p *VirtualSessionProvider, sid string, kv map[interface{}]interface{}) *VirtualStore {
  106. return &VirtualStore{
  107. p: p,
  108. sid: sid,
  109. data: kv,
  110. }
  111. }
  112. // Set sets value to given key in session.
  113. func (s *VirtualStore) Set(key, val interface{}) error {
  114. s.lock.Lock()
  115. defer s.lock.Unlock()
  116. s.data[key] = val
  117. return nil
  118. }
  119. // Get gets value by given key in session.
  120. func (s *VirtualStore) Get(key interface{}) interface{} {
  121. s.lock.RLock()
  122. defer s.lock.RUnlock()
  123. return s.data[key]
  124. }
  125. // Delete delete a key from session.
  126. func (s *VirtualStore) Delete(key interface{}) error {
  127. s.lock.Lock()
  128. defer s.lock.Unlock()
  129. delete(s.data, key)
  130. return nil
  131. }
  132. // ID returns current session ID.
  133. func (s *VirtualStore) ID() string {
  134. return s.sid
  135. }
  136. // Release releases resource and save data to provider.
  137. func (s *VirtualStore) Release() error {
  138. s.lock.Lock()
  139. defer s.lock.Unlock()
  140. // Now need to lock the provider
  141. s.p.lock.Lock()
  142. defer s.p.lock.Unlock()
  143. if oldUID, ok := s.data["_old_uid"]; (ok && (oldUID != "0" || len(s.data) > 1)) || (!ok && len(s.data) > 0) {
  144. // Now ensure that we don't exist!
  145. realProvider := s.p.provider
  146. if realProvider.Exist(s.sid) {
  147. // This is an error!
  148. return fmt.Errorf("new sid '%s' already exists", s.sid)
  149. }
  150. realStore, err := realProvider.Read(s.sid)
  151. if err != nil {
  152. return err
  153. }
  154. for key, value := range s.data {
  155. if err := realStore.Set(key, value); err != nil {
  156. return err
  157. }
  158. }
  159. return realStore.Release()
  160. }
  161. return nil
  162. }
  163. // Flush deletes all session data.
  164. func (s *VirtualStore) Flush() error {
  165. s.lock.Lock()
  166. defer s.lock.Unlock()
  167. s.data = make(map[interface{}]interface{})
  168. return nil
  169. }