added back anchor and selfheal broken chunks

This commit is contained in:
ston1th 2022-10-09 01:12:05 +02:00
commit 6122768619
8 changed files with 65 additions and 44 deletions

View file

@ -64,8 +64,8 @@ func main() {
slog, slog,
), ),
} }
go func() {
log.Info("starting main server", "addr", c.Server.HTTP.Addr) log.Info("starting main server", "addr", c.Server.HTTP.Addr)
go func() {
err := s.ListenAndServe() err := s.ListenAndServe()
if err != nil && err != http.ErrServerClosed { if err != nil && err != http.ErrServerClosed {
klog.Fatalf("init failed: %s", err) klog.Fatalf("init failed: %s", err)
@ -78,7 +78,6 @@ func main() {
) )
davAddr := c.Server.WebDav.Addr davAddr := c.Server.WebDav.Addr
if davAddr != "" { if davAddr != "" {
log.Info("starting webdav server", "addr", davAddr)
dav = &http.Server{ dav = &http.Server{
Addr: davAddr, Addr: davAddr,
Handler: srv.NewWebDavServer( Handler: srv.NewWebDavServer(
@ -86,6 +85,7 @@ func main() {
slog.WithName("webdav"), slog.WithName("webdav"),
), ),
} }
log.Info("starting webdav server", "addr", davAddr)
go func() { go func() {
err := dav.ListenAndServe() err := dav.ListenAndServe()
if err != nil && err != http.ErrServerClosed { if err != nil && err != http.ErrServerClosed {
@ -95,7 +95,6 @@ func main() {
} }
cacheAddr := c.Server.Cache.Addr cacheAddr := c.Server.Cache.Addr
if cacheAddr != "" { if cacheAddr != "" {
log.Info("starting cache server", "addr", cacheAddr)
cache = &http.Server{ cache = &http.Server{
Addr: cacheAddr, Addr: cacheAddr,
Handler: srv.NewCacheServer( Handler: srv.NewCacheServer(
@ -103,6 +102,7 @@ func main() {
slog.WithName("cache"), slog.WithName("cache"),
), ),
} }
log.Info("starting cache server", "addr", cacheAddr)
go func() { go func() {
err := cache.ListenAndServe() err := cache.ListenAndServe()
if err != nil && err != http.ErrServerClosed { if err != nil && err != http.ErrServerClosed {
@ -112,7 +112,6 @@ func main() {
} }
plainAddr := c.Server.Plain.Addr plainAddr := c.Server.Plain.Addr
if plainAddr != "" { if plainAddr != "" {
log.Info("starting plain server", "addr", plainAddr)
plain = &http.Server{ plain = &http.Server{
Addr: plainAddr, Addr: plainAddr,
Handler: srv.NewPlainServer( Handler: srv.NewPlainServer(
@ -120,6 +119,7 @@ func main() {
slog.WithName("plain"), slog.WithName("plain"),
), ),
} }
log.Info("starting plain server", "addr", plainAddr)
go func() { go func() {
err := plain.ListenAndServe() err := plain.ListenAndServe()
if err != nil && err != http.ErrServerClosed { if err != nil && err != http.ErrServerClosed {

View file

@ -98,8 +98,12 @@ func (f *File) Read(p []byte) (n int, err error) {
if err == io.EOF { if err == io.EOF {
return return
} }
if err == crypto.ErrDecrypt {
log.V(2).Info("rereading to cache file", "err", err)
return f.readToCache(p)
}
if err != nil { if err != nil {
if !IsIOErr(err) && err != crypto.ErrDecrypt { if !IsIOErr(err) {
log.Error(err, "error reading cache file") log.Error(err, "error reading cache file")
return return
} }

View file

@ -129,13 +129,13 @@ const (
func FileSize(s int64) string { func FileSize(s int64) string {
switch { switch {
case s >= TiB: case s >= TiB:
return strconv.Itoa(int(s/TiB)) + " TiB" return strconv.FormatFloat(float64(s)/TiB, 'f', 2, 64) + " TiB"
case s >= GiB: case s >= GiB:
return strconv.Itoa(int(s/GiB)) + " GiB" return strconv.FormatFloat(float64(s)/GiB, 'f', 2, 64) + " GiB"
case s >= MiB: case s >= MiB:
return strconv.Itoa(int(s/MiB)) + " MiB" return strconv.FormatFloat(float64(s)/MiB, 'f', 2, 64) + " MiB"
case s >= KiB: case s >= KiB:
return strconv.Itoa(int(s/KiB)) + " KiB" return strconv.FormatFloat(float64(s)/KiB, 'f', 2, 64) + " KiB"
} }
return strconv.Itoa(int(s)) + " B" return strconv.Itoa(int(s)) + " B"
} }

View file

@ -381,6 +381,7 @@ func (md *Metadata) close() (err error) {
md.cancel() md.cancel()
if md.wc != nil { if md.wc != nil {
close(md.wc) close(md.wc)
<-md.done
md.wc = nil md.wc = nil
} }
if md.f != nil { if md.f != nil {
@ -449,17 +450,14 @@ type writeAt struct {
func (md *Metadata) resetChans() { func (md *Metadata) resetChans() {
md.wc = make(chan writeAt, 10) md.wc = make(chan writeAt, 10)
md.done = make(chan struct{})
} }
func (md *Metadata) writer() { func (md *Metadata) writer() {
md.resetChans() md.resetChans()
md.err.Store(nil) md.err.Store(nil)
go func() { go func() {
for { for wa := range md.wc {
select {
case <-md.ctx.Done():
return
case wa := <-md.wc:
atomic.StoreInt64(&md.Atime, now()) atomic.StoreInt64(&md.Atime, now())
n, err := md.f.WriteAt(wa.data, wa.pos) n, err := md.f.WriteAt(wa.data, wa.pos)
if err == nil { if err == nil {
@ -472,7 +470,7 @@ func (md *Metadata) writer() {
streamingPool.Put(wa.ret) streamingPool.Put(wa.ret)
} }
} }
} close(md.done)
}() }()
} }

View file

@ -82,7 +82,7 @@ func (cs *CacheServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.Del("Last-Modified") h.Del("Last-Modified")
paths, err := i.GetPaths(p, cs.fs, true) paths, pathAnchor, err := i.GetPaths(p, cs.fs, true)
if err == io.EOF { if err == io.EOF {
w.WriteHeader(i.Status()) w.WriteHeader(i.Status())
return return
@ -94,7 +94,7 @@ func (cs *CacheServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.Set(csp, indexCSP) h.Set(csp, indexCSP)
w.WriteHeader(i.Status()) w.WriteHeader(i.Status())
err = cache.Execute(w, data{Paths: paths}) err = cache.Execute(w, data{Paths: paths, PathAnchor: pathAnchor})
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return

View file

@ -49,6 +49,7 @@ type dirContents struct {
type dir struct { type dir struct {
Name template.HTML Name template.HTML
URI template.HTML URI template.HTML
Anchor string
} }
type dirs []dir type dirs []dir
@ -96,7 +97,19 @@ func (r *responseInterceptor) Status() int {
return r.status return r.status
} }
func (r *responseInterceptor) GetPaths(path string, filesystem *fs.FS, relative bool) (dc dirContents, err error) { func xmldecode(s string) string {
s = strings.ReplaceAll(s, "&amp;", "&")
s = strings.ReplaceAll(s, "&#39;", "'")
return s
}
func urlencode(s string) string {
s = strings.ReplaceAll(s, "[", "%5B")
s = strings.ReplaceAll(s, "]", "%5D")
return s
}
func (r *responseInterceptor) GetPaths(path string, filesystem *fs.FS, relative bool) (dc dirContents, pa string, err error) {
buf := r.buf.Bytes() buf := r.buf.Bytes()
buf = bytes.ReplaceAll(buf, []byte{'&'}, []byte("&#38;")) buf = bytes.ReplaceAll(buf, []byte{'&'}, []byte("&#38;"))
err = xml.Unmarshal(buf, &dc) err = xml.Unmarshal(buf, &dc)
@ -105,19 +118,20 @@ func (r *responseInterceptor) GetPaths(path string, filesystem *fs.FS, relative
} }
dc.Base = path dc.Base = path
path = strings.TrimSuffix(path, "/") path = strings.TrimSuffix(path, "/")
pa = "#" + anchor(path)
for _, p := range dc.AllPaths { for _, p := range dc.AllPaths {
p = strings.ReplaceAll(p, "&amp;", "&") p = xmldecode(p)
p = strings.ReplaceAll(p, "&#39;", "'")
name := template.HTML(p) name := template.HTML(p)
full := path + "/" + p full := path + "/" + p
uri := template.HTML(full) uri := template.HTML(urlencode(full))
if relative { if relative {
uri = template.HTML(p) uri = template.HTML(urlencode(p))
} }
if p[len(p)-1] == '/' { if p[len(p)-1] == '/' {
dc.Dirs = append(dc.Dirs, dir{ dc.Dirs = append(dc.Dirs, dir{
Name: name, Name: name,
URI: uri, URI: uri,
Anchor: pathAnchor(p),
}) })
} else { } else {
dc.Files = append(dc.Files, file{ dc.Files = append(dc.Files, file{
@ -139,7 +153,7 @@ func getPreloads(path string, filesystem *fs.FS) (dc dirContents) {
for _, p := range filesystem.Preloads() { for _, p := range filesystem.Preloads() {
dc.Files = append(dc.Files, file{ dc.Files = append(dc.Files, file{
Name: template.HTML(p.Name), Name: template.HTML(p.Name),
URI: template.HTML(p.Name), URI: template.HTML(urlencode(p.Name)),
Size: fs.FileSize(p.Size), Size: fs.FileSize(p.Size),
Rate: p.Rate(), Rate: p.Rate(),
Status: p.Status, Status: p.Status,
@ -151,6 +165,10 @@ func getPreloads(path string, filesystem *fs.FS) (dc dirContents) {
return return
} }
func pathAnchor(s string) string {
return anchor(strings.TrimSuffix(s, "/"))
}
func anchor(s string) string { func anchor(s string) string {
if i := strings.LastIndex(s, "/"); i > 0 && i+1 < len(s) { if i := strings.LastIndex(s, "/"); i > 0 && i+1 < len(s) {
s = s[i+1:] s = s[i+1:]

View file

@ -28,6 +28,7 @@ type data struct {
QuotaCur float64 QuotaCur float64
QuotaMax float64 QuotaMax float64
Paths dirContents Paths dirContents
PathAnchor string
} }
type FileServer struct { type FileServer struct {
@ -136,7 +137,7 @@ func (fs *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.Del("Last-Modified") h.Del("Last-Modified")
paths, err := i.GetPaths(p, fs.fs, false) paths, pathAnchor, err := i.GetPaths(p, fs.fs, false)
if err == io.EOF { if err == io.EOF {
w.WriteHeader(i.Status()) w.WriteHeader(i.Status())
return return
@ -148,7 +149,7 @@ func (fs *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.Set(csp, indexCSP) h.Set(csp, indexCSP)
w.WriteHeader(i.Status()) w.WriteHeader(i.Status())
err = index.Execute(w, data{Paths: paths}) err = index.Execute(w, data{Paths: paths, PathAnchor: pathAnchor})
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return

View file

@ -5,13 +5,13 @@
<a href="/?o=preloads">[Preloads]</a></pre> <a href="/?o=preloads">[Preloads]</a></pre>
<table> <table>
<tr class="listitem"> <tr class="listitem">
<td class="listpath up"><a href="../">../</a></td> <td class="listpath up"><a href="../{{.PathAnchor}}">../</a></td>
<td class="listoptions">[dir]</td> <td class="listoptions">[dir]</td>
</tr> </tr>
<tr class="spacer"><td colspan="2"></td></tr> <tr class="spacer"><td colspan="2"></td></tr>
{{range $s := .Paths.Dirs -}} {{range $s := .Paths.Dirs -}}
<tr class="listitem"> <tr class="listitem">
<td class="listpath"><a href="{{$s.URI}}">{{$s.Name}}</a></td> <td class="listpath"><a id="{{$s.Anchor}}" href="{{$s.URI}}">{{$s.Name}}</a></td>
<td class="listoptions">[dir]</td> <td class="listoptions">[dir]</td>
</tr> </tr>
<tr class="spacer"><td colspan="2"></td></tr> <tr class="spacer"><td colspan="2"></td></tr>