github.com/cloudwego/localsession@v0.0.2/session.go (about) 1 // Copyright 2023 CloudWeGo Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package localsession 16 17 import ( 18 "context" 19 "sync" 20 "sync/atomic" 21 "time" 22 ) 23 24 // Session represents a local storage for one session 25 type Session interface { 26 // IsValid tells if the session is valid at present 27 IsValid() bool 28 29 // Get returns value for specific key 30 Get(key interface{}) interface{} 31 32 // WithValue sets value for specific key,and return newly effective session 33 WithValue(key interface{}, val interface{}) Session 34 } 35 36 // SessionCtx implements Session with context, 37 // which means children session WON'T affect parent and sibling sessions 38 type SessionCtx struct { 39 enabled *atomic.Value 40 storage context.Context 41 } 42 43 // NewSessionCtx creates and enables a SessionCtx 44 func NewSessionCtx(ctx context.Context) SessionCtx { 45 var enabled atomic.Value 46 enabled.Store(true) 47 return SessionCtx{ 48 enabled: &enabled, 49 storage: ctx, 50 } 51 } 52 53 // NewSessionCtx creates and enables a SessionCtx, 54 // and disable the session after timeout 55 func NewSessionCtxWithTimeout(ctx context.Context, timeout time.Duration) SessionCtx { 56 ret := NewSessionCtx(ctx) 57 go func() { 58 <-time.NewTimer(timeout).C 59 ret.Disable() 60 }() 61 return ret 62 } 63 64 // Disable ends the session 65 func (self SessionCtx) Disable() { 66 self.enabled.Store(false) 67 } 68 69 // Export exports underlying context 70 func (self SessionCtx) Export() context.Context { 71 return self.storage 72 } 73 74 // IsValid tells if the session is valid at present 75 func (self SessionCtx) IsValid() bool { 76 return self.enabled.Load().(bool) 77 } 78 79 // Get value for specific key 80 func (self SessionCtx) Get(key interface{}) interface{} { 81 return self.storage.Value(key) 82 } 83 84 // Set value for specific key,and return newly effective session 85 func (self SessionCtx) WithValue(key interface{}, val interface{}) Session { 86 ctx := context.WithValue(self.storage, key, val) 87 return SessionCtx{ 88 enabled: self.enabled, 89 storage: ctx, 90 } 91 } 92 93 // NewSessionMap implements Session with map, 94 // which means children session WILL affect parent session and sibling sessions 95 type SessionMap struct { 96 enabled *atomic.Value 97 storage map[interface{}]interface{} 98 lock sync.RWMutex 99 } 100 101 // NewSessionMap creates and enables a SessionMap 102 func NewSessionMap(m map[interface{}]interface{}) *SessionMap { 103 var enabled atomic.Value 104 enabled.Store(true) 105 return &SessionMap{ 106 enabled: &enabled, 107 storage: m, 108 } 109 } 110 111 // NewSessionCtx creates and enables a SessionCtx, 112 // and disable the session after timeout 113 func NewSessionMapWithTimeout(m map[interface{}]interface{}, timeout time.Duration) *SessionMap { 114 ret := NewSessionMap(m) 115 go func() { 116 <-time.NewTimer(timeout).C 117 ret.Disable() 118 }() 119 return ret 120 } 121 122 // IsValid tells if the session is valid at present 123 func (self *SessionMap) IsValid() bool { 124 if self == nil { 125 return false 126 } 127 return self.enabled.Load().(bool) 128 } 129 130 // Disable ends the session 131 func (self *SessionMap) Disable() { 132 if self == nil { 133 return 134 } 135 self.enabled.Store(false) 136 } 137 138 // Export COPIES and exports underlying map 139 func (self *SessionMap) Export() map[interface{}]interface{} { 140 if self == nil { 141 return nil 142 } 143 m := make(map[interface{}]interface{}, len(self.storage)) 144 self.lock.RLock() 145 for k, v := range self.storage { 146 m[k] = v 147 } 148 self.lock.RUnlock() 149 return m 150 } 151 152 // Get value for specific key 153 func (self *SessionMap) Get(key interface{}) interface{} { 154 if self == nil { 155 return nil 156 } 157 self.lock.RLock() 158 val := self.storage[key] 159 self.lock.RUnlock() 160 return val 161 } 162 163 // Set value for specific key,and return itself 164 func (self *SessionMap) WithValue(key interface{}, val interface{}) Session { 165 if self == nil { 166 return nil 167 } 168 self.lock.Lock() 169 self.storage[key] = val 170 self.lock.Unlock() 171 return self 172 }