sess_file.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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. filepder.lock.Lock()
  72. defer filepder.lock.Unlock()
  73. b, err := EncodeGob(fs.values)
  74. if err != nil {
  75. SLogger.Println(err)
  76. return
  77. }
  78. _, err = os.Stat(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid))
  79. var f *os.File
  80. if err == nil {
  81. f, err = os.OpenFile(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_RDWR, 0777)
  82. if err != nil {
  83. SLogger.Println(err)
  84. return
  85. }
  86. } else if os.IsNotExist(err) {
  87. f, err = os.Create(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid))
  88. if err != nil {
  89. SLogger.Println(err)
  90. return
  91. }
  92. } else {
  93. return
  94. }
  95. f.Truncate(0)
  96. f.Seek(0, 0)
  97. f.Write(b)
  98. f.Close()
  99. }
  100. // FileProvider File session provider
  101. type FileProvider struct {
  102. lock sync.RWMutex
  103. maxlifetime int64
  104. savePath string
  105. }
  106. // SessionInit Init file session provider.
  107. // savePath sets the session files path.
  108. func (fp *FileProvider) SessionInit(maxlifetime int64, savePath string) error {
  109. fp.maxlifetime = maxlifetime
  110. fp.savePath = savePath
  111. return nil
  112. }
  113. // SessionRead Read file session by sid.
  114. // if file is not exist, create it.
  115. // the file path is generated from sid string.
  116. func (fp *FileProvider) SessionRead(sid string) (Store, error) {
  117. filepder.lock.Lock()
  118. defer filepder.lock.Unlock()
  119. err := os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777)
  120. if err != nil {
  121. SLogger.Println(err.Error())
  122. }
  123. _, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
  124. var f *os.File
  125. if err == nil {
  126. f, err = os.OpenFile(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), os.O_RDWR, 0777)
  127. } else if os.IsNotExist(err) {
  128. f, err = os.Create(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
  129. } else {
  130. return nil, err
  131. }
  132. defer f.Close()
  133. os.Chtimes(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), time.Now(), time.Now())
  134. var kv map[interface{}]interface{}
  135. b, err := ioutil.ReadAll(f)
  136. if err != nil {
  137. return nil, err
  138. }
  139. if len(b) == 0 {
  140. kv = make(map[interface{}]interface{})
  141. } else {
  142. kv, err = DecodeGob(b)
  143. if err != nil {
  144. return nil, err
  145. }
  146. }
  147. ss := &FileSessionStore{sid: sid, values: kv}
  148. return ss, nil
  149. }
  150. // SessionExist Check file session exist.
  151. // it checks the file named from sid exist or not.
  152. func (fp *FileProvider) SessionExist(sid string) bool {
  153. filepder.lock.Lock()
  154. defer filepder.lock.Unlock()
  155. _, err := os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
  156. return err == nil
  157. }
  158. // SessionDestroy Remove all files in this save path
  159. func (fp *FileProvider) SessionDestroy(sid string) error {
  160. filepder.lock.Lock()
  161. defer filepder.lock.Unlock()
  162. os.Remove(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
  163. return nil
  164. }
  165. // SessionGC Recycle files in save path
  166. func (fp *FileProvider) SessionGC() {
  167. filepder.lock.Lock()
  168. defer filepder.lock.Unlock()
  169. gcmaxlifetime = fp.maxlifetime
  170. filepath.Walk(fp.savePath, gcpath)
  171. }
  172. // SessionAll Get active file session number.
  173. // it walks save path to count files.
  174. func (fp *FileProvider) SessionAll() int {
  175. a := &activeSession{}
  176. err := filepath.Walk(fp.savePath, func(path string, f os.FileInfo, err error) error {
  177. return a.visit(path, f, err)
  178. })
  179. if err != nil {
  180. SLogger.Printf("filepath.Walk() returned %v\n", err)
  181. return 0
  182. }
  183. return a.total
  184. }
  185. // SessionRegenerate Generate new sid for file session.
  186. // it delete old file and create new file named from new sid.
  187. func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (Store, error) {
  188. filepder.lock.Lock()
  189. defer filepder.lock.Unlock()
  190. oldPath := path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1]))
  191. oldSidFile := path.Join(oldPath, oldsid)
  192. newPath := path.Join(fp.savePath, string(sid[0]), string(sid[1]))
  193. newSidFile := path.Join(newPath, sid)
  194. // new sid file is exist
  195. _, err := os.Stat(newSidFile)
  196. if err == nil {
  197. return nil, fmt.Errorf("newsid %s exist", newSidFile)
  198. }
  199. err = os.MkdirAll(newPath, 0777)
  200. if err != nil {
  201. SLogger.Println(err.Error())
  202. }
  203. // if old sid file exist
  204. // 1.read and parse file content
  205. // 2.write content to new sid file
  206. // 3.remove old sid file, change new sid file atime and ctime
  207. // 4.return FileSessionStore
  208. _, err = os.Stat(oldSidFile)
  209. if err == nil {
  210. b, err := ioutil.ReadFile(oldSidFile)
  211. if err != nil {
  212. return nil, err
  213. }
  214. var kv map[interface{}]interface{}
  215. if len(b) == 0 {
  216. kv = make(map[interface{}]interface{})
  217. } else {
  218. kv, err = DecodeGob(b)
  219. if err != nil {
  220. return nil, err
  221. }
  222. }
  223. ioutil.WriteFile(newSidFile, b, 0777)
  224. os.Remove(oldSidFile)
  225. os.Chtimes(newSidFile, time.Now(), time.Now())
  226. ss := &FileSessionStore{sid: sid, values: kv}
  227. return ss, nil
  228. }
  229. // if old sid file not exist, just create new sid file and return
  230. newf, err := os.Create(newSidFile)
  231. if err != nil {
  232. return nil, err
  233. }
  234. newf.Close()
  235. ss := &FileSessionStore{sid: sid, values: make(map[interface{}]interface{})}
  236. return ss, nil
  237. }
  238. // remove file in save path if expired
  239. func gcpath(path string, info os.FileInfo, err error) error {
  240. if err != nil {
  241. return err
  242. }
  243. if info.IsDir() {
  244. return nil
  245. }
  246. if (info.ModTime().Unix() + gcmaxlifetime) < time.Now().Unix() {
  247. os.Remove(path)
  248. }
  249. return nil
  250. }
  251. type activeSession struct {
  252. total int
  253. }
  254. func (as *activeSession) visit(paths string, f os.FileInfo, err error) error {
  255. if err != nil {
  256. return err
  257. }
  258. if f.IsDir() {
  259. return nil
  260. }
  261. as.total = as.total + 1
  262. return nil
  263. }
  264. func init() {
  265. Register("file", filepder)
  266. }