Selaa lähdekoodia

Fixed websocket upload override quota bug

TC pushbot 5 4 vuotta sitten
vanhempi
commit
8f945dac05
5 muutettua tiedostoa jossa 193 lisäystä ja 58 poistoa
  1. 27 2
      AGI Documentation.md
  2. 25 4
      file_system.go
  3. 54 51
      mod/agi/agi.file.go
  4. 86 0
      mod/filesystem/fssort/fssort.go
  5. 1 1
      web/Photo/embedded/listNearbyImage.js

+ 27 - 2
AGI Documentation.md

@@ -434,8 +434,8 @@ if (!requirelib("filelib")){
 	filelib.deleteFile("user:/Desktop/test.txt"); 						//Delete a file by given path
 	filelib.readdir("user:/Desktop/"); 									//List all subdirectories within this directory
 	filelib.walk("user:/Desktop/"); 									//Recursive scan dir and return all files and folder in subdirs
-	filelib.glob("user:/Desktop/*.jpg");
-	filelib.aglob("user:/Desktop/*.jpg");
+	filelib.glob("user:/Desktop/*.jpg", "smallToLarge");
+	filelib.aglob("user:/Desktop/*.jpg", "user");
 	filelib.filesize("user:/Desktop/test.jpg");
 	filelib.fileExists("user:/Desktop/test.jpg");
 	filelib.isDir("user:/Desktop/NewFolder/");
@@ -445,8 +445,33 @@ if (!requirelib("filelib")){
 	filelib.rname("user:/Deskop"); 										//Get Rootname, return "User"
 ```
 
+##### Special sorting mode for glob and aglob
+
+For glob and aglob, developer can pass in the following sorting modes (case sensitive)
+
+- default
+- reverse
+- smallToLarge
+- largeToSmall
+- mostRecent
+- leastRecent
+
+```
+//Example for sorting the desktop files to largeToSmall
+filelib.aglob("user:/Desktop/*", "largeToSmall");
+```
+
+To use the user default option which user has set in File Manager WebApp, pass in "user". Default sorting method is "default"
+
+```
+//Example of using user's selected mode
+filelib.aglob("user:/Desktop/*.jpg", "user");
+```
+
+
 
 ### imagelib
+
 A basic image handling library to process images. Allowing basic image resize,
 get image dimension and others (to be expanded)
 

+ 25 - 4
file_system.go

@@ -382,6 +382,12 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 	//Start websocket connection
 	var upgrader = websocket.Upgrader{}
 	c, err := upgrader.Upgrade(w, r, nil)
+	if err != nil {
+		log.Println("Failed to upgrade websocket connection: ", err.Error())
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write([]byte("500 WebSocket upgrade failed"))
+		return
+	}
 	defer c.Close()
 
 	//Handle WebSocket upload
@@ -476,7 +482,6 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 		c.Close()
 		return
 	}
-	defer out.Close()
 
 	for _, filesrc := range chunkName {
 		srcChunkReader, err := os.Open(filesrc)
@@ -489,6 +494,22 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 		srcChunkReader.Close()
 	}
 
+	out.Close()
+
+	//Check if the size fit in user quota
+	fi, err := os.Stat(targetUploadLocation)
+	if err != nil {
+		// Could not obtain stat, handle error
+		log.Println("Failed to validate uploaded file: ", targetUploadLocation, ". Error Message: ", err.Error())
+		c.WriteMessage(1, []byte(`{\"error\":\"Failed to validate uploaded file\"}`))
+		return
+	}
+
+	if !userinfo.StorageQuota.HaveSpace(fi.Size()) {
+		c.WriteMessage(1, []byte(`{\"error\":\"User Storage Quota Exceeded\"}`))
+		return
+	}
+
 	//Set owner of the new uploaded file
 	userinfo.SetOwnerOfFile(targetUploadLocation)
 
@@ -499,7 +520,7 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 	done <- true
 
 	//Clear the tmp folder
-	time.Sleep(1 * time.Second)
+	time.Sleep(300 * time.Millisecond)
 	err = os.RemoveAll(uploadFolder)
 	if err != nil {
 		log.Println(err)
@@ -507,7 +528,7 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 
 	//Close WebSocket connection after finished
 	c.WriteControl(8, []byte{}, time.Now().Add(time.Second))
-	time.Sleep(1 * time.Second)
+	time.Sleep(300 * time.Second)
 	c.Close()
 
 }
@@ -585,7 +606,7 @@ func system_fs_handleUpload(w http.ResponseWriter, r *http.Request) {
 	//Check for storage quota
 	uploadFileSize := handler.Size
 	if !userinfo.StorageQuota.HaveSpace(uploadFileSize) {
-		sendErrorResponse(w, "Storage Quota Full")
+		sendErrorResponse(w, "User Storage Quota Exceeded")
 		return
 	}
 

+ 54 - 51
mod/agi/agi.file.go

@@ -6,11 +6,10 @@ import (
 	"log"
 	"os"
 	"path/filepath"
-	"sort"
-	"strings"
 
 	"github.com/robertkrimen/otto"
 	fs "imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/filesystem/fssort"
 	user "imuslab.com/arozos/mod/user"
 )
 
@@ -255,6 +254,8 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 	//Glob
 	//glob("user:/Desktop/*.mp3") => return fileList in array
 	//glob("/") => return a list of root directories
+	//glob("user:/Desktop/*", "mostRecent") => return fileList in mostRecent sorting mode
+	//glob("user:/Desktop/*", "user") => return fileList in array in user prefered sorting method
 	vm.Set("_filelib_glob", func(call otto.FunctionCall) otto.Value {
 		regex, err := call.Argument(0).ToString()
 		if err != nil {
@@ -263,6 +264,11 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 			return reply
 		}
 
+		userSortMode, err := call.Argument(1).ToString()
+		if err != nil || userSortMode == "" || userSortMode == "undefined" {
+			userSortMode = "default"
+		}
+
 		//Handle when regex = "." or "./" (listroot)
 		if filepath.ToSlash(filepath.Clean(regex)) == "/" || filepath.Clean(regex) == "." {
 			//List Root
@@ -282,6 +288,22 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 			//This function can only handle wildcard in filename but not in dir name
 			vrootPath := filepath.Dir(regex)
 			regexFilename := filepath.Base(regex)
+
+			//Rewrite and validate the sort mode
+			if userSortMode == "user" {
+				//Use user sorting mode.
+				if g.Option.UserHandler.GetDatabase().KeyExists("fs-sortpref", u.Username+"/"+filepath.ToSlash(vrootPath)) {
+					g.Option.UserHandler.GetDatabase().Read("fs-sortpref", u.Username+"/"+filepath.ToSlash(vrootPath), &userSortMode)
+				} else {
+					userSortMode = "default"
+				}
+			}
+
+			if !fssort.SortModeIsSupported(userSortMode) {
+				log.Println("[AGI] Sort mode: " + userSortMode + " not supported. Using default")
+				userSortMode = "default"
+			}
+
 			//Translate the virtual path to realpath
 			rrootPath, err := virtualPathToRealPath(vrootPath, u)
 			if err != nil {
@@ -297,8 +319,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 				return reply
 			}
 
+			//Sort the files
+			newFilelist := fssort.SortFileList(suitableFiles, userSortMode)
+
+			//Return the results in virtual paths
 			results := []string{}
-			for _, file := range suitableFiles {
+			for _, file := range newFilelist {
 				thisRpath, _ := realpathToVirtualpath(filepath.ToSlash(file), u)
 				results = append(results, thisRpath)
 			}
@@ -316,7 +342,10 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 			return reply
 		}
 
-		sortMode, _ := call.Argument(1).ToString()
+		userSortMode, err := call.Argument(1).ToString()
+		if err != nil || userSortMode == "" || userSortMode == "undefined" {
+			userSortMode = "default"
+		}
 
 		if regex != "/" && !u.CanRead(regex) {
 			panic(vm.MakeCustomError("PermissionDenied", "Path access denied"))
@@ -325,8 +354,23 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 		//This function can only handle wildcard in filename but not in dir name
 		vrootPath := filepath.Dir(regex)
 		regexFilename := filepath.Base(regex)
-		//Translate the virtual path to realpath
 
+		//Rewrite and validate the sort mode
+		if userSortMode == "user" {
+			//Use user sorting mode.
+			if g.Option.UserHandler.GetDatabase().KeyExists("fs-sortpref", u.Username+"/"+filepath.ToSlash(vrootPath)) {
+				g.Option.UserHandler.GetDatabase().Read("fs-sortpref", u.Username+"/"+filepath.ToSlash(vrootPath), &userSortMode)
+			} else {
+				userSortMode = "default"
+			}
+		}
+
+		if !fssort.SortModeIsSupported(userSortMode) {
+			log.Println("[AGI] Sort mode: " + userSortMode + " not supported. Using default")
+			userSortMode = "default"
+		}
+
+		//Translate the virtual path to realpath
 		rrootPath, err := virtualPathToRealPath(vrootPath, u)
 		if err != nil {
 			g.raiseError(err)
@@ -341,55 +385,14 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 			return reply
 		}
 
-		type SortingFileData struct {
-			Filename string
-			Filepath string
-			Filesize int64
-			ModTime  int64
-		}
-
-		parsedFilelist := []fs.FileData{}
-		for _, file := range suitableFiles {
-			vpath, err := realpathToVirtualpath(filepath.ToSlash(file), u)
-			if err != nil {
-				g.raiseError(err)
-				reply, _ := vm.ToValue(false)
-				return reply
-			}
-			modtime, _ := fs.GetModTime(file)
-			parsedFilelist = append(parsedFilelist, fs.FileData{
-				Filename: filepath.Base(file),
-				Filepath: vpath,
-				Filesize: fs.GetFileSize(file),
-				ModTime:  modtime,
-			})
-		}
-
-		if sortMode != "" {
-			if sortMode == "reverse" || sortMode == "descending" {
-				//Sort by reverse name
-				sort.Slice(parsedFilelist, func(i, j int) bool {
-					return strings.ToLower(parsedFilelist[i].Filename) > strings.ToLower(parsedFilelist[j].Filename)
-				})
-			} else if sortMode == "smallToLarge" {
-				sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].Filesize < parsedFilelist[j].Filesize })
-			} else if sortMode == "largeToSmall" {
-				sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].Filesize > parsedFilelist[j].Filesize })
-			} else if sortMode == "mostRecent" {
-				sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].ModTime > parsedFilelist[j].ModTime })
-			} else if sortMode == "leastRecent" {
-				sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].ModTime < parsedFilelist[j].ModTime })
-			} else {
-				sort.Slice(parsedFilelist, func(i, j int) bool {
-					return strings.ToLower(parsedFilelist[i].Filename) < strings.ToLower(parsedFilelist[j].Filename)
-				})
-			}
-		}
+		//Sort the files
+		newFilelist := fssort.SortFileList(suitableFiles, userSortMode)
 
 		//Parse the results (Only extract the filepath)
 		results := []string{}
