krz/skunky-art

Alternative privacy frontend for DeviantArt.

clone: git clone https://gitbay.org/krz/skunky-art.git

v1.3.2: app/cache.go · raw

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