quota.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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.IsDir() {
  115. totalUsedVolume += fs.GetFileSize(path)
  116. }
  117. return nil
  118. })
  119. if err != nil {
  120. continue
  121. }
  122. }
  123. }
  124. q.UsedStorageQuota = totalUsedVolume
  125. }
  126. func inSlice(slice []string, val string) (int, bool) {
  127. for i, item := range slice {
  128. if item == val {
  129. return i, true
  130. }
  131. }
  132. return -1, false
  133. }