cache.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // TODO: реализовать кеширование JSON и почистить код
  2. package app
  3. import (
  4. "crypto/sha1"
  5. "encoding/hex"
  6. "io"
  7. "os"
  8. "strings"
  9. "sync"
  10. "syscall"
  11. "time"
  12. )
  13. type file struct {
  14. Score int
  15. Content []byte
  16. }
  17. var tempFS = make(map[[20]byte]*file)
  18. var mx = &sync.RWMutex{}
  19. func (s skunkyart) DownloadAndSendMedia(subdomain, path string) {
  20. var url strings.Builder
  21. url.WriteString("https://images-wixmp-")
  22. url.WriteString(subdomain)
  23. url.WriteString(".wixmp.com/")
  24. url.WriteString(path)
  25. if t := s.Args.Get("token"); t != "" {
  26. url.WriteString("?token=")
  27. url.WriteString(t)
  28. }
  29. var response []byte
  30. switch {
  31. case CFG.Cache.Enabled:
  32. fileName := sha1.Sum([]byte(subdomain + path))
  33. filePath := CFG.Cache.Path + "/" + hex.EncodeToString(fileName[:])
  34. mx.Lock()
  35. if tempFS[fileName] == nil {
  36. tempFS[fileName] = &file{}
  37. }
  38. mx.Unlock()
  39. if tempFS[fileName].Content != nil {
  40. response = tempFS[fileName].Content
  41. tempFS[fileName].Score += 2
  42. break
  43. } else {
  44. file, err := os.Open(filePath)
  45. if err != nil {
  46. if dwnld := Download(url.String()); dwnld.Status == 200 && dwnld.Headers["Content-Type"][0][:5] == "image" {
  47. response = dwnld.Body
  48. try(os.WriteFile(filePath, response, 0700))
  49. } else {
  50. s.ReturnHTTPError(dwnld.Status)
  51. return
  52. }
  53. } else {
  54. file, e := io.ReadAll(file)
  55. try(e)
  56. response = file
  57. }
  58. go func() {
  59. defer restore()
  60. mx.RLock()
  61. tempFS[fileName].Content = response
  62. mx.RUnlock()
  63. for {
  64. time.Sleep(1 * time.Minute)
  65. mx.Lock()
  66. if tempFS[fileName].Score <= 0 {
  67. delete(tempFS, fileName)
  68. mx.Unlock()
  69. return
  70. }
  71. tempFS[fileName].Score--
  72. mx.Unlock()
  73. }
  74. }()
  75. }
  76. case CFG.Proxy:
  77. dwnld := Download(url.String())
  78. if dwnld.Status != 200 {
  79. s.ReturnHTTPError(dwnld.Status)
  80. return
  81. }
  82. response = dwnld.Body
  83. default:
  84. s.Writer.WriteHeader(403)
  85. response = []byte("Sorry, butt proxy on this instance are disabled.")
  86. }
  87. s.Writer.Write(response)
  88. }
  89. func InitCacheSystem() {
  90. c := &CFG.Cache
  91. for {
  92. dir, err := os.ReadDir(c.Path)
  93. if err != nil {
  94. if os.IsNotExist(err) {
  95. os.Mkdir(c.Path, 0700)
  96. continue
  97. }
  98. println(err.Error())
  99. }
  100. for _, file := range dir {
  101. fileName := c.Path + "/" + file.Name()
  102. fileInfo, err := file.Info()
  103. try(err)
  104. if c.Lifetime != "" {
  105. now := time.Now().UnixMilli()
  106. stat := fileInfo.Sys().(*syscall.Stat_t)
  107. time := statTime(stat)
  108. if time+lifetimeParsed <= now {
  109. try(os.RemoveAll(fileName))
  110. }
  111. }
  112. if c.MaxSize != 0 && fileInfo.Size() > c.MaxSize {
  113. try(os.RemoveAll(fileName))
  114. }
  115. }
  116. time.Sleep(time.Second * time.Duration(c.UpdateInterval))
  117. }
  118. }