mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-06 08:22:24 +01:00
improve (performance): increase performance as per the benchmark observation
This commit is contained in:
parent
7f820b8cd4
commit
36f937da80
8 changed files with 69 additions and 57 deletions
|
|
@ -8,6 +8,7 @@ import (
|
|||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"hash/fnv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
mathrand "math/rand"
|
||||
|
|
@ -62,6 +63,24 @@ func Hash(str string, n int) string {
|
|||
return h
|
||||
}
|
||||
|
||||
func QuickHash(str string, n int) string {
|
||||
hash := fnv.New32()
|
||||
hash.Write([]byte(str))
|
||||
d := string(hash.Sum(nil))
|
||||
h := ""
|
||||
for i:=0; i<len(d); i++ {
|
||||
if n > 0 && len(h) >= n {
|
||||
break
|
||||
}
|
||||
h += ReversedBaseChange(Letters, int(d[i]))
|
||||
}
|
||||
|
||||
if len(h) > n {
|
||||
return h[0:len(h) - 1]
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func ReversedBaseChange(alphabet []rune, i int) string {
|
||||
str := ""
|
||||
for {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
var MOCK_CURRENT_DIR string
|
||||
|
||||
func GetCurrentDir() string {
|
||||
if MOCK_CURRENT_DIR != "" {
|
||||
return MOCK_CURRENT_DIR
|
||||
}
|
||||
ex, _ := os.Executable()
|
||||
return filepath.Dir(ex)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,17 @@ func SendSuccessResult(res http.ResponseWriter, data interface{}) {
|
|||
encoder.Encode(APISuccessResult{"ok", data})
|
||||
}
|
||||
|
||||
func SendSuccessResultWithEtag(res http.ResponseWriter, req *http.Request, data interface{}) {
|
||||
json, _ := json.Marshal(APISuccessResult{"ok", data})
|
||||
hash := QuickHash(string(json), 20)
|
||||
if req.Header.Get("If-None-Match") == hash {
|
||||
res.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
res.Header().Set("Etag", hash)
|
||||
res.Write(json)
|
||||
}
|
||||
|
||||
func SendSuccessResults(res http.ResponseWriter, data interface{}) {
|
||||
encoder := json.NewEncoder(res)
|
||||
encoder.SetEscapeHTML(false)
|
||||
|
|
|
|||
|
|
@ -76,21 +76,12 @@ func AdminSessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Reques
|
|||
SendSuccessResult(res, true)
|
||||
}
|
||||
|
||||
|
||||
func AdminBackend(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
backends := make(map[string]Form)
|
||||
func AdminBackend(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
drivers := Backend.Drivers()
|
||||
backends := make(map[string]Form, len(drivers))
|
||||
for key := range drivers {
|
||||
backends[key] = drivers[key].LoginForm()
|
||||
}
|
||||
|
||||
if c, err := json.Marshal(backends); err == nil {
|
||||
hash := Hash(string(c), 20)
|
||||
if req.Header.Get("If-None-Match") == hash {
|
||||
res.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
res.Header().Set("Etag", hash)
|
||||
}
|
||||
SendSuccessResult(res, backends)
|
||||
SendSuccessResultWithEtag(res, req, backends)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package ctrl
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
|
@ -14,10 +13,11 @@ import (
|
|||
var (
|
||||
logpath = filepath.Join(GetCurrentDir(), LOG_PATH, "access.log")
|
||||
cachepath = filepath.Join(GetCurrentDir(), CONFIG_PATH, "config.json")
|
||||
pluginpath = filepath.Join(GetCurrentDir(), PLUGIN_PATH)
|
||||
)
|
||||
|
||||
func FetchPluginsHandler(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
f, err := os.OpenFile(filepath.Join(GetCurrentDir(), PLUGIN_PATH), os.O_RDONLY, os.ModePerm)
|
||||
f, err := os.OpenFile(pluginpath, os.O_RDONLY, os.ModePerm)
|
||||
if err != nil {
|
||||
SendErrorResult(res, err)
|
||||
return
|
||||
|
|
@ -90,14 +90,5 @@ func PrivateConfigUpdateHandler(ctx App, res http.ResponseWriter, req *http.Requ
|
|||
|
||||
func PublicConfigHandler(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
cfg := Config.Export()
|
||||
|
||||
if c, err := json.Marshal(cfg); err == nil {
|
||||
hash := Hash(string(c), 20)
|
||||
if req.Header.Get("If-None-Match") == hash {
|
||||
res.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
res.Header().Set("Etag", hash)
|
||||
}
|
||||
SendSuccessResult(res, cfg)
|
||||
SendSuccessResultWithEtag(res, req, cfg)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package ctrl
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"github.com/mickael-kerjean/filestash/server/model"
|
||||
"io"
|
||||
|
|
@ -19,13 +19,12 @@ type FileInfo struct {
|
|||
}
|
||||
|
||||
func FileLs(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
var files []FileInfo = make([]FileInfo, 0)
|
||||
if model.CanRead(&ctx) == false {
|
||||
if model.CanUpload(&ctx) == false {
|
||||
SendErrorResult(res, NewError("Permission denied", 403))
|
||||
return
|
||||
}
|
||||
SendSuccessResults(res, files)
|
||||
SendSuccessResults(res, make([]FileInfo, 0))
|
||||
return
|
||||
}
|
||||
path, err := pathBuilder(ctx, req.URL.Query().Get("path"))
|
||||
|
|
@ -40,21 +39,23 @@ func FileLs(ctx App, res http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
f := FileInfo{
|
||||
Name: entry.Name(),
|
||||
Size: entry.Size(),
|
||||
files := make([]FileInfo, len(entries))
|
||||
etag := fmt.Sprintf("%d", len(entries)) + path
|
||||
for i:=0; i<len(entries); i++ {
|
||||
etag += files[i].Name
|
||||
files[i] = FileInfo{
|
||||
Name: entries[i].Name(),
|
||||
Size: entries[i].Size(),
|
||||
Time: func(t time.Time) int64 {
|
||||
return t.UnixNano() / int64(time.Millisecond)
|
||||
}(entry.ModTime()),
|
||||
}(entries[i].ModTime()),
|
||||
Type: func(isDir bool) string {
|
||||
if isDir == true {
|
||||
return "directory"
|
||||
}
|
||||
return "file"
|
||||
}(entry.IsDir()),
|
||||
}(entries[i].IsDir()),
|
||||
}
|
||||
files = append(files, f)
|
||||
}
|
||||
|
||||
var perms Metadata = Metadata{}
|
||||
|
|
@ -79,22 +80,12 @@ func FileLs(ctx App, res http.ResponseWriter, req *http.Request) {
|
|||
perms.CanShare = NewBool(false)
|
||||
}
|
||||
|
||||
etag := func() string {
|
||||
tmp := struct {
|
||||
Tmp0 interface{}
|
||||
Tmp1 interface{}
|
||||
}{ files, perms }
|
||||
if j, err := json.Marshal(tmp); err == nil {
|
||||
return Hash(string(j), 20)
|
||||
}
|
||||
return ""
|
||||
}()
|
||||
etag = QuickHash(etag, 20)
|
||||
res.Header().Set("Etag", etag)
|
||||
if etag != "" && req.Header.Get("If-None-Match") == etag {
|
||||
res.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
res.Header().Set("Etag", etag)
|
||||
|
||||
SendSuccessResultsWithMetadata(res, files, perms)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
package ctrl
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/base32"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"fmt"
|
||||
"io"
|
||||
"text/template"
|
||||
"net/http"
|
||||
|
|
@ -12,12 +11,12 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
var ETAGS SafeMapStringString = NewSafeMapStringString()
|
||||
var ETAGS SafeMapStringString = NewSafeMapStringString()
|
||||
|
||||
func StaticHandler(_path string) func(App, http.ResponseWriter, *http.Request) {
|
||||
return func(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
var base string = GetAbsolutePath(_path)
|
||||
var srcPath string
|
||||
base := GetAbsolutePath(_path)
|
||||
if srcPath = JoinPath(base, req.URL.Path); srcPath == base {
|
||||
http.NotFound(res, req)
|
||||
return
|
||||
|
|
@ -93,11 +92,12 @@ func hashFile (path string, n int) string {
|
|||
return ""
|
||||
}
|
||||
defer f.Close()
|
||||
h := md5.New()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return ""
|
||||
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
return "UNKNOWN"
|
||||
}
|
||||
return base32.HexEncoding.EncodeToString(h.Sum(nil))[:n]
|
||||
return QuickHash(fmt.Sprintf("%s %d %d %s", path, stat.Size(), stat.Mode(), stat.ModTime()), n)
|
||||
}
|
||||
|
||||
func ServeFile(res http.ResponseWriter, req *http.Request, filePath string) {
|
||||
|
|
@ -105,7 +105,7 @@ func ServeFile(res http.ResponseWriter, req *http.Request, filePath string) {
|
|||
tags := ETAGS.Gets(filePath, zFilePath)
|
||||
etagNormal := tags[0]
|
||||
etagGzip := tags[1]
|
||||
|
||||
|
||||
if req.Header.Get("If-None-Match") != "" {
|
||||
browserTag := req.Header.Get("If-None-Match")
|
||||
if browserTag == etagNormal {
|
||||
|
|
@ -128,6 +128,7 @@ func ServeFile(res http.ResponseWriter, req *http.Request, filePath string) {
|
|||
head.Set("Etag", etagGzip)
|
||||
}
|
||||
io.Copy(res, file)
|
||||
file.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -145,4 +146,5 @@ func ServeFile(res http.ResponseWriter, req *http.Request, filePath string) {
|
|||
head.Set("Etag", etagNormal)
|
||||
}
|
||||
io.Copy(res, file)
|
||||
file.Close()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ func NewMiddlewareChain(fn func(App, http.ResponseWriter, *http.Request), m []Mi
|
|||
f = m[i](f)
|
||||
}
|
||||
f(app, &resw, req)
|
||||
req.Body.Close()
|
||||
if req.Body != nil {
|
||||
req.Body.Close()
|
||||
}
|
||||
go Logger(app, &resw, req)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue