Toby Chui 6 yıl önce
ebeveyn
işleme
6f1806cf31
6 değiştirilmiş dosya ile 357 ekleme ve 1 silme
  1. 39 1
      README.md
  2. 5 0
      example command.txt
  3. BIN
      fszip.exe
  4. 313 0
      main.go
  5. BIN
      title.png
  6. BIN
      title.psd

+ 39 - 1
README.md

@@ -1,3 +1,41 @@
 # fszip
 
-ArOZ Online File System Zipping Application, design to replace the legacy zipping PHP script.
+ArOZ Online System File Explorer - File System Zipping Backgroundworker, design to replace the legacy zipping PHP script.
+
+## What is File System Zipping Backgroundworker?
+
+File System Zipping Backgroundworker - Short for fszip, is a backgound working script that is design to replace the current
+PHP based zipping method used by the file explorer. This work similar to fsexec with asynchonized design to prevent the main
+PHP server from freezing due to the zipping process. This is particularly useful on low power host like the Raspberry Pi Zero
+series. 
+
+## How can I use the fszip?
+Although we strongly recommend using the fszip via file explorer API, you can call the binary directly with the following command.
+
+```
+./fsexec {uuid} {command_in_base64_encoded_JSON_string}
+```
+The command has to be in one of the format that fits the following rule
+
+```
+// Command Structure:
+// [{"zip" / "unzip", "{source}", "{target}"]
+
+//Examples
+//["zip","test","test.zip"]
+//Zip the folder "test" into "test.zip"
+
+./fszip uuid1 WyJ6aXAiLCJ0ZXN0IiwidGVzdC56aXAiXQo=
+
+//["unzip","test.zip","unzip"]
+//Unzip the folder "test.zip" to unzip/
+
+./fszip uuid2 WyJ1bnppcCIsInRlc3QuemlwIiwidW56aXAiXQo=
+
+```
+
+## Log file and command conversion detail
+Please take a look at fsexec's README file for more examples.
+
+## License
+CopyRight Author Toby Chui under ArOZ Online Project, 2019

+ 5 - 0
example command.txt

@@ -0,0 +1,5 @@
+["zip","test","test.zip"]
+WyJ6aXAiLCJ0ZXN0IiwidGVzdC56aXAiXQo=
+
+["unzip","test.zip","unzip"]
+WyJ1bnppcCIsInRlc3QuemlwIiwidW56aXAiXQo=

BIN
fszip.exe


+ 313 - 0
main.go

