added back anchor and selfheal broken chunks
This commit is contained in:
parent
fd035148bb
commit
6122768619
8 changed files with 65 additions and 44 deletions
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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, "&", "&")
|
||||||
|
s = strings.ReplaceAll(s, "'", "'")
|
||||||
|
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("&"))
|
buf = bytes.ReplaceAll(buf, []byte{'&'}, []byte("&"))
|
||||||
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, "&", "&")
|
p = xmldecode(p)
|
||||||
p = strings.ReplaceAll(p, "'", "'")
|
|
||||||
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:]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue