123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- /*
- ArOZ Online System - fsexec File System Asynchronize File Opertation Execution Instance
- This is a stand alone application design to replace the synchronize file operation designed since the start
- of the AOB project. By replacing the original file operation php script with this new script, the file explorer
- in AOB should be "freeze-free" while moving / copying large files.
- This application provide the following functions
- copy {from} {target}
- copy_folder {from} {target}
- delete {filename}
- move {from} {target}
- move_folder {from} {target}
- All the command should be stringify with JSON and encoded into base64, then pass into the command parameter of the
- application launching paramters.
- */
- package main
- import (
- "encoding/base64"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "os"
- "path"
- "path/filepath"
- "reflect"
- "time"
- )
- //Commonly used functions
- 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 showHelp() {
- fmt.Println("<<ArOZ Online System File System Freeze Script Executer>>")
- fmt.Println("Usage: ./fsexec {uuid} {command_in_base64}")
- }
- func decodeBase64(base64string string) string {
- l, err := base64.StdEncoding.DecodeString(base64string)
- if err != nil {
- panic(err)
- }
- return string(l)
- }
- func validateCopySourceAndTarget(from string, target string) bool {
- if !file_exists(from) {
- return false
- }
- if file_exists(target) {
- return false
- }
- return true
- }
- func getTimestamp() string {
- t := time.Now()
- return (t.Format("2006-01-02 150405"))
- }
- 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")
- } else if target == "error" {
- os.Rename(logfile, "log/error/"+uuid+".log")
- } else {
- //What happened?o
- panic("ERROR. Undefined log file sattle location.")
- }
- }
- func finishFileOperation(logfile string, uuid string) {
- //Finishing the file operation.
- writeLog(logfile, "[done] ", "Task finished successfully")
- moveLogFile(logfile, "done", uuid)
- fmt.Println("Done")
- }
- func initChk() {
- //Initiation Checking for all the required directories
- 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)
- }
- }
- //Main programming logic
- func main() {
- initChk()
- acceptOperations := []string{"copy", "copy_folder", "delete", "move", "move_folder"}
- if len(os.Args) == 1 {
- showHelp()
- return
- }
- //Get the command in using base64 and required log file uuid
- startSettings := os.Args[1:]
- uuid := startSettings[0]
- encodedCommand := startSettings[1]
- decodedCommand := decodeBase64(encodedCommand)
- filename := uuid + ".log"
- var command []string
- //Create the log file for this task
- logfile := "log/" + filename
- //Check if the given id exists already.
- if file_exists(logfile) || file_exists("log/done/"+filename) || file_exists("log/error/"+filename) {
- panic("ERROR. Required task already exists.")
- }
- //Create the log file for this task
- writeLog(logfile, "[init] ", "Task created on "+getTimestamp())
- 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 if the given file operation correct or not.
- correctOpr, _ := in_array(string(command[0]), acceptOperations)
- if !correctOpr {
- fmt.Println(string(command[0]))
- writeLog(logfile, "[error] ", "Invalid file operation. "+command[0]+" given.")
- moveLogFile(logfile, "error", uuid)
- panic("ERROR. Invalid file operation. " + command[0] + " given.")
- }
- writeLog(logfile, "[info] ", decodedCommand)
- //Start reading the command for file operations
- opr := command[0]
- if opr == "copy" {
- //Copy a given file to a given location
- from := command[1]
- target := command[2]
- if !validateCopySourceAndTarget(from, target) {
- writeLog(logfile, "[error] ", "Invalid source file or target directory.")
- moveLogFile(logfile, "error", uuid)
- panic("ERROR. Invalid source file or target directory.")
- }
- //Check if the parent dir exists
- dirname := path.Dir(target)
- if !file_exists(dirname) {
- os.MkdirAll(dirname, 0777)
- }
- Copy(from, target)
- finishFileOperation(logfile, uuid)
- } else if opr == "copy_folder" {
- //Copy a folder to a given location
- from := command[1]
- target := command[2]
- if !validateCopySourceAndTarget(from, target) {
- writeLog(logfile, "[error] ", "Invalid source file or target directory.")
- moveLogFile(logfile, "error", uuid)
- panic("ERROR. Invalid source file or target directory.")
- }
- Copy(from, target)
- finishFileOperation(logfile, uuid)
- } else if opr == "move" {
- //Move a file
- from := command[1]
- target := command[2]
- if !validateCopySourceAndTarget(from, target) {
- writeLog(logfile, "[error] ", "Invalid source file or target directory.")
- moveLogFile(logfile, "error", uuid)
- panic("ERROR. Invalid source file or target directory.")
- }
- err := os.Rename(from, target)
- if err != nil {
- writeLog(logfile, "[error] ", "Unable to move file due to unknown error.")
- moveLogFile(logfile, "error", uuid)
- panic("ERROR. Unable to move file due to unknown error.")
- }
- finishFileOperation(logfile, uuid)
- } else if opr == "move_folder" {
- //Move a folder
- from := command[1]
- target := command[2]
- if !validateCopySourceAndTarget(from, target) {
- writeLog(logfile, "[error] ", "Invalid source file or target directory.")
- moveLogFile(logfile, "error", uuid)
- panic("ERROR. Invalid source file or target directory.")
- }
- err := os.Rename(from, target)
- if err != nil {
- writeLog(logfile, "[error] ", "Unable to move folder due to unknown error.")
- moveLogFile(logfile, "error", uuid)
- panic("ERROR. Unable to move folder due to unknown error.")
- }
- finishFileOperation(logfile, uuid)
- }
- }
- //Program required external library. Included in main to prevent download on other building platform.
- //Recursive Copy Lib, not sure why it can't be imported like other module. Hence directly copy and paste in the section below.
- const (
- // tmpPermissionForDirectory makes the destination directory writable,
- // so that stuff can be copied recursively even if any original directory is NOT writable.
- // See https://github.com/otiai10/copy/pull/9 for more information.
- tmpPermissionForDirectory = os.FileMode(0755)
- )
- // Copy copies src to dest, doesn't matter if src is a directory or a file
- func Copy(src, dest string) error {
- info, err := os.Lstat(src)
- if err != nil {
- return err
- }
- return copy(src, dest, info)
- }
- // copy dispatches copy-funcs according to the mode.
- // Because this "copy" could be called recursively,
- // "info" MUST be given here, NOT nil.
- func copy(src, dest string, info os.FileInfo) error {
- if info.Mode()&os.ModeSymlink != 0 {
- return lcopy(src, dest, info)
- }
- if info.IsDir() {
- return dcopy(src, dest, info)
- }
- return fcopy(src, dest, info)
- }
- // fcopy is for just a file,
- // with considering existence of parent directory
- // and file permission.
- func fcopy(src, dest string, info os.FileInfo) error {
- if err := os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil {
- return err
- }
- f, err := os.Create(dest)
- if err != nil {
- return err
- }
- defer f.Close()
- if err = os.Chmod(f.Name(), info.Mode()); err != nil {
- return err
- }
- s, err := os.Open(src)
- if err != nil {
- return err
- }
- defer s.Close()
- _, err = io.Copy(f, s)
- return err
- }
- // dcopy is for a directory,
- // with scanning contents inside the directory
- // and pass everything to "copy" recursively.
- func dcopy(srcdir, destdir string, info os.FileInfo) error {
- originalMode := info.Mode()
- // Make dest dir with 0755 so that everything writable.
- if err := os.MkdirAll(destdir, tmpPermissionForDirectory); err != nil {
- return err
- }
- // Recover dir mode with original one.
- defer os.Chmod(destdir, originalMode)
- contents, err := ioutil.ReadDir(srcdir)
- if err != nil {
- return err
- }
- for _, content := range contents {
- cs, cd := filepath.Join(srcdir, content.Name()), filepath.Join(destdir, content.Name())
- if err := copy(cs, cd, content); err != nil {
- // If any error, exit immediately
- return err
- }
- }
- return nil
- }
- // lcopy is for a symlink,
- // with just creating a new symlink by replicating src symlink.
- func lcopy(src, dest string, info os.FileInfo) error {
- src, err := os.Readlink(src)
- if err != nil {
- return err
- }
- return os.Symlink(src, dest)
- }
|