sess_file.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // Copyright 2014 beego Author. All Rights Reserved.
  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. package session
  15. import (
  16. "fmt"
  17. "io/ioutil"
  18. "net/http"
  19. "os"
  20. "path"
  21. "path/filepath"
  22. "sync"
  23. "time"
  24. )
  25. var (
  26. filepder = &FileProvider{}
  27. gcmaxlifetime int64
  28. )
  29. // FileSessionStore File session store
  30. type FileSessionStore struct {
  31. sid string
  32. lock sync.RWMutex
  33. values map[interface{}]interface{}
  34. }
  35. // Set value to file session
  36. func (fs *FileSessionStore) Set(key, value interface{}) error {
  37. fs.lock.Lock()
  38. defer fs.lock.Unlock()
  39. fs.values[key] = value
  40. return nil
  41. }
  42. // Get value from file session
  43. func (fs *FileSessionStore) Get(key interface{}) interface{} {
  44. fs.lock.RLock()
  45. defer fs.lock.RUnlock()
  46. if v, ok := fs.values[key]; ok {
  47. return v
  48. }
  49. return nil
  50. }
  51. // Delete value in file session by given key
  52. func (fs *FileSessionStore) Delete(key interface{}) error {
  53. fs.lock.Lock()
  54. defer fs.lock.Unlock()
  55. delete(fs.values, key)
  56. return nil
  57. }
  58. // Flush Clean all values in file session
  59. func (fs *FileSessionStore) Flush() error {
  60. fs.lock.Lock()
  61. defer fs.lock.Unlock()
  62. fs.values = make(map[interface{}]interface{})
  63. return nil
  64. }
  65. // SessionID Get file session store id
  66. func (fs *FileSessionStore) SessionID() string {
  67. return fs.sid
  68. }
  69. // SessionRelease Write file session to local file with Gob string
  70. func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) {
  71. b, err := EncodeGob(fs.values)
  72. if err != nil {
  73. SLogger.Println(err)
  74. return
  75. }
  76. _, err = os.Stat(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid))
  77. var f *os.File
  78. if err == nil {
  79. f, err = os.OpenFile(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_RDWR, 0777)
  80. } else if os.IsNotExist(err) {
  81. f, err = os.Create(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid))
  82. } else {
  83. return
  84. }
  85. f.Truncate(0)
  86. f.Seek(0, 0)
  87. f.Write(b)
  88. f.Close()
  89. }
  90. // FileProvider File session provider
  91. type FileProvider struct {
  92. lock sync.RWMutex
  93. maxlifetime int64
  94. savePath string
  95. }
  96. // SessionInit Init file session provider.
  97. // savePath sets the session files path.
  98. func (fp *FileProvider) SessionInit(maxlifetime int64, savePath string) error {
  99. fp.maxlifetime = maxlifetime
  100. fp.savePath = savePath
  101. return nil
  102. }
  103. // SessionRead Read file session by sid.
  104. // if file is not exist, create it.
  105. // the file path is generated from sid string.
  106. func (fp *FileProvider) SessionRead(sid string) (Store, error) {
  107. filepder.lock.Lock()
  108. defer filepder.lock.Unlock()
  109. err := os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777)
  110. if err != nil {
  111. SLogger.Println(err.Error())
  112. }
  113. _, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
  114. var f *os.File
  115. if err == nil {
  116. f, err = os.OpenFile(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), os.O_RDWR, 0777)
  117. } else if os.IsNotExist(err) {
  118. f, err = os.Create(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
  119. } else {
  120. return nil, err
  121. }
  122. defer f.Close()
  123. os.Chtimes(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), time.Now(), time.Now())
  124. var kv map[interface{}]interface{}
  125. b, err := ioutil.ReadAll(f)
  126. if err != nil {
  127. return nil, err
  128. }
  129. if len(b) == 0 {
  130. kv = make(map[interface{}]interface{})
  131. } else {
  132. kv, err = DecodeGob(b)
  133. if err != nil {
  134. return nil, err
  135. }
  136. }
  137. ss := &FileSessionStore{sid: sid, values: kv}
  138. return ss, nil
  139. }
  140. // SessionExist Check file session exist.
  141. // it checkes the file named from sid exist or not.
  142. func (fp *FileProvider) SessionExist(sid string) bool {
  143. filepder.lock.Lock()
  144. defer filepder.lock.Unlock()
  145. _, err := os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
  146. if err == nil {
  147. return true
  148. }
  149. return false
  150. }
  151. // SessionDestroy Remove all files in this save path
  152. func (fp *FileProvider) SessionDestroy(sid string) error {
  153. filepder.lock.Lock()
  154. defer filepder.lock.Unlock()
  155. os.Remove(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
  156. return nil
  157. }
  158. // SessionGC Recycle files in save path
  159. func (fp *FileProvider) SessionGC() {
  160. filepder.lock.Lock()
  161. defer filepder.lock.Unlock()
  162. gcmaxlifetime = fp.maxlifetime
  163. filepath.Walk(fp.savePath, gcpath)
  164. }
  165. // SessionAll Get active file session number.
  166. // it walks save path to count files.
  167. func (fp *FileProvider) SessionAll() int {
  168. a := &activeSession{}
  169. err := filepath.Walk(fp.savePath, func(path string, f os.FileInfo, err error) error {
  170. return a.visit(path, f, err)
  171. })
  172. if err != nil {
  173. SLogger.Printf("filepath.Walk() returned %v\n", err)
  174. return 0
  175. }
  176. return a.total
  177. }
  178. // SessionRegenerate Generate new sid for file session.
  179. // it delete old file and create new file named from new sid.
  180. func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (Store, error) {
  181. filepder.lock.Lock()
  182. defer filepder.lock.Unlock()
  183. oldPath := path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1]))
  184. oldSidFile := path.Join(oldPath, oldsid)
  185. newPath := path.Join(fp.savePath, string(sid[0]), string(sid[1]))
  186. newSidFile := path.Join(newPath, sid)
  187. // new sid file is exist
  188. _, err := os.Stat(newSidFile)
  189. if err == nil {
  190. return nil, fmt.Errorf("newsid %s exist", newSidFile)
  191. }
  192. err = os.MkdirAll(newPath, 0777)
  193. if err != nil {
  194. SLogger.Println(err.Error())
  195. }
  196. // if old sid file exist
  197. // 1.read and parse file content
  198. // 2.write content to new sid file
  199. // 3.remove old sid file, change new sid file atime and ctime
  200. // 4.return FileSessionStore
  201. _, err = os.Stat(oldSidFile)
  202. if err == nil {
  203. b, err := ioutil.ReadFile(oldSidFile)
  204. if err != nil {
  205. return nil, err
  206. }
  207. var kv map[interface{}]interface{}
  208. if len(b) == 0 {
  209. kv = make(map[interface{}]interface{})
  210. } else {
  211. kv, err = DecodeGob(b)
  212. if err != nil {
  213. return nil, err
  214. }
  215. }
  216. ioutil.WriteFile(newSidFile, b, 0777)
  217. os.Remove(oldSidFile)
  218. os.Chtimes(newSidFile, time.Now(), time.Now())
  219. ss := &FileSessionStore{sid: sid, values: kv}
  220. return ss, nil
  221. }
  222. // if old sid file not exist, just create new sid file and return
  223. newf, err := os.Create(newSidFile)
  224. if err != nil {
  225. return nil, err
  226. }
  227. newf.Close()
  228. ss := &FileSessionStore{sid: sid, values: make(map[interface{}]interface{})}
  229. return ss, nil
  230. }
  231. // remove file in save path if expired
  232. func gcpath(path string, info os.FileInfo, err error) error {
  233. if err != nil {
  234. return err
  235. }
  236. if info.IsDir() {
  237. return nil
  238. }
  239. if (info.ModTime().Unix() + gcmaxlifetime) < time.Now().Unix() {
  240. os.Remove(path)
  241. }
  242. return nil
  243. }
  244. type activeSession struct {
  245. total int
  246. }
  247. func (as *activeSession) visit(paths string, f os.FileInfo, err error) error {
  248. if err != nil {
  249. return err
  250. }
  251. if f.IsDir() {
  252. return nil
  253. }
  254. as.total = as.total + 1
  255. return nil
  256. }
  257. func init() {
  258. Register("file", filepder)
  259. }