krz/skunky-art
Alternative privacy frontend for DeviantArt.
clone: git clone https://gitbay.org/krz/skunky-art.git
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}