-		for _, fileData := range parsedFilelist {
-			results = append(results, fileData.Filepath)
+		for _, filename := range newFilelist {
+			thisVpath, _ := u.RealPathToVirtualPath(filename)
+			results = append(results, thisVpath)
 		}
 
 		reply, _ := vm.ToValue(results)

+ 86 - 0
mod/filesystem/fssort/fssort.go

@@ -0,0 +1,86 @@
+package fssort
+
+import (
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+)
+
+type sortBufferedStructure struct {
+	Filename string
+	Filepath string
+	Filesize int64
+	ModTime  int64
+}
+
+/*
+	Quick utilties to sort file list according to different modes
+*/
+func SortFileList(filelistRealpath []string, sortMode string) []string {
+	//Build a filelist with information based on the given filelist
+	parsedFilelist := []*sortBufferedStructure{}
+	for _, file := range filelistRealpath {
+		thisFileInfo := sortBufferedStructure{
+			Filename: filepath.Base(file),
+			Filepath: file,
+		}
+
+		//Get Filesize
+		fi, err := os.Stat(file)
+		if err != nil {
+			thisFileInfo.Filesize = 0
+		} else {
+			thisFileInfo.Filesize = fi.Size()
+			thisFileInfo.ModTime = fi.ModTime().Unix()
+		}
+
+		parsedFilelist = append(parsedFilelist, &thisFileInfo)
+
+	}
+
+	//Sort the filelist
+	if sortMode == "default" {
+		//Sort by name, convert filename to window sorting methods
+		sort.Slice(parsedFilelist, func(i, j int) bool {
+			return strings.ToLower(parsedFilelist[i].Filename) < strings.ToLower(parsedFilelist[j].Filename)
+		})
+	} else if sortMode == "reverse" {
+		//Sort by reverse name
+		sort.Slice(parsedFilelist, func(i, j int) bool {
+			return strings.ToLower(parsedFilelist[i].Filename) > strings.ToLower(parsedFilelist[j].Filename)
+		})
+	} else if sortMode == "smallToLarge" {
+		sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].Filesize < parsedFilelist[j].Filesize })
+	} else if sortMode == "largeToSmall" {
+		sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].Filesize > parsedFilelist[j].Filesize })
+	} else if sortMode == "mostRecent" {
+		sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].ModTime > parsedFilelist[j].ModTime })
+	} else if sortMode == "leastRecent" {
+		sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].ModTime < parsedFilelist[j].ModTime })
+	}
+
+	results := []string{}
+	for _, sortedFile := range parsedFilelist {
+		results = append(results, sortedFile.Filepath)
+	}
+
+	return results
+}
+
+func SortModeIsSupported(sortMode string) bool {
+	if !contains(sortMode, []string{"default", "reverse", "smallToLarge", "largeToSmall", "mostRecent", "leastRecent"}) {
+		return false
+	}
+	return true
+}
+
+func contains(item string, slice []string) bool {
+	set := make(map[string]struct{}, len(slice))
+	for _, s := range slice {
+		set[s] = struct{}{}
+	}
+
+	_, ok := set[item]
+	return ok
+}

+ 1 - 1
web/Photo/embedded/listNearbyImage.js

@@ -12,7 +12,7 @@ function listNearby(){
     dirpath = dirpath.join("/");
 
     //Get nearby files and filter out the one that is web supported photo format
-    var nearbyFiles = filelib.aglob(dirpath + "/*")
+    var nearbyFiles = filelib.aglob(dirpath + "/*", "user")
     for (var i = 0; i < nearbyFiles.length; i++){
         var ext = nearbyFiles[i].split(".").pop();
         ext = ext.toLowerCase();