quota.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package quota
  2. /*
  3. ArOZ Online Storage Quota Limiting and Tracking Module
  4. author: tobychui
  5. This system track and limit the quota of the users.
  6. */
  7. import (
  8. //"log"
  9. "os"
  10. "path/filepath"
  11. db "imuslab.com/arozos/mod/database"
  12. fs "imuslab.com/arozos/mod/filesystem"
  13. )
  14. //QuotaHandler Object
  15. type QuotaHandler struct {
  16. database *db.Database //System database for storing data
  17. username string //The current username for this handler
  18. fspool []*fs.FileSystemHandler
  19. TotalStorageQuota int64
  20. UsedStorageQuota int64
  21. }
  22. //Create a storage quotation handler for this user
  23. func NewUserQuotaHandler(database *db.Database, username string, fsh []*fs.FileSystemHandler, defaultQuota int64) *QuotaHandler {
  24. //Create the quota table if not exists
  25. totalQuota := defaultQuota //Use defalt quota if init first time
  26. err := database.NewTable("quota")
  27. if err != nil {
  28. //Set this account to readonly.
  29. return &QuotaHandler{
  30. database: database,
  31. username: username,
  32. fspool: fsh,
  33. TotalStorageQuota: 0,
  34. UsedStorageQuota: 0,
  35. }
  36. }
  37. //Get the user storage quota
  38. if !database.KeyExists("quota", username+"/quota") {
  39. //This user do not have a quota yet. Put in a default quota
  40. database.Write("quota", username+"/quota", defaultQuota)
  41. }
  42. //Load the user storage quota from database
  43. thisUserQuotaManager := QuotaHandler{
  44. database: database,
  45. username: username,
  46. fspool: fsh,
  47. TotalStorageQuota: totalQuota,
  48. UsedStorageQuota: 0,
  49. }
  50. thisUserQuotaManager.CalculateQuotaUsage()
  51. return &thisUserQuotaManager
  52. }
  53. //Set and Get the user storage quota
  54. func (q *QuotaHandler) SetUserStorageQuota(quota int64) {
  55. q.database.Write("quota", q.username+"/quota", quota)
  56. q.TotalStorageQuota = quota
  57. }
  58. func (q *QuotaHandler) GetUserStorageQuota() int64 {
  59. quota := int64(-2)
  60. q.database.Read("quota", q.username+"/quota", &quota)
  61. //Also update the one in memory
  62. q.TotalStorageQuota = quota
  63. return quota
  64. }
  65. //Check if the user's quota has been initialized
  66. func (q *QuotaHandler) IsQuotaInitialized() bool {
  67. if q.GetUserStorageQuota() == int64(-2) {
  68. return false
  69. } else {
  70. return true
  71. }
  72. }
  73. func (q *QuotaHandler) RemoveUserQuota() {
  74. q.database.Delete("quota", q.username+"/quota")
  75. }
  76. func (q *QuotaHandler) HaveSpace(size int64) bool {
  77. remaining := q.TotalStorageQuota - q.UsedStorageQuota
  78. if q.TotalStorageQuota == -1 {
  79. return true
  80. }
  81. if size < remaining {
  82. return true
  83. } else {
  84. return false
  85. }
  86. }
  87. //Update the user's storage pool to new one
  88. func (q *QuotaHandler) UpdateUserStoragePool(fsh []*fs.FileSystemHandler) {
  89. q.fspool = fsh
  90. }
  91. //Claim a space for the given file and set the file ownership to this user
  92. func (q *QuotaHandler) AllocateSpace(filesize int64) error {
  93. q.UsedStorageQuota += filesize
  94. return nil
  95. }
  96. //Reclaim file occupied space (Call this before removing it)
  97. func (q *QuotaHandler) ReclaimSpace(filesize int64) error {
  98. q.UsedStorageQuota -= filesize
  99. if q.UsedStorageQuota < 0 {
  100. q.UsedStorageQuota = 0
  101. }
  102. return nil
  103. }
  104. //Recalculate the user storage quota. This takes a lot of time and CPUs
  105. func (q *QuotaHandler) CalculateQuotaUsage() {
  106. totalUsedVolume := int64(0)
  107. for _, thisfs := range q.fspool {
  108. if thisfs.Hierarchy == "user" {
  109. if !fs.FileExists(filepath.ToSlash(filepath.Clean(thisfs.Path)) + "/users/" + q.username) {
  110. //This folder not exists. Maybe not initialized
  111. continue
  112. }
  113. err := filepath.Walk(filepath.ToSlash(filepath.Clean(thisfs.Path))+"/users/"+q.username, func(path string, info os.FileInfo, err error) error {
  114. if info == nil || err != nil {
  115. //This file gone when quota is calculating. Ignore this
  116. return nil
  117. }
  118. if !info.IsDir() {
  119. totalUsedVolume += fs.GetFileSize(path)
  120. }
  121. return nil
  122. })
  123. if err != nil {
  124. continue
  125. }
  126. }
  127. }
  128. q.UsedStorageQuota = totalUsedVolume
  129. }
  130. func inSlice(slice []string, val string) (int, bool) {
  131. for i, item := range slice {
  132. if item == val {
  133. return i, true
  134. }
  135. }
  136. return -1, false
  137. }