Sfoglia il codice sorgente

Fixed linux build error on template_apply deprecated func

Toby Chui 1 anno fa
parent
commit
d91f5b714a

+ 21 - 16
mod/agi/agi.appdata.go

@@ -4,13 +4,12 @@ import (
 	"encoding/json"
 	"errors"
 	"log"
-	"net/http"
 	"os"
 	"path/filepath"
 
 	"github.com/robertkrimen/otto"
+	"imuslab.com/arozos/mod/agi/static"
 	"imuslab.com/arozos/mod/filesystem"
-	user "imuslab.com/arozos/mod/user"
 	"imuslab.com/arozos/mod/utils"
 )
 
@@ -33,23 +32,29 @@ func (g *Gateway) AppdataLibRegister() {
 	}
 }
 
-func (g *Gateway) injectAppdataLibFunctions(vm *otto.Otto, u *user.User, scriptFsh *filesystem.FileSystemHandler, scriptPath string, w http.ResponseWriter, r *http.Request) {
+func (g *Gateway) injectAppdataLibFunctions(payload *static.AgiLibInjectionPayload) {
+	vm := payload.VM
+	//u := payload.User
+	//scriptFsh := payload.ScriptFsh
+	//scriptPath := payload.ScriptPath
+	//w := payload.Writer
+	//r := payload.Request
 	vm.Set("_appdata_readfile", func(call otto.FunctionCall) otto.Value {
 		relpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Check if this is path escape
-		escaped, err := checkRootEscape(webRoot, filepath.Join(webRoot, relpath))
+		escaped, err := static.CheckRootEscape(webRoot, filepath.Join(webRoot, relpath))
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		if escaped {
-			g.raiseError(errors.New("Path escape detected"))
+			g.RaiseError(errors.New("Path escape detected"))
 			return otto.FalseValue()
 		}
 
@@ -58,7 +63,7 @@ func (g *Gateway) injectAppdataLibFunctions(vm *otto.Otto, u *user.User, scriptF
 		if utils.FileExists(targetFile) && !filesystem.IsDir(targetFile) {
 			content, err := os.ReadFile(targetFile)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
@@ -66,11 +71,11 @@ func (g *Gateway) injectAppdataLibFunctions(vm *otto.Otto, u *user.User, scriptF
 			result, _ := vm.ToValue(string(content))
 			return result
 		} else if filesystem.IsDir(targetFile) {
-			g.raiseError(errors.New("Cannot read from directory"))
+			g.RaiseError(errors.New("Cannot read from directory"))
 			return otto.FalseValue()
 
 		} else {
-			g.raiseError(errors.New("File not exists"))
+			g.RaiseError(errors.New("File not exists"))
 			return otto.FalseValue()
 		}
 	})
@@ -78,19 +83,19 @@ func (g *Gateway) injectAppdataLibFunctions(vm *otto.Otto, u *user.User, scriptF
 	vm.Set("_appdata_listdir", func(call otto.FunctionCall) otto.Value {
 		relpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Check if this is path escape
-		escaped, err := checkRootEscape(webRoot, filepath.Join(webRoot, relpath))
+		escaped, err := static.CheckRootEscape(webRoot, filepath.Join(webRoot, relpath))
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		if escaped {
-			g.raiseError(errors.New("Path escape detected"))
+			g.RaiseError(errors.New("Path escape detected"))
 			return otto.FalseValue()
 		}
 
@@ -100,7 +105,7 @@ func (g *Gateway) injectAppdataLibFunctions(vm *otto.Otto, u *user.User, scriptF
 			//Glob the directory for filelist
 			files, err := filepath.Glob(filepath.ToSlash(filepath.Clean(targetFolder)) + "/*")
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
@@ -118,7 +123,7 @@ func (g *Gateway) injectAppdataLibFunctions(vm *otto.Otto, u *user.User, scriptF
 			return result
 
 		} else {
-			g.raiseError(errors.New("Directory not exists"))
+			g.RaiseError(errors.New("Directory not exists"))
 			return otto.FalseValue()
 		}
 	})

+ 8 - 5
mod/agi/agi.audio.go

@@ -2,11 +2,8 @@ package agi
 
 import (
 	"log"
-	"net/http"
 
-	"github.com/robertkrimen/otto"
-	"imuslab.com/arozos/mod/filesystem"
-	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/agi/static"
 )
 
 /*
@@ -26,6 +23,12 @@ func (g *Gateway) AudioLibRegister() {
 	}
 }
 
-func (g *Gateway) injectAudioFunctions(vm *otto.Otto, u *user.User, scriptFsh *filesystem.FileSystemHandler, scriptPath string, w http.ResponseWriter, r *http.Request) {
+func (g *Gateway) injectAudioFunctions(payload *static.AgiLibInjectionPayload) {
+	//vm := payload.VM
+	//u := payload.User
+	//scriptFsh := payload.ScriptFsh
+	//scriptPath := payload.ScriptPath
+	//w := payload.Writer
+	//r := payload.Request
 
 }

+ 160 - 0
mod/agi/agi.ffmpeg.go

@@ -0,0 +1,160 @@
+package agi
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+
+	"github.com/robertkrimen/otto"
+	"imuslab.com/arozos/mod/agi/static"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	AJGI FFmpeg adaptor Library
+
+	This is a library for allow the use of ffmpeg via the arozos virtualized layer
+	without the danger of directly accessing the bash / shell interface.
+
+	Author: tobychui
+
+*/
+
+func (g *Gateway) FFmpegLibRegister() {
+	err := g.RegisterLib("ffmpeg", g.injectFFmpegFunctions)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+/*
+	FFmepg functions
+*/
+
+func ffmpeg_conv(input string, output string, compression int) error {
+	var cmd *exec.Cmd
+
+	switch {
+	case isVideo(input) && isVideo(output):
+		// Video to video with resolution compression
+		cmd = exec.Command("ffmpeg", "-i", input, "-vf", fmt.Sprintf("scale=-1:%d", compression), output)
+
+	case (isAudio(input) || isVideo(input)) && isAudio(output):
+		// Audio or video to audio with bitrate compression
+		cmd = exec.Command("ffmpeg", "-i", input, "-b:a", fmt.Sprintf("%dk", compression), output)
+
+	case isImage(output):
+		// Resize image with width compression
+		cmd = exec.Command("ffmpeg", "-i", input, "-vf", fmt.Sprintf("scale=%d:-1", compression), output)
+
+	default:
+		// Handle other cases or leave it for the user to implement
+		return fmt.Errorf("unsupported conversion: %s to %s", input, output)
+	}
+
+	// Set the output of the command to os.Stdout so you can see it in your console
+	cmd.Stdout = os.Stdout
+
+	// Set the output of the command to os.Stderr so you can see any errors
+	cmd.Stderr = os.Stderr
+
+	// Run the command
+	err := cmd.Run()
+	if err != nil {
+		return fmt.Errorf("error running ffmpeg command: %v", err)
+	}
+
+	return nil
+}
+
+// Helper functions to check file types
+func isVideo(filename string) bool {
+	videoFormats := []string{
+		".mp4", ".mkv", ".avi", ".mov", ".flv", ".webm",
+	}
+	return utils.StringInArray(videoFormats, filepath.Ext(filename))
+}
+
+func isAudio(filename string) bool {
+	audioFormats := []string{
+		".mp3", ".wav", ".aac", ".ogg", ".flac",
+	}
+	return utils.StringInArray(audioFormats, filepath.Ext(filename))
+}
+
+func isImage(filename string) bool {
+	imageFormats := []string{
+		".jpg", ".png", ".gif", ".bmp", ".tiff", ".webp",
+	}
+	return utils.StringInArray(imageFormats, filepath.Ext(filename))
+}
+
+func main() {
+	// Example usage
+	err := ffmpeg_conv("input.mp4", "output.mp4", 720)
+	if err != nil {
+		fmt.Println("Error:", err)
+	}
+}
+
+func (g *Gateway) injectFFmpegFunctions(payload *static.AgiLibInjectionPayload) {
+	vm := payload.VM
+	u := payload.User
+	scriptFsh := payload.ScriptFsh
+	//scriptPath := payload.ScriptPath
+	//w := payload.Writer
+	//r := payload.Request
+	vm.Set("_ffmpeg_conv", func(call otto.FunctionCall) otto.Value {
+		//Get the input and output filepath
+		vinput, err := call.Argument(0).ToString()
+		if err != nil {
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+
+		voutput, err := call.Argument(1).ToString()
+		if err != nil {
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+
+		if voutput == "" {
+			//Output filename not provided. Not sure what format to convert
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+
+		//Rewrite the vpath if it is relative
+		vinput = static.RelativeVpathRewrite(scriptFsh, vinput, vm, u)
+		voutput = static.RelativeVpathRewrite(scriptFsh, voutput, vm, u)
+
+		//Translate the virtual path to realpath for the input file
+		fsh, rinput, err := static.VirtualPathToRealPath(vinput, u)
+		if err != nil {
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+
+		//Translate the virtual path to realpath for the output file
+		fsh, routput, err := static.VirtualPathToRealPath(voutput, u)
+		if err != nil {
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+
+		//Buffer the file to tmp
+		//Note that even for local disk, it still need to be buffered to make sure
+		//permission is in-scope as well as to avoid locking a file by child-process
+		bufferedFilepath, err := fsh.BufferRemoteToLocal(rinput)
+		if err != nil {
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+
+		fmt.Println(rinput, routput, bufferedFilepath)
+
+		return otto.TrueValue()
+	})
+}

+ 85 - 79
mod/agi/agi.file.go

@@ -8,15 +8,14 @@ import (
 	"io"
 	"io/fs"
 	"log"
-	"net/http"
 	"os"
 	"path/filepath"
 
 	"github.com/robertkrimen/otto"
-	"imuslab.com/arozos/mod/filesystem"
+
+	"imuslab.com/arozos/mod/agi/static"
 	"imuslab.com/arozos/mod/filesystem/fssort"
 	"imuslab.com/arozos/mod/filesystem/hidden"
-	user "imuslab.com/arozos/mod/user"
 )
 
 /*
@@ -35,17 +34,24 @@ func (g *Gateway) FileLibRegister() {
 	}
 }
 
-func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh *filesystem.FileSystemHandler, scriptPath string, w http.ResponseWriter, r *http.Request) {
+func (g *Gateway) injectFileLibFunctions(payload *static.AgiLibInjectionPayload) {
+	vm := payload.VM
+	u := payload.User
+	scriptFsh := payload.ScriptFsh
+	//scriptPath := payload.ScriptPath
+	//w := payload.Writer
+	//r := payload.Request
+
 	//writeFile(virtualFilepath, content) => return true/false when succeed / failed
 	vm.Set("_filelib_writeFile", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Check for permission
 		if !u.CanWrite(vpath) {
@@ -54,21 +60,21 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 
 		content, err := call.Argument(1).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Check if there is quota for the given length
 		if !u.StorageQuota.HaveSpace(int64(len(content))) {
 			//User have no remaining storage quota
-			g.raiseError(errors.New("Storage Quota Fulled"))
+			g.RaiseError(errors.New("Storage Quota Fulled"))
 			return otto.FalseValue()
 		}
 
 		//Translate the virtual path to realpath
-		fsh, rpath, err := virtualPathToRealPath(vpath, u)
+		fsh, rpath, err := static.VirtualPathToRealPath(vpath, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -85,7 +91,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		//Create and write to file using ioutil
 		err = fsh.FileSystemAbstraction.WriteFile(rpath, []byte(content), 0755)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -99,12 +105,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_deleteFile", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Check for permission
 		if !u.CanWrite(vpath) {
@@ -112,9 +118,9 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		}
 
 		//Translate the virtual path to realpath
-		fsh, rpath, err := virtualPathToRealPath(vpath, u)
+		fsh, rpath, err := static.VirtualPathToRealPath(vpath, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -127,7 +133,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 				u.RemoveOwnershipFromFile(fsh, vpath)
 			}
 		} else {
-			g.raiseError(errors.New("File not exists"))
+			g.RaiseError(errors.New("File not exists"))
 			return otto.FalseValue()
 		}
 
@@ -142,12 +148,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_readFile", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Check for permission
 		if !u.CanRead(vpath) {
@@ -155,16 +161,16 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		}
 
 		//Translate the virtual path to realpath
-		fsh, rpath, err := virtualPathToRealPath(vpath, u)
+		fsh, rpath, err := static.VirtualPathToRealPath(vpath, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Create and write to file using ioUtil
 		content, err := fsh.FileSystemAbstraction.ReadFile(rpath)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		reply, _ := vm.ToValue(string(content))
@@ -178,7 +184,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_walk", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		mode, err := call.Argument(1).ToString()
@@ -187,11 +193,11 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
-		fsh, rpath, err := virtualPathToRealPath(vpath, u)
+		fsh, rpath, err := static.VirtualPathToRealPath(vpath, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		results := []string{}
@@ -200,7 +206,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 				//Ignore this error file and continue
 				return nil
 			}
-			thisVpath, err := realpathToVirtualpath(fsh, path, u)
+			thisVpath, err := static.RealpathToVirtualpath(fsh, path, u)
 			if err != nil {
 				return nil
 			}
@@ -231,7 +237,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_glob", func(call otto.FunctionCall) otto.Value {
 		regex, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -280,15 +286,15 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 			}
 
 			//Translate the virtual path to realpath
-			fsh, rrootPath, err := virtualPathToRealPath(vrootPath, u)
+			fsh, rrootPath, err := static.VirtualPathToRealPath(vrootPath, u)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
 			suitableFiles, err := fsh.FileSystemAbstraction.Glob(filepath.Join(rrootPath, regexFilename))
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
@@ -313,7 +319,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 					//Hidden file. Skip this
 					continue
 				}
-				thisVpath, _ := realpathToVirtualpath(fsh, file, u)
+				thisVpath, _ := static.RealpathToVirtualpath(fsh, file, u)
 				results = append(results, thisVpath)
 			}
 			reply, _ := vm.ToValue(results)
@@ -325,7 +331,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_aglob", func(call otto.FunctionCall) otto.Value {
 		regex, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -360,14 +366,14 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		//Translate the virtual path to realpath
 		fsh, err := u.GetFileSystemHandlerFromVirtualPath(vrootPath)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		fshAbs := fsh.FileSystemAbstraction
 		rrootPath, _ := fshAbs.VirtualPathToRealPath(vrootPath, u.Username)
 		suitableFiles, err := fshAbs.Glob(filepath.Join(rrootPath, regexFilename))
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -392,7 +398,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 				//Hidden file. Skip this
 				continue
 			}
-			thisVpath, _ := realpathToVirtualpath(fsh, filename, u)
+			thisVpath, _ := static.RealpathToVirtualpath(fsh, filename, u)
 			results = append(results, thisVpath)
 		}
 		reply, _ := vm.ToValue(results)
@@ -402,12 +408,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_readdir", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Check for permission
 		if !u.CanRead(vpath) {
@@ -436,19 +442,19 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 
 		fsh, err := u.GetFileSystemHandlerFromVirtualPath(vpath)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		fshAbs := fsh.FileSystemAbstraction
 		rpath, err := fshAbs.VirtualPathToRealPath(vpath, u.Username)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		dirEntry, err := fshAbs.ReadDir(rpath)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -475,7 +481,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 				continue
 			}
 			fstat, _ := de.Info()
-			vpath, _ := realpathToVirtualpath(fsh, filepath.ToSlash(filepath.Join(rpath, de.Name())), u)
+			vpath, _ := static.RealpathToVirtualpath(fsh, filepath.ToSlash(filepath.Join(rpath, de.Name())), u)
 
 			thisInfo := fileInfo{
 				Filename: de.Name(),
@@ -498,12 +504,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_filesize", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Check for permission
 		if !u.CanRead(vpath) {
@@ -512,20 +518,20 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 
 		fsh, err := u.GetFileSystemHandlerFromVirtualPath(vpath)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		fshAbs := fsh.FileSystemAbstraction
 		rpath, err := fshAbs.VirtualPathToRealPath(vpath, u.Username)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Get filesize of file
 		rawsize := fshAbs.GetFileSize(rpath)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -537,12 +543,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_fileExists", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Check for permission
 		if !u.CanRead(vpath) {
@@ -551,13 +557,13 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 
 		fsh, err := u.GetFileSystemHandlerFromVirtualPath(vpath)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		fshAbs := fsh.FileSystemAbstraction
 		rpath, err := fshAbs.VirtualPathToRealPath(vpath, u.Username)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -572,12 +578,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_isDir", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Check for permission
 		if !u.CanRead(vpath) {
@@ -585,9 +591,9 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		}
 
 		//Translate the virtual path to realpath
-		fsh, rpath, err := virtualPathToRealPath(vpath, u)
+		fsh, rpath, err := static.VirtualPathToRealPath(vpath, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -616,7 +622,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		}
 
 		//Translate the path to realpath
-		fsh, rdir, err := virtualPathToRealPath(vdir, u)
+		fsh, rdir, err := static.VirtualPathToRealPath(vdir, u)
 		if err != nil {
 			log.Println(err.Error())
 			return otto.FalseValue()
@@ -636,12 +642,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_md5", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Check for permission
 		if !u.CanRead(vpath) {
@@ -650,26 +656,26 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 
 		fsh, err := u.GetFileSystemHandlerFromVirtualPath(vpath)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		fshAbs := fsh.FileSystemAbstraction
 		rpath, err := fshAbs.VirtualPathToRealPath(vpath, u.Username)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		f, err := fshAbs.ReadStream(rpath)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		defer f.Close()
 		h := md5.New()
 		if _, err := io.Copy(h, f); err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -683,17 +689,17 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		//Get virtual path from the function input
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Get fs handler from the vpath
 		fsHandler, err := u.GetFileSystemHandlerFromVirtualPath(vpath)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -706,12 +712,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_mtime", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Check for permission
 		if !u.CanRead(vpath) {
@@ -723,7 +729,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 			parseToUnix = false
 		}
 
-		fsh, rpath, err := virtualPathToRealPath(vpath, u)
+		fsh, rpath, err := static.VirtualPathToRealPath(vpath, u)
 		if err != nil {
 			log.Println(err.Error())
 			return otto.FalseValue()
@@ -752,12 +758,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_writeBinaryFile", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Check for permission
 		if !u.CanWrite(vpath) {
@@ -766,12 +772,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 
 		hexContent, err := call.Argument(1).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Get the target vpath
-		fsh, rpath, err := virtualPathToRealPath(vpath, u)
+		fsh, rpath, err := static.VirtualPathToRealPath(vpath, u)
 		if err != nil {
 			log.Println(err.Error())
 			return otto.FalseValue()
@@ -780,14 +786,14 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		//Decode the hex content to bytes
 		hexContentInByte, err := hex.DecodeString(hexContent)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Write the file to target file
 		err = fsh.FileSystemAbstraction.WriteFile(rpath, hexContentInByte, 0775)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -799,12 +805,12 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_filelib_readBinaryFile", func(call otto.FunctionCall) otto.Value {
 		vpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.NullValue()
 		}
 
 		//Rewrite the vpath if it is relative
-		vpath = relativeVpathRewrite(scriptFsh, vpath, vm, u)
+		vpath = static.RelativeVpathRewrite(scriptFsh, vpath, vm, u)
 
 		//Check for permission
 		if !u.CanRead(vpath) {
@@ -812,21 +818,21 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		}
 
 		//Get the target vpath
-		fsh, rpath, err := virtualPathToRealPath(vpath, u)
+		fsh, rpath, err := static.VirtualPathToRealPath(vpath, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.NullValue()
 		}
 
 		if !fsh.FileSystemAbstraction.FileExists(rpath) {
 			//Check if the target file exists
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.NullValue()
 		}
 
 		content, err := fsh.FileSystemAbstraction.ReadFile(rpath)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.NullValue()
 		}
 

+ 10 - 27
mod/agi/agi.go

@@ -14,6 +14,7 @@ import (
 	"github.com/robertkrimen/otto"
 	uuid "github.com/satori/go.uuid"
 
+	"imuslab.com/arozos/mod/agi/static"
 	apt "imuslab.com/arozos/mod/apt"
 	"imuslab.com/arozos/mod/filesystem"
 	metadata "imuslab.com/arozos/mod/filesystem/metadata"
@@ -33,15 +34,13 @@ import (
 */
 
 var (
-	AgiVersion string = "2.3" //Defination of the agi runtime version. Update this when new function is added
+	AgiVersion string = "3.0" //Defination of the agi runtime version. Update this when new function is added
 
 	//AGI Internal Error Standard
 	errExitcall = errors.New("errExit")
 	errTimeout  = errors.New("errTimeout")
 )
 
-// Lib interface, require vm, user, target system file handler and the vpath of the running script
-type AgiLibIntergface func(*otto.Otto, *user.User, *filesystem.FileSystemHandler, string, http.ResponseWriter, *http.Request) //Define the lib loader interface for AGI Libraries
 type AgiPackage struct {
 	InitRoot string //The initialization of the root for the module that request this package
 }
@@ -72,7 +71,7 @@ type Gateway struct {
 	ReservedTables   []string
 	NightlyScripts   []string
 	AllowAccessPkgs  map[string][]AgiPackage
-	LoadedAGILibrary map[string]AgiLibIntergface
+	LoadedAGILibrary map[string]AgiLibInjectionIntergface
 	Option           *AgiSysInfo
 }
 
@@ -82,7 +81,7 @@ func NewGateway(option AgiSysInfo) (*Gateway, error) {
 		ReservedTables:   option.ReservedTables,
 		NightlyScripts:   []string{},
 		AllowAccessPkgs:  map[string][]AgiPackage{},
-		LoadedAGILibrary: map[string]AgiLibIntergface{},
+		LoadedAGILibrary: map[string]AgiLibInjectionIntergface{},
 		Option:           &option,
 	}
 
@@ -91,12 +90,7 @@ func NewGateway(option AgiSysInfo) (*Gateway, error) {
 	gatewayObject.RegisterNightlyOperations()
 
 	//Load all the other libs entry points into the memoary
-	gatewayObject.ImageLibRegister()
-	gatewayObject.FileLibRegister()
-	gatewayObject.HTTPLibRegister()
-	gatewayObject.ShareLibRegister()
-	gatewayObject.IoTLibRegister()
-	gatewayObject.AppdataLibRegister()
+	gatewayObject.LoadAllFunctionalModules()
 
 	return &gatewayObject, nil
 }
@@ -105,7 +99,7 @@ func (g *Gateway) RegisterNightlyOperations() {
 	g.Option.NightlyManager.RegisterNightlyTask(func() {
 		//This function will execute nightly
 		for _, scriptFile := range g.NightlyScripts {
-			if isValidAGIScript(scriptFile) {
+			if static.IsValidAGIScript(scriptFile) {
 				//Valid script file. Execute it with system
 				for _, username := range g.Option.UserHandler.GetAuthAgent().ListUsers() {
 					userinfo, err := g.Option.UserHandler.GetUserInfoFromUsername(username)
@@ -113,7 +107,7 @@ func (g *Gateway) RegisterNightlyOperations() {
 						continue
 					}
 
-					if checkUserAccessToScript(userinfo, scriptFile, "") {
+					if static.CheckUserAccessToScript(userinfo, scriptFile, "") {
 						//This user can access the module that provide this script.
 						//Execute this script on his account.
 						log.Println("[AGI_Nightly] WIP (" + scriptFile + ")")
@@ -164,18 +158,7 @@ func (g *Gateway) RunScript(script string) error {
 	return nil
 }
 
-func (g *Gateway) RegisterLib(libname string, entryPoint AgiLibIntergface) error {
-	_, ok := g.LoadedAGILibrary[libname]
-	if ok {
-		//This lib already registered. Return error
-		return errors.New("This library name already registered")
-	} else {
-		g.LoadedAGILibrary[libname] = entryPoint
-	}
-	return nil
-}
-
-func (g *Gateway) raiseError(err error) {
+func (g *Gateway) RaiseError(err error) {
 	log.Println("[AGI] Runtime Error " + err.Error())
 
 	//To be implemented
@@ -221,7 +204,7 @@ func (g *Gateway) InterfaceHandler(w http.ResponseWriter, r *http.Request, thisu
 		utils.SendErrorResponse(w, "Invalid script path")
 		return
 	}
-	scriptFile = specialURIDecode(scriptFile)
+	scriptFile = static.SpecialURIDecode(scriptFile)
 
 	//Check if the script path exists
 	scriptExists := false
@@ -241,7 +224,7 @@ func (g *Gateway) InterfaceHandler(w http.ResponseWriter, r *http.Request, thisu
 	}
 
 	//Check for user permission on this module
-	moduleName := getScriptRoot(scriptFile, scriptScope)
+	moduleName := static.GetScriptRoot(scriptFile, scriptScope)
 	if !thisuser.GetModuleAccessPermission(moduleName) {
 		w.WriteHeader(http.StatusForbidden)
 		if g.Option.BuildVersion == "development" {

+ 12 - 7
mod/agi/agi.http.go

@@ -12,8 +12,7 @@ import (
 	"path/filepath"
 
 	"github.com/robertkrimen/otto"
-	"imuslab.com/arozos/mod/filesystem"
-	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/agi/static"
 )
 
 /*
@@ -32,7 +31,13 @@ func (g *Gateway) HTTPLibRegister() {
 	}
 }
 
-func (g *Gateway) injectHTTPFunctions(vm *otto.Otto, u *user.User, scriptFsh *filesystem.FileSystemHandler, scriptPath string, w http.ResponseWriter, r *http.Request) {
+func (g *Gateway) injectHTTPFunctions(payload *static.AgiLibInjectionPayload) {
+	vm := payload.VM
+	u := payload.User
+	//scriptFsh := payload.ScriptFsh
+	//scriptPath := payload.ScriptPath
+	w := payload.Writer
+	//r := payload.Request
 	vm.Set("_http_get", func(call otto.FunctionCall) otto.Value {
 		//Get URL from function variable
 		url, err := call.Argument(0).ToString()
@@ -143,7 +148,7 @@ func (g *Gateway) injectHTTPFunctions(vm *otto.Otto, u *user.User, scriptFsh *fi
 
 		req, err := http.NewRequest("GET", url, nil)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -190,18 +195,18 @@ func (g *Gateway) injectHTTPFunctions(vm *otto.Otto, u *user.User, scriptFsh *fi
 
 		//Check user acess permission
 		if !u.CanWrite(vpath) {
-			g.raiseError(errors.New("Permission Denied"))
+			g.RaiseError(errors.New("Permission Denied"))
 			return otto.FalseValue()
 		}
 
 		//Convert the vpath to realpath. Check if it exists
-		fsh, rpath, err := virtualPathToRealPath(vpath, u)
+		fsh, rpath, err := static.VirtualPathToRealPath(vpath, u)
 		if err != nil {
 			return otto.FalseValue()
 		}
 
 		if !fsh.FileSystemAbstraction.FileExists(rpath) || !fsh.FileSystemAbstraction.IsDir(rpath) {
-			g.raiseError(errors.New(vpath + " is a file not a directory."))
+			g.RaiseError(errors.New(vpath + " is a file not a directory."))
 			return otto.FalseValue()
 		}
 

+ 59 - 55
mod/agi/agi.image.go

@@ -10,7 +10,6 @@ import (
 	"image/png"
 	_ "image/png"
 	"log"
-	"net/http"
 	"os"
 	"path/filepath"
 	"strings"
@@ -19,10 +18,9 @@ import (
 	"github.com/oliamb/cutter"
 	"github.com/robertkrimen/otto"
 
-	"imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/agi/static"
 	"imuslab.com/arozos/mod/filesystem/arozfs"
 	"imuslab.com/arozos/mod/neuralnet"
-	user "imuslab.com/arozos/mod/user"
 	"imuslab.com/arozos/mod/utils"
 )
 
@@ -40,23 +38,29 @@ func (g *Gateway) ImageLibRegister() {
 	}
 }
 
-func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh *filesystem.FileSystemHandler, scriptPath string, w http.ResponseWriter, r *http.Request) {
+func (g *Gateway) injectImageLibFunctions(payload *static.AgiLibInjectionPayload) {
+	vm := payload.VM
+	u := payload.User
+	//scriptFsh := payload.ScriptFsh
+	//scriptPath := payload.ScriptPath
+	//w := payload.Writer
+	//r := payload.Request
 	//Get image dimension, requires filepath (virtual)
 	vm.Set("_imagelib_getImageDimension", func(call otto.FunctionCall) otto.Value {
 		imageFileVpath, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
-		fsh, imagePath, err := virtualPathToRealPath(imageFileVpath, u)
+		fsh, imagePath, err := static.VirtualPathToRealPath(imageFileVpath, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		if !fsh.FileSystemAbstraction.FileExists(imagePath) {
-			g.raiseError(errors.New("File not exists! Given " + imagePath))
+			g.RaiseError(errors.New("File not exists! Given " + imagePath))
 			return otto.FalseValue()
 		}
 
@@ -69,7 +73,7 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 			defer closerFunc()
 			c, err := fsh.FileSystemAbstraction.ReadFile(imagePath)
 			if err != nil {
-				g.raiseError(errors.New("Read from file system failed: " + err.Error()))
+				g.RaiseError(errors.New("Read from file system failed: " + err.Error()))
 				return otto.FalseValue()
 			}
 			os.WriteFile(bufferPath, c, 0775)
@@ -77,20 +81,20 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 
 			file, err = os.Open(openingPath)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 		} else {
 			file, err = fsh.FileSystemAbstraction.Open(openingPath)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 		}
 
 		image, _, err := image.DecodeConfig(file)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		file.Close()
@@ -103,50 +107,50 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_imagelib_resizeImage", func(call otto.FunctionCall) otto.Value {
 		vsrc, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		vdest, err := call.Argument(1).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		width, err := call.Argument(2).ToInteger()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		height, err := call.Argument(3).ToInteger()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		//Convert the virtual paths to real paths
-		srcfsh, rsrc, err := virtualPathToRealPath(vsrc, u)
+		srcfsh, rsrc, err := static.VirtualPathToRealPath(vsrc, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
-		destfsh, rdest, err := virtualPathToRealPath(vdest, u)
+		destfsh, rdest, err := static.VirtualPathToRealPath(vdest, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		ext := strings.ToLower(filepath.Ext(rdest))
 		if !utils.StringInArray([]string{".jpg", ".jpeg", ".png"}, ext) {
-			g.raiseError(errors.New("File extension not supported. Only support .jpg and .png"))
+			g.RaiseError(errors.New("File extension not supported. Only support .jpg and .png"))
 			return otto.FalseValue()
 		}
 
 		if destfsh.FileSystemAbstraction.FileExists(rdest) {
 			err := destfsh.FileSystemAbstraction.Remove(rdest)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 		}
@@ -158,19 +162,19 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		if srcfsh.RequireBuffer {
 			resizeOpeningFile, _, err = g.bufferRemoteResourcesToLocal(srcfsh, u, rsrc)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
 			srcFile, err = os.Open(resizeOpeningFile)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 		} else {
 			srcFile, err = srcfsh.FileSystemAbstraction.Open(resizeOpeningFile)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 		}
@@ -179,19 +183,19 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		if destfsh.RequireBuffer {
 			resizeWritingFile, _, err = g.bufferRemoteResourcesToLocal(destfsh, u, rdest)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
 			destFile, err = os.OpenFile(resizeWritingFile, os.O_CREATE|os.O_WRONLY, 0775)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 		} else {
 			destFile, err = destfsh.FileSystemAbstraction.OpenFile(resizeWritingFile, os.O_CREATE|os.O_WRONLY, 0775)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 		}
@@ -202,20 +206,20 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		src, err := imaging.Decode(srcFile)
 		if err != nil {
 			//Opening failed
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		src = imaging.Resize(src, int(width), int(height), imaging.Lanczos)
 		//err = imaging.Save(src, resizeWritingFile)
 		f, err := imaging.FormatFromFilename(resizeWritingFile)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		err = imaging.Encode(destFile, src, f)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -231,13 +235,13 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_imagelib_cropImage", func(call otto.FunctionCall) otto.Value {
 		vsrc, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		vdest, err := call.Argument(1).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -253,27 +257,27 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 
 		width, err := call.Argument(4).ToInteger()
 		if err != nil {
-			g.raiseError(errors.New("Image width not defined"))
+			g.RaiseError(errors.New("Image width not defined"))
 			return otto.FalseValue()
 		}
 
 		height, err := call.Argument(5).ToInteger()
 		if err != nil {
-			g.raiseError(errors.New("Image height not defined"))
+			g.RaiseError(errors.New("Image height not defined"))
 			return otto.FalseValue()
 		}
 
 		//Convert the virtual paths to realpaths
 
-		srcFsh, rsrc, err := virtualPathToRealPath(vsrc, u)
+		srcFsh, rsrc, err := static.VirtualPathToRealPath(vsrc, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		srcFshAbs := srcFsh.FileSystemAbstraction
-		destFsh, rdest, err := virtualPathToRealPath(vdest, u)
+		destFsh, rdest, err := static.VirtualPathToRealPath(vdest, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -281,13 +285,13 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		imageBytes, err := srcFshAbs.ReadFile(rsrc)
 		if err != nil {
 			fmt.Println(err)
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		img, _, err := image.Decode(bytes.NewReader(imageBytes))
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -308,7 +312,7 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 			//Create the new image in buffer file
 			out, err = os.Create(destWritePath)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 			defer out.Close()
@@ -317,7 +321,7 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 			//Create the target file via FSA
 			out, err = destFsh.FileSystemAbstraction.Create(rdest)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 			defer out.Close()
@@ -328,7 +332,7 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		} else if strings.ToLower(filepath.Ext(rdest)) == ".jpg" {
 			jpeg.Encode(out, croppedImg, nil)
 		} else {
-			g.raiseError(errors.New("Not supported format: Only support jpg or png"))
+			g.RaiseError(errors.New("Not supported format: Only support jpg or png"))
 			return otto.FalseValue()
 		}
 		out.Close()
@@ -348,13 +352,13 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_imagelib_loadThumbString", func(call otto.FunctionCall) otto.Value {
 		vsrc, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
 		fsh, err := u.GetFileSystemHandlerFromVirtualPath(vsrc)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		rpath, _ := fsh.FileSystemAbstraction.VirtualPathToRealPath(vsrc, u.Username)
@@ -372,7 +376,7 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 	vm.Set("_imagelib_classify", func(call otto.FunctionCall) otto.Value {
 		vsrc, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -386,9 +390,9 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		}
 
 		//Convert the vsrc to real path
-		fsh, rsrc, err := virtualPathToRealPath(vsrc, u)
+		fsh, rsrc, err := static.VirtualPathToRealPath(vsrc, u)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -397,7 +401,7 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		if fsh.RequireBuffer {
 			analysisSrc, closerFunc, err = g.bufferRemoteResourcesToLocal(fsh, u, rsrc)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 			defer closerFunc()
@@ -407,13 +411,13 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 			//Use darknet19 for classification
 			r, err := neuralnet.AnalysisPhotoDarknet19(analysisSrc)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
 			result, err := vm.ToValue(r)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
@@ -423,13 +427,13 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 			//Use yolo3 for classification, return positions of object as well
 			r, err := neuralnet.AnalysisPhotoYOLO3(analysisSrc)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
 			result, err := vm.ToValue(r)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
@@ -438,7 +442,7 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		} else {
 			//Unsupported classifier
 			log.Println("[AGI] Unsupported image classifier name: " + classifier)
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 

+ 8 - 4
mod/agi/agi.iot.go

@@ -3,12 +3,10 @@ package agi
 import (
 	"encoding/json"
 	"log"
-	"net/http"
 
 	"github.com/robertkrimen/otto"
-	"imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/agi/static"
 	"imuslab.com/arozos/mod/iot"
-	user "imuslab.com/arozos/mod/user"
 )
 
 /*
@@ -27,7 +25,13 @@ func (g *Gateway) IoTLibRegister() {
 	}
 }
 
-func (g *Gateway) injectIoTFunctions(vm *otto.Otto, u *user.User, scriptFsh *filesystem.FileSystemHandler, scriptPath string, w http.ResponseWriter, r *http.Request) {
+func (g *Gateway) injectIoTFunctions(payload *static.AgiLibInjectionPayload) {
+	vm := payload.VM
+	//u := payload.User
+	//scriptFsh := payload.ScriptFsh
+	//scriptPath := payload.ScriptPath
+	//w := payload.Writer
+	//r := payload.Request
 	//Scan and return the latest iot device list
 	vm.Set("_iot_scan", func(call otto.FunctionCall) otto.Value {
 		scannedDevices := g.Option.IotManager.ScanDevices()

+ 8 - 4
mod/agi/agi.share.go

@@ -2,12 +2,10 @@ package agi
 
 import (
 	"log"
-	"net/http"
 	"time"
 
 	"github.com/robertkrimen/otto"
-	"imuslab.com/arozos/mod/filesystem"
-	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/agi/static"
 )
 
 func (g *Gateway) ShareLibRegister() {
@@ -17,7 +15,13 @@ func (g *Gateway) ShareLibRegister() {
 	}
 }
 
-func (g *Gateway) injectShareFunctions(vm *otto.Otto, u *user.User, scriptFsh *filesystem.FileSystemHandler, scriptPath string, w http.ResponseWriter, r *http.Request) {
+func (g *Gateway) injectShareFunctions(payload *static.AgiLibInjectionPayload) {
+	vm := payload.VM
+	u := payload.User
+	//scriptFsh := payload.ScriptFsh
+	//scriptPath := payload.ScriptPath
+	//w := payload.Writer
+	//r := payload.Request
 	vm.Set("_share_file", func(call otto.FunctionCall) otto.Value {
 		//Get the vpath of file to share
 		vpath, err := call.Argument(0).ToString()

+ 2 - 1
mod/agi/external.agi.go → mod/agi/externalReqHandler.go

@@ -9,6 +9,7 @@ import (
 	"time"
 
 	uuid "github.com/satori/go.uuid"
+	"imuslab.com/arozos/mod/agi/static"
 	"imuslab.com/arozos/mod/utils"
 )
 
@@ -54,7 +55,7 @@ func (g *Gateway) ExtAPIHandler(w http.ResponseWriter, r *http.Request) {
 		utils.SendErrorResponse(w, "Invalid username")
 		return
 	}
-	fsh, realPath, err := virtualPathToRealPath(pathFromDb, userInfo)
+	fsh, realPath, err := static.VirtualPathToRealPath(pathFromDb, userInfo)
 	if err != nil {
 		utils.SendErrorResponse(w, "Invalid filepath")
 		return

+ 2 - 1
mod/agi/handler.go

@@ -5,6 +5,7 @@ import (
 	"os"
 	"path/filepath"
 
+	"imuslab.com/arozos/mod/agi/static"
 	"imuslab.com/arozos/mod/utils"
 )
 
@@ -43,7 +44,7 @@ func (g *Gateway) HandleAgiExecutionRequestWithToken(w http.ResponseWriter, r *h
 	}
 
 	scriptScope := ""
-	allowAccess := checkUserAccessToScript(targetUser, script, scriptScope)
+	allowAccess := static.CheckUserAccessToScript(targetUser, script, scriptScope)
 	if !allowAccess {
 		w.WriteHeader(http.StatusUnauthorized)
 		w.Write([]byte("401 - Unauthorized (Permission Denied)"))

+ 54 - 0
mod/agi/moduleManager.go

@@ -0,0 +1,54 @@
+package agi
+
+import (
+	"errors"
+
+	"imuslab.com/arozos/mod/agi/static"
+)
+
+/*
+	AGI Module Manager
+
+	This interface handles the agi function module registartions
+	and make sure the structures of all modules fits the pre-defined
+	interface to be used by ArozOS Core system
+*/
+
+// Lib interface, require vm, user, target system file handler and the vpath of the running script
+// This interface is called during injection (in user's term, require / import)
+// When called, the required agi function module will be injected into the virtual machine
+// which provide the function required for the vm code to interact with the real-systems
+type AgiLibInjectionIntergface func(*static.AgiLibInjectionPayload)
+
+type AgiLibInterface interface {
+	GetLibraryID() string                         //Get the module unique name for import
+	GetInjectFunction() AgiLibInjectionIntergface //Get the module injection point
+}
+
+// Register a library's identification name and its injection interface to the VM environment
+func (g *Gateway) RegisterLib(libname string, entryPoint AgiLibInjectionIntergface) error {
+	_, ok := g.LoadedAGILibrary[libname]
+	if ok {
+		//This lib already registered. Return error
+		return errors.New("This library name already registered")
+	} else {
+		g.LoadedAGILibrary[libname] = entryPoint
+	}
+	return nil
+}
+
+/*
+	AGI Library Register List
+
+	Add more library here if required
+*/
+
+func (g *Gateway) LoadAllFunctionalModules() {
+	g.ImageLibRegister()
+	g.FileLibRegister()
+	g.HTTPLibRegister()
+	g.ShareLibRegister()
+	g.IoTLibRegister()
+	g.AppdataLibRegister()
+	g.FFmpegLibRegister()
+}

+ 0 - 0
mod/agi/agi.serverless.go → mod/agi/serverlessReqHandler.go


+ 44 - 15
mod/agi/static.go → mod/agi/static/static.go

@@ -1,6 +1,7 @@
-package agi
+package static
 
 import (
+	"net/http"
 	"net/url"
 	"path/filepath"
 	"strings"
@@ -12,9 +13,20 @@ import (
 	"imuslab.com/arozos/mod/utils"
 )
 
-//Get the full vpath if the passing value is a relative path
-//Return the original vpath if any error occured
-func relativeVpathRewrite(fsh *filesystem.FileSystemHandler, vpath string, vm *otto.Otto, u *user.User) string {
+// Injection payload, the minimal required information for a function module to execute the
+// agi script in virtualized environment
+type AgiLibInjectionPayload struct {
+	VM         *otto.Otto
+	User       *user.User
+	ScriptFsh  *filesystem.FileSystemHandler
+	ScriptPath string
+	Writer     http.ResponseWriter
+	Request    *http.Request
+}
+
+// Get the full vpath if the passing value is a relative path
+// Return the original vpath if any error occured
+func RelativeVpathRewrite(fsh *filesystem.FileSystemHandler, vpath string, vm *otto.Otto, u *user.User) string {
 	//Check if the vpath contain a UUID
 	if strings.Contains(vpath, ":/") || (len(vpath) > 0 && vpath[len(vpath)-1:] == ":") {
 		//This vpath contain root uuid.
@@ -47,22 +59,39 @@ func relativeVpathRewrite(fsh *filesystem.FileSystemHandler, vpath string, vm *o
 	return arozfs.ToSlash(filepath.Clean(filepath.Join(rootScriptDir, vpath)))
 }
 
-//Check if the user can access this script file
-func checkUserAccessToScript(thisuser *user.User, scriptFile string, scriptScope string) bool {
-	moduleName := getScriptRoot(scriptFile, scriptScope)
+// Define path translation function
+func VirtualPathToRealPath(vpath string, u *user.User) (*filesystem.FileSystemHandler, string, error) {
+	fsh, err := u.GetFileSystemHandlerFromVirtualPath(vpath)
+	if err != nil {
+		return nil, "", err
+	}
+	rpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(vpath, u.Username)
+	if err != nil {
+		return nil, "", err
+	}
+	return fsh, rpath, nil
+}
+
+func RealpathToVirtualpath(fsh *filesystem.FileSystemHandler, path string, u *user.User) (string, error) {
+	return fsh.FileSystemAbstraction.RealPathToVirtualPath(path, u.Username)
+}
+
+// Check if the user can access this script file
+func CheckUserAccessToScript(thisuser *user.User, scriptFile string, scriptScope string) bool {
+	moduleName := GetScriptRoot(scriptFile, scriptScope)
 	if !thisuser.GetModuleAccessPermission(moduleName) {
 		return false
 	}
 	return true
 }
 
-//validate the given path is a script from webroot
-func isValidAGIScript(scriptPath string) bool {
+// validate the given path is a script from webroot
+func IsValidAGIScript(scriptPath string) bool {
 	return utils.FileExists(filepath.Join("./web", scriptPath)) && (filepath.Ext(scriptPath) == ".js" || filepath.Ext(scriptPath) == ".agi")
 }
 
-//Return the script root of the current executing script
-func getScriptRoot(scriptFile string, scriptScope string) string {
+// Return the script root of the current executing script
+func GetScriptRoot(scriptFile string, scriptScope string) string {
 	//Get the script root from the script path
 	webRootAbs, _ := filepath.Abs(scriptScope)
 	webRootAbs = filepath.ToSlash(filepath.Clean(webRootAbs) + "/")
@@ -73,16 +102,16 @@ func getScriptRoot(scriptFile string, scriptScope string) string {
 	return scriptRoot
 }
 
-//For handling special url decode in the request
-func specialURIDecode(inputPath string) string {
+// For handling special url decode in the request
+func SpecialURIDecode(inputPath string) string {
 	inputPath = strings.ReplaceAll(inputPath, "+", "{{plus_sign}}")
 	inputPath, _ = url.QueryUnescape(inputPath)
 	inputPath = strings.ReplaceAll(inputPath, "{{plus_sign}}", "+")
 	return inputPath
 }
 
-//Check if the target path is escaping the rootpath, accept relative and absolute path
-func checkRootEscape(rootPath string, targetPath string) (bool, error) {
+// Check if the target path is escaping the rootpath, accept relative and absolute path
+func CheckRootEscape(rootPath string, targetPath string) (bool, error) {
 	rootAbs, err := filepath.Abs(rootPath)
 	if err != nil {
 		return true, err

+ 25 - 24
mod/agi/systemFunc.go

@@ -12,6 +12,7 @@ import (
 	"time"
 
 	"github.com/robertkrimen/otto"
+	"imuslab.com/arozos/mod/agi/static"
 	"imuslab.com/arozos/mod/utils"
 )
 
@@ -77,7 +78,7 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 
 	vm.Set("addNightlyTask", func(call otto.FunctionCall) otto.Value {
 		scriptPath, _ := call.Argument(0).ToString() //From web directory
-		if isValidAGIScript(scriptPath) {
+		if static.IsValidAGIScript(scriptPath) {
 			g.NightlyScripts = append(g.NightlyScripts, scriptPath)
 		} else {
 			return otto.FalseValue()
@@ -90,7 +91,7 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 	vm.Set("newDBTableIfNotExists", func(call otto.FunctionCall) otto.Value {
 		tableName, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			reply, _ := vm.ToValue(false)
 			return reply
 		}
@@ -108,7 +109,7 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 	vm.Set("DBTableExists", func(call otto.FunctionCall) otto.Value {
 		tableName, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			reply, _ := vm.ToValue(false)
 			return reply
 		}
@@ -124,7 +125,7 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 	vm.Set("dropDBTable", func(call otto.FunctionCall) otto.Value {
 		tableName, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			reply, _ := vm.ToValue(false)
 			return reply
 		}
@@ -144,7 +145,7 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 	vm.Set("writeDBItem", func(call otto.FunctionCall) otto.Value {
 		tableName, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			reply, _ := vm.ToValue(false)
 			return reply
 		}
@@ -153,13 +154,13 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 		if g.filterDBTable(tableName, true) {
 			keyString, err := call.Argument(1).ToString()
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				reply, _ := vm.ToValue(false)
 				return reply
 			}
 			valueString, err := call.Argument(2).ToString()
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				reply, _ := vm.ToValue(false)
 				return reply
 			}
@@ -234,14 +235,14 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 	vm.Set("registerModule", func(call otto.FunctionCall) otto.Value {
 		jsonModuleConfig, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			reply, _ := vm.ToValue(false)
 			return reply
 		}
 		//Try to decode it to a module Info
 		g.Option.ModuleRegisterParser(jsonModuleConfig)
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			reply, _ := vm.ToValue(false)
 			return reply
 		}
@@ -254,16 +255,16 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 		vm.Set("requirepkg", func(call otto.FunctionCall) otto.Value {
 			packageName, err := call.Argument(0).ToString()
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 			requireComply, err := call.Argument(1).ToBoolean()
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
-			scriptRoot := getScriptRoot(scriptFile, scriptScope)
+			scriptRoot := static.GetScriptRoot(scriptFile, scriptScope)
 
 			//Check if this module already get registered.
 			alreadyRegistered := false
@@ -284,7 +285,7 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 			//Try to install the package via apt
 			err = g.Option.PackageManager.InstallIfNotExists(packageName, requireComply)
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
@@ -294,10 +295,10 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 		//Exec required pkg with permission control
 		vm.Set("execpkg", func(call otto.FunctionCall) otto.Value {
 			//Check if the pkg is already registered
-			scriptRoot := getScriptRoot(scriptFile, scriptScope)
+			scriptRoot := static.GetScriptRoot(scriptFile, scriptScope)
 			packageName, err := call.Argument(0).ToString()
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
@@ -312,12 +313,12 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 				}
 
 				if !thisModuleRegistered {
-					g.raiseError(errors.New("Package request not registered: " + packageName))
+					g.RaiseError(errors.New("Package request not registered: " + packageName))
 					return otto.FalseValue()
 				}
 
 			} else {
-				g.raiseError(errors.New("Package request not registered: " + packageName))
+				g.RaiseError(errors.New("Package request not registered: " + packageName))
 				return otto.FalseValue()
 			}
 
@@ -329,7 +330,7 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 			r.Comma = ' ' // space
 			fields, err := r.Read()
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
@@ -338,7 +339,7 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 			out, err := cmd.CombinedOutput()
 			if err != nil {
 				log.Println(string(out))
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
@@ -351,20 +352,20 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 			//Check if the pkg is already registered
 			scriptName, err := call.Argument(0).ToString()
 			if err != nil {
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
 			//Check if it is calling itself
 			if filepath.Base(scriptFile) == filepath.Base(scriptName) {
-				g.raiseError(errors.New("*AGI* Self calling is not allowed"))
+				g.RaiseError(errors.New("*AGI* Self calling is not allowed"))
 				return otto.FalseValue()
 			}
 
 			//Check if the script file exists
 			targetScriptPath := filepath.ToSlash(filepath.Join(filepath.Dir(scriptFile), scriptName))
 			if !utils.FileExists(targetScriptPath) {
-				g.raiseError(errors.New("*AGI* Target path not exists!"))
+				g.RaiseError(errors.New("*AGI* Target path not exists!"))
 				return otto.FalseValue()
 			}
 
@@ -374,7 +375,7 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 			if err != nil {
 				//Script execution failed
 				log.Println("Script Execution Failed: ", err.Error())
-				g.raiseError(err)
+				g.RaiseError(err)
 				return otto.FalseValue()
 			}
 
@@ -387,7 +388,7 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 	vm.Set("delay", func(call otto.FunctionCall) otto.Value {
 		delayTime, err := call.Argument(0).ToInteger()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 		time.Sleep(time.Duration(delayTime) * time.Millisecond)

+ 29 - 38
mod/agi/userFunc.go

@@ -9,28 +9,12 @@ import (
 	"path/filepath"
 
 	"github.com/robertkrimen/otto"
+	"imuslab.com/arozos/mod/agi/static"
 	"imuslab.com/arozos/mod/filesystem"
 	"imuslab.com/arozos/mod/filesystem/arozfs"
 	user "imuslab.com/arozos/mod/user"
 )
 
-// Define path translation function
-func virtualPathToRealPath(vpath string, u *user.User) (*filesystem.FileSystemHandler, string, error) {
-	fsh, err := u.GetFileSystemHandlerFromVirtualPath(vpath)
-	if err != nil {
-		return nil, "", err
-	}
-	rpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(vpath, u.Username)
-	if err != nil {
-		return nil, "", err
-	}
-	return fsh, rpath, nil
-}
-
-func realpathToVirtualpath(fsh *filesystem.FileSystemHandler, path string, u *user.User) (string, error) {
-	return fsh.FileSystemAbstraction.RealPathToVirtualPath(path, u.Username)
-}
-
 // Inject user based functions into the virtual machine
 // Note that the fsh might be nil and scriptPath must be real path of script being executed
 // **Use local file system check if fsh == nil**
@@ -91,7 +75,7 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 			//Get username from function paramter
 			username, err := call.Argument(0).ToString()
 			if err != nil || username == "undefined" {
-				g.raiseError(errors.New("username is undefined"))
+				g.RaiseError(errors.New("username is undefined"))
 				reply, _ := vm.ToValue(nil)
 				return reply
 			}
@@ -105,7 +89,7 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 			}
 
 		} else {
-			g.raiseError(errors.New("Permission Denied: userExists require admin permission"))
+			g.RaiseError(errors.New("Permission Denied: userExists require admin permission"))
 			return otto.FalseValue()
 		}
 
@@ -119,21 +103,21 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 			//Ok. Create user base on given information
 			username, err := call.Argument(0).ToString()
 			if err != nil || username == "undefined" {
-				g.raiseError(errors.New("username is undefined"))
+				g.RaiseError(errors.New("username is undefined"))
 				reply, _ := vm.ToValue(false)
 				return reply
 			}
 
 			password, err := call.Argument(1).ToString()
 			if err != nil || password == "undefined" {
-				g.raiseError(errors.New("password is undefined"))
+				g.RaiseError(errors.New("password is undefined"))
 				reply, _ := vm.ToValue(false)
 				return reply
 			}
 
 			defaultGroup, err := call.Argument(2).ToString()
 			if err != nil || defaultGroup == "undefined" {
-				g.raiseError(errors.New("defaultGroup is undefined"))
+				g.RaiseError(errors.New("defaultGroup is undefined"))
 				reply, _ := vm.ToValue(false)
 				return reply
 			}
@@ -141,7 +125,7 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 			//Check if username already used
 			userExists := u.Parent().GetAuthAgent().UserExists(username)
 			if userExists {
-				g.raiseError(errors.New("Username already exists"))
+				g.RaiseError(errors.New("Username already exists"))
 				reply, _ := vm.ToValue(false)
 				return reply
 			}
@@ -149,7 +133,7 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 			//Check if the given permission group exists
 			groupExists := u.Parent().GetPermissionHandler().GroupExists(defaultGroup)
 			if !groupExists {
-				g.raiseError(errors.New(defaultGroup + " user-group not exists"))
+				g.RaiseError(errors.New(defaultGroup + " user-group not exists"))
 				reply, _ := vm.ToValue(false)
 				return reply
 			}
@@ -158,14 +142,14 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 			err = u.Parent().GetAuthAgent().CreateUserAccount(username, password, []string{defaultGroup})
 
 			if err != nil {
-				g.raiseError(errors.New("User creation failed: " + err.Error()))
+				g.RaiseError(errors.New("User creation failed: " + err.Error()))
 				reply, _ := vm.ToValue(false)
 				return reply
 			}
 
 			return otto.TrueValue()
 		} else {
-			g.raiseError(errors.New("Permission Denied: createUser require admin permission"))
+			g.RaiseError(errors.New("Permission Denied: createUser require admin permission"))
 			return otto.FalseValue()
 		}
 
@@ -175,7 +159,7 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 		if u.IsAdmin() {
 
 		} else {
-			g.raiseError(errors.New("Permission Denied: editUser require admin permission"))
+			g.RaiseError(errors.New("Permission Denied: editUser require admin permission"))
 			return otto.FalseValue()
 		}
 		//libname, err := call.Argument(0).ToString()
@@ -190,7 +174,7 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 			//Get username from function paramters
 			username, err := call.Argument(0).ToString()
 			if err != nil || username == "undefined" {
-				g.raiseError(errors.New("username is undefined"))
+				g.RaiseError(errors.New("username is undefined"))
 				reply, _ := vm.ToValue(false)
 				return reply
 			}
@@ -198,7 +182,7 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 			//Check if the user exists
 			userExists := u.Parent().GetAuthAgent().UserExists(username)
 			if !userExists {
-				g.raiseError(errors.New(username + " not exists"))
+				g.RaiseError(errors.New(username + " not exists"))
 				reply, _ := vm.ToValue(false)
 				return reply
 			}
@@ -206,14 +190,14 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 			//User exists. Remove it from the system
 			err = u.Parent().GetAuthAgent().UnregisterUser(username)
 			if err != nil {
-				g.raiseError(errors.New("User removal failed: " + err.Error()))
+				g.RaiseError(errors.New("User removal failed: " + err.Error()))
 				reply, _ := vm.ToValue(false)
 				return reply
 			}
 
 			return otto.TrueValue()
 		} else {
-			g.raiseError(errors.New("Permission Denied: removeUser require admin permission"))
+			g.RaiseError(errors.New("Permission Denied: removeUser require admin permission"))
 			return otto.FalseValue()
 		}
 	})
@@ -224,7 +208,7 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 
 		} else {
 
-			g.raiseError(errors.New("Permission Denied: getUserInfoByName require admin permission"))
+			g.RaiseError(errors.New("Permission Denied: getUserInfoByName require admin permission"))
 			return otto.FalseValue()
 		}
 		return otto.TrueValue()
@@ -234,7 +218,7 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 	vm.Set("requirelib", func(call otto.FunctionCall) otto.Value {
 		libname, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			reply, _ := vm.ToValue(nil)
 			return reply
 		}
@@ -246,7 +230,14 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 		} else {
 			//Check if the library name exists. If yes, run the initiation script on the vm
 			if entryPoint, ok := g.LoadedAGILibrary[libname]; ok {
-				entryPoint(vm, u, fsh, scriptPath, w, r)
+				entryPoint(&static.AgiLibInjectionPayload{
+					VM:         vm,
+					User:       u,
+					ScriptFsh:  fsh,
+					ScriptPath: scriptPath,
+					Writer:     w,
+					Request:    r,
+				})
 				return otto.TrueValue()
 			} else {
 				//Lib not exists
@@ -261,7 +252,7 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 		//Check if the pkg is already registered
 		scriptName, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 
@@ -272,12 +263,12 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 		targetScriptPath := arozfs.ToSlash(filepath.Join(filepath.Dir(scriptPath), scriptName))
 		if fsh != nil {
 			if !fsh.FileSystemAbstraction.FileExists(targetScriptPath) {
-				g.raiseError(errors.New("[AGI] Target path not exists!"))
+				g.RaiseError(errors.New("[AGI] Target path not exists!"))
 				return otto.FalseValue()
 			}
 		} else {
 			if !filesystem.FileExists(targetScriptPath) {
-				g.raiseError(errors.New("[AGI] Target path not exists!"))
+				g.RaiseError(errors.New("[AGI] Target path not exists!"))
 				return otto.FalseValue()
 			}
 		}
@@ -297,7 +288,7 @@ func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemH
 			if err != nil {
 				//Script execution failed
 				log.Println("Script Execution Failed: ", err.Error())
-				g.raiseError(err)
+				g.RaiseError(err)
 			}
 		}()
 

+ 8 - 8
mod/agi/agi.ws.go → mod/agi/websocket.go

@@ -13,13 +13,13 @@ import (
 )
 
 /*
-	AJGI WebSocket Request Library
+AJGI WebSocket Request Library
 
-	This is a library for allowing AGI based connection upgrade to WebSocket
-	Different from other agi module, this do not use the register lib interface
-	deal to it special nature.
+This is a library for allowing AGI based connection upgrade to WebSocket
+Different from other agi module, this do not use the register lib interface
+deal to it special nature.
 
-	Author: tobychui
+Author: tobychui
 */
 var upgrader = websocket.Upgrader{
 	ReadBufferSize:  1024,
@@ -30,8 +30,8 @@ var upgrader = websocket.Upgrader{
 }
 var connections = sync.Map{}
 
-//This is a very special function to check if the connection has been updated or not
-//Return upgrade status (true for already upgraded) and connection uuid
+// This is a very special function to check if the connection has been updated or not
+// Return upgrade status (true for already upgraded) and connection uuid
 func checkWebSocketConnectionUpgradeStatus(vm *otto.Otto) (bool, string, *websocket.Conn) {
 	if value, err := vm.Get("_websocket_conn_id"); err == nil {
 		//Exists!
@@ -134,7 +134,7 @@ func (g *Gateway) injectWebSocketFunctions(vm *otto.Otto, u *user.User, w http.R
 		//Get the content to send
 		content, err := call.Argument(0).ToString()
 		if err != nil {
-			g.raiseError(err)
+			g.RaiseError(err)
 			return otto.FalseValue()
 		}
 

+ 88 - 46
mod/filesystem/filesystem.go

@@ -24,6 +24,7 @@ import (
 	"strings"
 	"time"
 
+	uuid "github.com/satori/go.uuid"
 	db "imuslab.com/arozos/mod/database"
 	"imuslab.com/arozos/mod/filesystem/abstractions/ftpfs"
 	"imuslab.com/arozos/mod/filesystem/abstractions/localfs"
@@ -31,6 +32,7 @@ import (
 	"imuslab.com/arozos/mod/filesystem/abstractions/smbfs"
 	"imuslab.com/arozos/mod/filesystem/abstractions/webdavfs"
 	"imuslab.com/arozos/mod/filesystem/arozfs"
+	"imuslab.com/arozos/mod/utils"
 )
 
 //Options for creating new file system handler
@@ -89,26 +91,32 @@ type FileSystemAbstraction interface {
 	Heartbeat() error
 }
 
+// Runtime persistence config, use to pass through startup paramters related to file system handlers
+type RuntimePersistenceConfig struct {
+	LocalBufferPath string
+}
+
 // System Handler for returing
 type FileSystemHandler struct {
-	Name                  string
-	UUID                  string
-	Path                  string
-	Hierarchy             string
-	HierarchyConfig       HierarchySpecificConfig
-	ReadOnly              bool
-	RequireBuffer         bool //Set this to true if the fsh do not provide file header functions like Open() or Create(), require WriteStream() and ReadStream()
-	Parentuid             string
-	InitiationTime        int64
-	FilesystemDatabase    *db.Database
-	FileSystemAbstraction FileSystemAbstraction
-	Filesystem            string
-	StartOptions          FileSystemOption
-	Closed                bool
+	Name                     string
+	UUID                     string
+	Path                     string
+	Hierarchy                string
+	HierarchyConfig          HierarchySpecificConfig
+	ReadOnly                 bool
+	RequireBuffer            bool //Set this to true if the fsh do not provide file header functions like Open() or Create(), require WriteStream() and ReadStream()
+	Parentuid                string
+	InitiationTime           int64
+	FilesystemDatabase       *db.Database
+	FileSystemAbstraction    FileSystemAbstraction
+	Filesystem               string
+	StartOptions             FileSystemOption
+	RuntimePersistenceConfig RuntimePersistenceConfig
+	Closed                   bool
 }
 
 // Create a list of file system handler from the given json content
-func NewFileSystemHandlersFromJSON(jsonContent []byte) ([]*FileSystemHandler, error) {
+func NewFileSystemHandlersFromJSON(jsonContent []byte, runtimePersistenceConfig RuntimePersistenceConfig) ([]*FileSystemHandler, error) {
 	//Generate a list of handler option from json file
 	options, err := loadConfigFromJSON(jsonContent)
 	if err != nil {
@@ -117,7 +125,7 @@ func NewFileSystemHandlersFromJSON(jsonContent []byte) ([]*FileSystemHandler, er
 
 	resultingHandlers := []*FileSystemHandler{}
 	for _, option := range options {
-		thisHandler, err := NewFileSystemHandler(option)
+		thisHandler, err := NewFileSystemHandler(option, runtimePersistenceConfig)
 		if err != nil {
 			log.Println("[File System] Failed to create system handler for " + option.Name)
 			//log.Println(err.Error())
@@ -130,7 +138,7 @@ func NewFileSystemHandlersFromJSON(jsonContent []byte) ([]*FileSystemHandler, er
 }
 
 // Create a new file system handler with the given config
-func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
+func NewFileSystemHandler(option FileSystemOption, RuntimePersistenceConfig RuntimePersistenceConfig) (*FileSystemHandler, error) {
 	fstype := strings.ToLower(option.Filesystem)
 	if inSlice([]string{"ext4", "ext2", "ext3", "fat", "vfat", "ntfs"}, fstype) || fstype == "" {
 		//Check if the target fs require mounting
@@ -165,19 +173,20 @@ func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
 		}
 		rootpath := filepath.ToSlash(filepath.Clean(option.Path)) + "/"
 		return &FileSystemHandler{
-			Name:                  option.Name,
-			UUID:                  option.Uuid,
-			Path:                  filepath.ToSlash(filepath.Clean(option.Path)) + "/",
-			ReadOnly:              option.Access == arozfs.FsReadOnly,
-			RequireBuffer:         false,
-			Hierarchy:             option.Hierarchy,
-			HierarchyConfig:       DefaultEmptyHierarchySpecificConfig,
-			InitiationTime:        time.Now().Unix(),
-			FilesystemDatabase:    fsdb,
-			FileSystemAbstraction: localfs.NewLocalFileSystemAbstraction(option.Uuid, rootpath, option.Hierarchy, option.Access == arozfs.FsReadOnly),
-			Filesystem:            fstype,
-			StartOptions:          option,
-			Closed:                false,
+			Name:                     option.Name,
+			UUID:                     option.Uuid,
+			Path:                     filepath.ToSlash(filepath.Clean(option.Path)) + "/",
+			ReadOnly:                 option.Access == arozfs.FsReadOnly,
+			RequireBuffer:            false,
+			Hierarchy:                option.Hierarchy,
+			HierarchyConfig:          DefaultEmptyHierarchySpecificConfig,
+			InitiationTime:           time.Now().Unix(),
+			FilesystemDatabase:       fsdb,
+			FileSystemAbstraction:    localfs.NewLocalFileSystemAbstraction(option.Uuid, rootpath, option.Hierarchy, option.Access == arozfs.FsReadOnly),
+			Filesystem:               fstype,
+			StartOptions:             option,
+			RuntimePersistenceConfig: RuntimePersistenceConfig,
+			Closed:                   false,
 		}, nil
 
 	} else if fstype == "webdav" {
@@ -325,27 +334,60 @@ func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
 	return nil, errors.New("Not supported file system: " + fstype)
 }
 
+// Check if a fsh is a network drive
 func (fsh *FileSystemHandler) IsNetworkDrive() bool {
 	return arozfs.IsNetworkDrive(fsh.Filesystem)
 }
 
-//Check if a fsh is virtual (e.g. Network or fs Abstractions that cannot be listed with normal fs API)
-/*
-func (fsh *FileSystemHandler) IsVirtual() bool {
-	if fsh.Hierarchy == "virtual" || fsh.Filesystem == "webdav" {
-		//Check if the config return placeholder
-		c, ok := fsh.HierarchyConfig.(EmptyHierarchySpecificConfig)
-		if ok && c.HierarchyType == "placeholder" {
-			//Real file system.
-			return false
-		}
+// Buffer a remote file to local tmp folder and return the tmp location for further processing
+func (fsh *FileSystemHandler) BufferRemoteToLocal(rpath string) (string, error) {
+	//Check if the target fsh is actually a network drive
+	if !fsh.IsNetworkDrive() {
+		return "", errors.New("target file system handler is not a network drive")
+	}
 
-		//Do more checking here if needed
-		return true
+	//Check if the remote file exists
+	fsa := fsh.FileSystemAbstraction
+	if !fsa.FileExists(rpath) {
+		//Target file not exists
+		return "", errors.New("target file not exists on remote")
 	}
-	return false
+
+	//Check if the remote is a file (not support dir)
+	if fsa.IsDir(rpath) {
+		return "", errors.New("directory cannot be buffered to local")
+	}
+
+	//Get the tmp folder directory
+	tmpdir := fsh.RuntimePersistenceConfig.LocalBufferPath
+	if !utils.FileExists(tmpdir) {
+		//Create the tmp dir if not exists
+		os.MkdirAll(tmpdir, 0775)
+	}
+
+	//Generate a filename for the buffer file
+	tmpFilename := uuid.NewV4().String()
+	tmpFilepath := arozfs.ToSlash(filepath.Join(tmpdir, tmpFilename))
+
+	//Copy the file from remote location to local
+	src, err := fsh.FileSystemAbstraction.ReadStream(rpath)
+	if err != nil {
+		return "", err
+	}
+
+	dest, err := os.OpenFile(tmpFilepath, os.O_WRONLY, 0777)
+	if err != nil {
+		return "", errors.New("unable to write to buffer location: " + err.Error())
+	}
+
+	_, err = io.Copy(dest, src)
+	if err != nil {
+		return "", errors.New("file buffer failed: " + err.Error())
+	}
+
+	//Return the buffered filepath on local disk
+	return tmpFilepath, nil
 }
-*/
 
 func (fsh *FileSystemHandler) IsRootOf(vpath string) bool {
 	return strings.HasPrefix(vpath, fsh.UUID+":")
@@ -456,7 +498,7 @@ func (fsh *FileSystemHandler) ReloadFileSystelAbstraction() error {
 	log.Println("[File System] Reloading File System Abstraction for " + fsh.Name)
 	//Load the start option for this fsh
 	originalStartOption := fsh.StartOptions
-
+	runtimePersistenceConfig := fsh.RuntimePersistenceConfig
 	//Close the file system handler
 	fsh.Close()
 
@@ -464,7 +506,7 @@ func (fsh *FileSystemHandler) ReloadFileSystelAbstraction() error {
 	time.Sleep(800 * time.Millisecond)
 
 	//Generate a new fsh from original start option
-	reloadedFsh, err := NewFileSystemHandler(originalStartOption)
+	reloadedFsh, err := NewFileSystemHandler(originalStartOption, runtimePersistenceConfig)
 	if err != nil {
 		return err
 	}

+ 5 - 3
mod/network/wifi/wifi_linux.go

@@ -13,6 +13,8 @@ import (
 	"strconv"
 	"strings"
 	"time"
+
+	"imuslab.com/arozos/mod/utils"
 )
 
 // Toggle WiFi On Off. Only allow on sudo mode
@@ -428,12 +430,12 @@ func (w *WiFiManager) ConnectWiFi(ssid string, password string, connType string,
 
 		if strings.TrimSuffix(filepath.Base(configFile), filepath.Ext(configFile)) == ssid {
 			//The new SSID. Set this to higher priority
-			networks = append(networks, template_apply(string(thisNetworkConfig), map[string]interface{}{
+			networks = append(networks, utils.TemplateApply(string(thisNetworkConfig), map[string]string{
 				"priority": strconv.Itoa(1),
 			}))
 		} else {
 			//Old SSID. Use default priority
-			networks = append(networks, template_apply(string(thisNetworkConfig), map[string]interface{}{
+			networks = append(networks, utils.TemplateApply(string(thisNetworkConfig), map[string]string{
 				"priority": strconv.Itoa(0),
 			}))
 		}
@@ -442,7 +444,7 @@ func (w *WiFiManager) ConnectWiFi(ssid string, password string, connType string,
 
 	//Subsitute the results into the template
 	networksConfigString := strings.Join(networks, "\n")
-	newconfig := template_apply(string(configHeader), map[string]interface{}{
+	newconfig := utils.TemplateApply(string(configHeader), map[string]string{
 		"networks": networksConfigString,
 	})
 

+ 11 - 40
mod/utils/utils.go

@@ -40,46 +40,6 @@ func SendOK(w http.ResponseWriter) {
 	w.Write([]byte("\"OK\""))
 }
 
-/*
-	The paramter move function (mv)
-
-	You can find similar things in the PHP version of ArOZ Online Beta. You need to pass in
-	r (HTTP Request Object)
-	getParamter (string, aka $_GET['This string])
-
-	Will return
-	Paramter string (if any)
-	Error (if error)
-
-*/
-/*
-func Mv(r *http.Request, getParamter string, postMode bool) (string, error) {
-	if postMode == false {
-		//Access the paramter via GET
-		keys, ok := r.URL.Query()[getParamter]
-
-		if !ok || len(keys[0]) < 1 {
-			//log.Println("Url Param " + getParamter +" is missing")
-			return "", errors.New("GET paramter " + getParamter + " not found or it is empty")
-		}
-
-		// Query()["key"] will return an array of items,
-		// we only want the single item.
-		key := keys[0]
-		return string(key), nil
-	} else {
-		//Access the parameter via POST
-		r.ParseForm()
-		x := r.Form.Get(getParamter)
-		if len(x) == 0 || x == "" {
-			return "", errors.New("POST paramter " + getParamter + " not found or it is empty")
-		}
-		return string(x), nil
-	}
-
-}
-*/
-
 // Get GET parameter
 func GetPara(r *http.Request, key string) (string, error) {
 	keys, ok := r.URL.Query()[key]
@@ -188,3 +148,14 @@ func Templateload(templateFile string, data map[string]string) (string, error) {
 
 	return string(content), nil
 }
+
+// Apply template from a pre-loaded string
+func TemplateApply(templateString string, data map[string]string) string {
+	content := []byte(templateString)
+	for key, value := range data {
+		key = "{{" + key + "}}"
+		content = []byte(strings.ReplaceAll(string(content), key, value))
+	}
+
+	return string(content)
+}

+ 14 - 3
storage.go

@@ -61,6 +61,8 @@ func LoadBaseStoragePool() error {
 		Hierarchy:  "user",
 		Automount:  false,
 		Filesystem: localFileSystem,
+	}, fs.RuntimePersistenceConfig{
+		LocalBufferPath: *tmp_directory,
 	})
 
 	if err != nil {
@@ -77,6 +79,8 @@ func LoadBaseStoragePool() error {
 		Hierarchy:  "user",
 		Automount:  false,
 		Filesystem: localFileSystem,
+	}, fs.RuntimePersistenceConfig{
+		LocalBufferPath: *tmp_directory,
 	})
 
 	if err != nil {
@@ -92,7 +96,9 @@ func LoadBaseStoragePool() error {
 		systemWideLogger.PrintAndLog("Storage", "Storage configuration file not found. Using internal storage only.", err)
 	} else {
 		//Configuration loaded. Initializing handler
-		externalHandlers, err := fs.NewFileSystemHandlersFromJSON(rawConfig)
+		externalHandlers, err := fs.NewFileSystemHandlersFromJSON(rawConfig, fs.RuntimePersistenceConfig{
+			LocalBufferPath: *tmp_directory,
+		})
 		if err != nil {
 			systemWideLogger.PrintAndLog("Storage", "Failed to load storage configuration: "+err.Error()+" -- Skipping", err)
 		} else {
@@ -149,7 +155,9 @@ func StoragePerformFileSystemAbstractionConnectionHeartbeat() {
 			json.Unmarshal(js, &originalStartOption)
 
 			//Create a new fsh from original start options
-			newfsh, err := filesystem.NewFileSystemHandler(originalStartOption)
+			newfsh, err := filesystem.NewFileSystemHandler(originalStartOption, fs.RuntimePersistenceConfig{
+				LocalBufferPath: *tmp_directory,
+			})
 			if err != nil {
 				log.Println("[Storage] Unable to reconnect " + thisFsh.Name + ": " + err.Error())
 				continue
@@ -207,7 +215,10 @@ func LoadStoragePoolForGroup(pg *permission.PermissionGroup) error {
 		}
 
 		//Generate fsHandler form json
-		thisGroupFsHandlers, err := fs.NewFileSystemHandlersFromJSON(pgStorageConfig)
+		thisGroupFsHandlers, err := fs.NewFileSystemHandlersFromJSON(pgStorageConfig, fs.RuntimePersistenceConfig{
+			LocalBufferPath: *tmp_directory,
+		})
+
 		if err != nil {
 			systemWideLogger.PrintAndLog("Storage", "Failed to load storage configuration: "+err.Error(), err)
 			return errors.New("Failed to load storage configuration: " + err.Error())

File diff suppressed because it is too large
+ 7 - 263
web/FFmpeg Factory/index.html


+ 2 - 2
web/FFmpeg Factory/public/transcode-mt.esm.html

@@ -29,9 +29,9 @@
         const { name } = files[0];
         await ffmpeg.writeFile(name, await fetchFile(files[0]));
         message.innerHTML = 'Start transcoding';
-        await ffmpeg.exec(['-i', name,  'output.mp3']);
+        await ffmpeg.exec(['-i', name,  'output.mp4']);
         message.innerHTML = 'Complete transcoding';
-        const data = await ffmpeg.readFile('output.mp3');
+        const data = await ffmpeg.readFile('output.mp4');
 
         const video = document.getElementById('output-video');
         video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));

+ 33 - 33
web/SystemAO/info/gomod-license.csv

@@ -1,75 +1,75 @@
 cloud.google.com/go/compute/metadata,https://github.com/googleapis/google-cloud-go/blob/compute/metadata/v0.2.3/compute/metadata/LICENSE,Apache-2.0
+dario.cat/mergo,https://github.com/imdario/mergo/blob/v1.0.0/LICENSE,BSD-3-Clause
 github.com/Microsoft/go-winio,https://github.com/Microsoft/go-winio/blob/v0.6.1/LICENSE,MIT
-github.com/ProtonMail/go-crypto,https://github.com/ProtonMail/go-crypto/blob/58e86b294756/LICENSE,BSD-3-Clause
-github.com/andybalholm/brotli,https://github.com/andybalholm/brotli/blob/v1.0.5/LICENSE,MIT
+github.com/ProtonMail/go-crypto,https://github.com/ProtonMail/go-crypto/blob/afb1ddc0824c/LICENSE,BSD-3-Clause
+github.com/andybalholm/brotli,https://github.com/andybalholm/brotli/blob/v1.0.6/LICENSE,MIT
 github.com/boltdb/bolt,https://github.com/boltdb/bolt/blob/v1.3.1/LICENSE,MIT
 github.com/cenkalti/backoff,https://github.com/cenkalti/backoff/blob/v2.2.1/LICENSE,MIT
-github.com/cloudflare/circl,https://github.com/cloudflare/circl/blob/v1.3.3/LICENSE,BSD-3-Clause
-github.com/dhowden/tag,https://github.com/dhowden/tag/blob/adf36e896086/LICENSE,BSD-2-Clause
+github.com/cloudflare/circl,https://github.com/cloudflare/circl/blob/v1.3.7/LICENSE,BSD-3-Clause
+github.com/cyphar/filepath-securejoin,https://github.com/cyphar/filepath-securejoin/blob/v0.2.4/LICENSE,BSD-3-Clause
+github.com/dhowden/tag,https://github.com/dhowden/tag/blob/978a0926ee25/LICENSE,BSD-2-Clause
 github.com/disintegration/imaging,https://github.com/disintegration/imaging/blob/v1.6.2/LICENSE,MIT
 github.com/dsnet/compress,https://github.com/dsnet/compress/blob/f66993602bf5/LICENSE.md,BSD-3-Clause
 github.com/emirpasic/gods,https://github.com/emirpasic/gods/blob/v1.18.1/LICENSE,BSD-2-Clause
-github.com/fclairamb/ftpserverlib,https://github.com/fclairamb/ftpserverlib/blob/v0.21.0/license.txt,MIT
+github.com/fclairamb/ftpserverlib,https://github.com/fclairamb/ftpserverlib/blob/v0.22.0/license.txt,MIT
 github.com/fclairamb/go-log,https://github.com/fclairamb/go-log/blob/v0.4.1/license.txt,MIT
 github.com/fogleman/fauxgl,https://github.com/fogleman/fauxgl/blob/27cddc103802/LICENSE.md,MIT
 github.com/fogleman/simplify,https://github.com/fogleman/simplify/blob/d32f302d5046/LICENSE.md,MIT
-github.com/gabriel-vasile/mimetype,https://github.com/gabriel-vasile/mimetype/blob/v1.4.2/LICENSE,MIT
+github.com/gabriel-vasile/mimetype,https://github.com/gabriel-vasile/mimetype/blob/v1.4.3/LICENSE,MIT
 github.com/geoffgarside/ber,https://github.com/geoffgarside/ber/blob/v1.1.0/LICENSE,BSD-3-Clause
-github.com/go-git/gcfg,https://github.com/go-git/gcfg/blob/v1.5.0/LICENSE,BSD-3-Clause
-github.com/go-git/go-billy/v5,https://github.com/go-git/go-billy/blob/v5.4.1/LICENSE,Apache-2.0
-github.com/go-git/go-git/v5,https://github.com/go-git/go-git/blob/v5.6.1/LICENSE,Apache-2.0
+github.com/go-git/gcfg,https://github.com/go-git/gcfg/blob/3a3c6141e376/LICENSE,BSD-3-Clause
+github.com/go-git/go-billy/v5,https://github.com/go-git/go-billy/blob/v5.5.0/LICENSE,Apache-2.0
+github.com/go-git/go-git/v5,https://github.com/go-git/go-git/blob/v5.11.0/LICENSE,Apache-2.0
 github.com/go-ldap/ldap,https://github.com/go-ldap/ldap/blob/v3.0.3/LICENSE,MIT
 github.com/golang/freetype,Unknown,Unknown
 github.com/golang/freetype/raster,Unknown,Unknown
 github.com/golang/freetype/truetype,Unknown,Unknown
+github.com/golang/groupcache/lru,https://github.com/golang/groupcache/blob/41bb18bfe9da/LICENSE,Apache-2.0
 github.com/golang/snappy,https://github.com/golang/snappy/blob/v0.0.4/LICENSE,BSD-3-Clause
-github.com/gorilla/securecookie,https://github.com/gorilla/securecookie/blob/v1.1.1/LICENSE,BSD-3-Clause
-github.com/gorilla/sessions,https://github.com/gorilla/sessions/blob/v1.2.1/LICENSE,BSD-3-Clause
-github.com/gorilla/websocket,https://github.com/gorilla/websocket/blob/v1.5.0/LICENSE,BSD-2-Clause
+github.com/gorilla/securecookie,https://github.com/gorilla/securecookie/blob/v1.1.2/LICENSE,BSD-3-Clause
+github.com/gorilla/sessions,https://github.com/gorilla/sessions/blob/v1.2.2/LICENSE,BSD-3-Clause
+github.com/gorilla/websocket,https://github.com/gorilla/websocket/blob/v1.5.1/LICENSE,BSD-3-Clause
 github.com/grandcat/zeroconf,https://github.com/grandcat/zeroconf/blob/v1.0.0/LICENSE,MIT
 github.com/hashicorp/errwrap,https://github.com/hashicorp/errwrap/blob/v1.1.0/LICENSE,MPL-2.0
 github.com/hashicorp/go-multierror,https://github.com/hashicorp/go-multierror/blob/v1.1.1/LICENSE,MPL-2.0
 github.com/hirochachacha/go-smb2,https://github.com/hirochachacha/go-smb2/blob/v1.1.0/LICENSE,BSD-2-Clause
-github.com/imdario/mergo,https://github.com/imdario/mergo/blob/v0.3.15/LICENSE,BSD-3-Clause
 github.com/jbenet/go-context/io,https://github.com/jbenet/go-context/blob/d14ea06fba99/LICENSE,MIT
-github.com/jlaffaye/ftp,https://github.com/jlaffaye/ftp/blob/v0.1.0/LICENSE,ISC
+github.com/jlaffaye/ftp,https://github.com/jlaffaye/ftp/blob/v0.2.0/LICENSE,ISC
 github.com/kevinburke/ssh_config,https://github.com/kevinburke/ssh_config/blob/v1.2.0/LICENSE,MIT
-github.com/klauspost/compress,https://github.com/klauspost/compress/blob/v1.16.5/LICENSE,Apache-2.0
-github.com/klauspost/compress/internal/snapref,https://github.com/klauspost/compress/blob/v1.16.5/internal\snapref\LICENSE,BSD-3-Clause
-github.com/klauspost/compress/zstd/internal/xxhash,https://github.com/klauspost/compress/blob/v1.16.5/zstd\internal\xxhash\LICENSE.txt,MIT
+github.com/klauspost/compress,https://github.com/klauspost/compress/blob/v1.17.4/LICENSE,Apache-2.0
+github.com/klauspost/compress/internal/snapref,https://github.com/klauspost/compress/blob/v1.17.4/internal\snapref\LICENSE,BSD-3-Clause
+github.com/klauspost/compress/zstd/internal/xxhash,https://github.com/klauspost/compress/blob/v1.17.4/zstd\internal\xxhash\LICENSE.txt,MIT
 github.com/klauspost/pgzip,https://github.com/klauspost/pgzip/blob/v1.2.6/LICENSE,MIT
 github.com/koron/go-ssdp,https://github.com/koron/go-ssdp/blob/v0.0.4/LICENSE,MIT
 github.com/kr/fs,https://github.com/kr/fs/blob/v0.1.0/LICENSE,BSD-3-Clause
 github.com/mholt/archiver/v3,https://github.com/mholt/archiver/blob/v3.5.1/LICENSE,MIT
-github.com/miekg/dns,https://github.com/miekg/dns/blob/v1.1.54/LICENSE,BSD-3-Clause
+github.com/miekg/dns,https://github.com/miekg/dns/blob/v1.1.57/LICENSE,BSD-3-Clause
 github.com/nfnt/resize,https://github.com/nfnt/resize/blob/83c6a9932646/LICENSE,ISC
 github.com/nwaples/rardecode,https://github.com/nwaples/rardecode/blob/v1.1.3/LICENSE,BSD-2-Clause
 github.com/oliamb/cutter,https://github.com/oliamb/cutter/blob/v0.2.2/LICENSE,MIT
 github.com/oov/psd,https://github.com/oov/psd/blob/5db5eafcecbb/LICENSE,MIT
-github.com/pierrec/lz4/v4,https://github.com/pierrec/lz4/blob/v4.1.17/LICENSE,BSD-3-Clause
+github.com/pierrec/lz4/v4,https://github.com/pierrec/lz4/blob/v4.1.19/LICENSE,BSD-3-Clause
 github.com/pjbgf/sha1cd,https://github.com/pjbgf/sha1cd/blob/v0.3.0/LICENSE,Apache-2.0
-github.com/pkg/sftp,https://github.com/pkg/sftp/blob/v1.13.5/LICENSE,BSD-2-Clause
-github.com/robertkrimen/otto,https://github.com/robertkrimen/otto/blob/v0.2.1/LICENSE,MIT
+github.com/pkg/sftp,https://github.com/pkg/sftp/blob/v1.13.6/LICENSE,BSD-2-Clause
+github.com/robertkrimen/otto,https://github.com/robertkrimen/otto/blob/v0.3.0/LICENSE,MIT
 github.com/satori/go.uuid,https://github.com/satori/go.uuid/blob/v1.2.0/LICENSE,MIT
 github.com/sergi/go-diff/diffmatchpatch,https://github.com/sergi/go-diff/blob/v1.3.1/LICENSE,MIT
-github.com/skeema/knownhosts,https://github.com/skeema/knownhosts/blob/v1.1.0/LICENSE,Apache-2.0
-github.com/spf13/afero,https://github.com/spf13/afero/blob/v1.9.5/LICENSE.txt,Apache-2.0
-github.com/studio-b12/gowebdav,https://github.com/studio-b12/gowebdav/blob/3282f94193f2/LICENSE,BSD-3-Clause
+github.com/skeema/knownhosts,https://github.com/skeema/knownhosts/blob/v1.2.1/LICENSE,Apache-2.0
+github.com/spf13/afero,https://github.com/spf13/afero/blob/v1.11.0/LICENSE.txt,Apache-2.0
+github.com/studio-b12/gowebdav,https://github.com/studio-b12/gowebdav/blob/v0.9.0/LICENSE,BSD-3-Clause
 github.com/ulikunitz/xz,https://github.com/ulikunitz/xz/blob/v0.5.11/LICENSE,BSD-3-Clause
-github.com/valyala/bytebufferpool,https://github.com/valyala/bytebufferpool/blob/v1.0.0/LICENSE,MIT
-github.com/valyala/fasttemplate,https://github.com/valyala/fasttemplate/blob/v1.2.2/LICENSE,MIT
 github.com/xanzy/ssh-agent,https://github.com/xanzy/ssh-agent/blob/v0.3.3/LICENSE,Apache-2.0
 github.com/xi2/xz,Unknown,Unknown
 gitlab.com/NebulousLabs/fastrand,https://gitlab.com/NebulousLabs/fastrand/blob/603482d69e40/LICENSE,MIT
 gitlab.com/NebulousLabs/go-upnp,https://gitlab.com/NebulousLabs/go-upnp/blob/11da932010b6/LICENSE,MIT
 gitlab.com/NebulousLabs/go-upnp/goupnp,https://gitlab.com/NebulousLabs/go-upnp/blob/11da932010b6/goupnp\LICENSE,BSD-2-Clause
-golang.org/x/crypto,https://cs.opensource.google/go/x/crypto/+/v0.9.0:LICENSE,BSD-3-Clause
-golang.org/x/image,https://cs.opensource.google/go/x/image/+/v0.7.0:LICENSE,BSD-3-Clause
-golang.org/x/net,https://cs.opensource.google/go/x/net/+/v0.10.0:LICENSE,BSD-3-Clause
-golang.org/x/oauth2,https://cs.opensource.google/go/x/oauth2/+/v0.8.0:LICENSE,BSD-3-Clause
-golang.org/x/sync/syncmap,https://cs.opensource.google/go/x/sync/+/v0.2.0:LICENSE,BSD-3-Clause
-golang.org/x/sys,https://cs.opensource.google/go/x/sys/+/v0.8.0:LICENSE,BSD-3-Clause
-golang.org/x/text,https://cs.opensource.google/go/x/text/+/v0.9.0:LICENSE,BSD-3-Clause
+golang.org/x/crypto,https://cs.opensource.google/go/x/crypto/+/v0.17.0:LICENSE,BSD-3-Clause
+golang.org/x/image,https://cs.opensource.google/go/x/image/+/v0.15.0:LICENSE,BSD-3-Clause
+golang.org/x/net,https://cs.opensource.google/go/x/net/+/v0.19.0:LICENSE,BSD-3-Clause
+golang.org/x/oauth2,https://cs.opensource.google/go/x/oauth2/+/v0.15.0:LICENSE,BSD-3-Clause
+golang.org/x/sync/syncmap,https://cs.opensource.google/go/x/sync/+/v0.6.0:LICENSE,BSD-3-Clause
+golang.org/x/sys,https://cs.opensource.google/go/x/sys/+/v0.16.0:LICENSE,BSD-3-Clause
+golang.org/x/text,https://cs.opensource.google/go/x/text/+/v0.14.0:LICENSE,BSD-3-Clause
 gopkg.in/asn1-ber.v1,https://github.com/go-asn1-ber/asn1-ber/blob/f715ec2f112d/LICENSE,MIT
 gopkg.in/sourcemap.v1,https://github.com/go-sourcemap/sourcemap/blob/v1.0.5/LICENSE,BSD-2-Clause
 gopkg.in/warnings.v0,https://github.com/go-warnings/warnings/blob/v0.1.2/LICENSE,BSD-2-Clause

Some files were not shown because too many files changed in this diff