@@ -0,0 +1,313 @@
+package main
+
+import (
+	"archive/zip"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"path"
+	"path/filepath"
+	"reflect"
+	"strings"
+	"time"
+)
+
+func in_array(val interface{}, array interface{}) (exists bool, index int) {
+	exists = false
+	index = -1
+
+	switch reflect.TypeOf(array).Kind() {
+	case reflect.Slice:
+		s := reflect.ValueOf(array)
+
+		for i := 0; i < s.Len(); i++ {
+			if reflect.DeepEqual(val, s.Index(i).Interface()) == true {
+				index = i
+				exists = true
+				return
+			}
+		}
+	}
+
+	return
+}
+
+func file_exists(path string) bool {
+	if _, err := os.Stat(path); os.IsNotExist(err) {
+		return false
+	}
+	return true
+}
+
+func file_get_contents(path string) string {
+	dat, err := ioutil.ReadFile(path)
+	if err != nil {
+		panic("Unable to read file: " + path)
+	}
+	return (string(dat))
+
+}
+
+func writeLog(filepath string, prefix string, message string) bool {
+	f, err := os.OpenFile(filepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+	if err != nil {
+		log.Println(err)
+	}
+	defer f.Close()
+
+	logger := log.New(f, prefix, log.LstdFlags)
+	logger.Println(message)
+	return true
+}
+
+func compress(source, target string) error {
+	zipfile, err := os.Create(target)
+	if err != nil {
+		return err
+	}
+	defer zipfile.Close()
+
+	archive := zip.NewWriter(zipfile)
+	defer archive.Close()
+
+	info, err := os.Stat(source)
+	if err != nil {
+		return nil
+	}
+
+	var baseDir string
+	if info.IsDir() {
+		baseDir = filepath.Base(source)
+	}
+
+	filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+
+		header, err := zip.FileInfoHeader(info)
+		if err != nil {
+			return err
+		}
+
+		if baseDir != "" {
+			header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
+		}
+
+		if info.IsDir() {
+			header.Name += "/"
+		} else {
+			header.Method = zip.Deflate
+		}
+
+		writer, err := archive.CreateHeader(header)
+		if err != nil {
+			return err
+		}
+
+		if info.IsDir() {
+			return nil
+		}
+
+		file, err := os.Open(path)
+		if err != nil {
+			return err
+		}
+		defer file.Close()
+		_, err = io.Copy(writer, file)
+		return err
+	})
+
+	return err
+}
+
+func unzip(archive, target string) error {
+	reader, err := zip.OpenReader(archive)
+	if err != nil {
+		return err
+	}
+
+	if err := os.MkdirAll(target, 0755); err != nil {
+		return err
+	}
+
+	for _, file := range reader.File {
+		path := filepath.Join(target, file.Name)
+		if file.FileInfo().IsDir() {
+			os.MkdirAll(path, file.Mode())
+			continue
+		}
+
+		fileReader, err := file.Open()
+		if err != nil {
+			return err
+		}
+		defer fileReader.Close()
+
+		targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
+		if err != nil {
+			return err
+		}
+		defer targetFile.Close()
+
+		if _, err := io.Copy(targetFile, fileReader); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func getTimestamp() string {
+	t := time.Now()
+	return (t.Format("2006-01-02 150405"))
+}
+
+func decodeBase64(base64string string) string {
+	l, err := base64.StdEncoding.DecodeString(base64string)
+	if err != nil {
+		panic(err)
+	}
+	return string(l)
+}
+func moveLogFile(logfile string, target string, uuid string) {
+	//If then else is used to prevent invalid move target
+	if target == "done" {
+		os.Rename(logfile, "log/done/"+uuid+".log")
+		os.Chmod("log/done/"+uuid+".log", 0777) //Unlock the file for read write from php
+	} else if target == "error" {
+		os.Rename(logfile, "log/error/"+uuid+".log")
+		os.Chmod("log/error/"+uuid+".log", 0777) //Unlock the file for read write from php
+	} else {
+		//What happened?
+		panic("ERROR. Undefined log file sattle location.")
+	}
+
+}
+
+func finishFileOperation(logfile string, uuid string) {
+	//Finishing the file operation.
+	//time.Sleep(20000 * time.Millisecond) //Added this line for debug purpose
+	writeLog(logfile, "[done] ", "Task finished successfully")
+	moveLogFile(logfile, "done", uuid)
+	fmt.Println("Done")
+}
+
+func isDir(path string) bool {
+	file, _ := os.Open(path)
+	if fi, err := file.Stat(); err != nil || fi.IsDir() {
+		return true
+	}
+	file.Close()
+	return false
+}
+
+func raiseError(logfile string, uuid string, errMsg string) {
+	writeLog(logfile, "[error] ", errMsg)
+	moveLogFile(logfile, "error", uuid)
+	panic("ERROR. " + errMsg)
+}
+
+func main() {
+	//Init the log folder if it doesn't exists
+	if !file_exists("log/") {
+		os.MkdirAll("log/", 0777)
+	}
+	if !file_exists("log/done/") {
+		os.MkdirAll("log/done/", 0777)
+	}
+	if !file_exists("log/error/") {
+		os.MkdirAll("log/error/", 0777)
+	}
+	//Check argument if satisfied
+	if len(os.Args) < 3 {
+		fmt.Println("<<ArOZ Online System File System Compress File Creator>>")
+		fmt.Println("Usage: fszip {uuid} {command_in_base64_JSON}")
+		fmt.Println("Command must be an array containing [{'zip' / 'unzip'},{filepath},{zip_target}]")
+		return
+	}
+	startSettings := os.Args[1:]
+	uuid := startSettings[0]
+	encodedCommand := startSettings[1]
+	decodedCommand := decodeBase64(encodedCommand)
+	filename := uuid + ".log"
+	logfile := "log/" + filename
+	var command []string
+	//Check if the given uuid already exists. If yes, terminate the execution
+	if file_exists("log/"+uuid+".log") || file_exists("log/done/"+uuid+".log") || file_exists("log/error/"+uuid+".log") {
+		panic("ERROR. Given uuid already exists.")
+	}
+	//Create the log file for this task
+	writeLog(logfile, "[init] ", "Task created on "+getTimestamp())
+	//Parse the JSON string into readable array
+	err := json.Unmarshal([]byte(decodedCommand), &command)
+	if err != nil {
+		writeLog(logfile, "[error] ", "Unable to parse JSON string.")
+		moveLogFile(logfile, "error", uuid)
+		panic("ERROR. Unable to parse JSON string.")
+	}
+
+	//Check opr
+	if command[0] == "zip" {
+		//Start the compression process for the given path
+		//Command structure: ["zip","{source}","{target} (Pass in empty string for default location)"]
+		//Check if the given filepath exists
+		if !file_exists(command[1]) {
+			raiseError(logfile, uuid, "Source not exists.")
+		}
+		inpath := command[1]
+		//Check if inpath end with "/". If yes, remove it
+		if inpath[len(inpath)-1:] == "/" {
+			inpath = inpath[0 : len(inpath)-1]
+		}
+		outpath := command[2]
+		//File exists. Check if it is a folder or not.
+		if outpath != "" {
+			//If there is a defined export filepath, check if the parent dir exists. If not, create it
+			if !file_exists(path.Dir(outpath)) {
+				os.MkdirAll(path.Dir(outpath), 0755)
+			}
+		} else {
+			//There is no defined export path. Export next to the source as zip.
+			if isDir(command[1]) {
+				outpath = path.Dir(path.Dir(inpath)) + "/" + path.Base(inpath) + ".zip"
+			} else {
+				outpath = path.Dir(inpath) + "/" + strings.TrimSuffix(inpath, filepath.Ext(inpath)) + ".zip"
+			}
+		}
+		if file_exists(outpath) {
+			raiseError(logfile, uuid, "Output file already exists.")
+		}
+		compress(inpath, outpath)
+		finishFileOperation(logfile, uuid)
+	} else if command[0] == "unzip" {
+		//Unzip a given filepath
+		//command structure: ["unzip","{source}","{target}"]
+		if !file_exists(command[1]) {
+			raiseError(logfile, uuid, "Source not exists.")
+		}
+
+		inpath := command[1]
+		outpath := command[2]
+		if outpath == "" {
+			//If unzup target is empty string, unzip to the current directory which the script is executed
+			outpath = "./"
+		}
+		//Check if the input path is a zip file. If not, post a warning into the log file
+		if filepath.Ext(inpath) != ".zip" {
+			writeLog(logfile, "[warning] ", "The given file might not be a zip file. Trying to open it anyway. File ext given: "+filepath.Ext(inpath))
+		}
+		//Create outpath if it doesn't exists
+		if !file_exists(outpath) {
+			os.MkdirAll(outpath, 0755)
+		}
+
+		unzip(inpath, outpath)
+		finishFileOperation(logfile, uuid)
+	}
+
+}

BIN
title.png


BIN
title.psd