package main import ( "fmt" "io/ioutil" "math" "os" "path" "path/filepath" "strconv" "strings" "github.com/FossoresLP/go-uuid-v4" ) func check(e error) { if e != nil { panic(e) } } //ArOZ PHP-Golang Bridge //The following sections remap the PHP functions to golang for the ease of development func file_exists(filepath string) bool { if _, err := os.Stat(filepath); !os.IsNotExist(err) { return true } return false } func mkdir(filepath string) { os.MkdirAll(filepath, os.ModePerm) } func file_put_contents(file string, data string) bool { f, err := os.Create(file) check(err) _, err = f.WriteString(data) defer f.Close() if err != nil { return false } return true } func file_get_contents(file string) string { b, err := ioutil.ReadFile(file) check(err) return string(b) } func strtolower(word string) string { return strings.ToLower(word) } func strtoupper(word string) string { return strings.ToUpper(word) } func trim(word string) string { return strings.Trim(word, " ") } func strlen(word string) int { return len(word) } func count(array []string) int { return len(array) } func explode(key string, word string) []string { return strings.Split(word, key) } func implode(key string, array []string) string { return strings.Join(array[:], key) } func str_replace(target string, result string, word string) string { return strings.Replace(word, target, result, -1) } func in_array(a string, list []string) bool { for _, b := range list { if b == a { return true } } return false } func strpos(word string, target string) int { return strings.Index(word, target) } func dirname(filepath string) string { return path.Dir(filepath) } func basename(filepath string) string { return path.Base(filepath) } //End of mapping functions //Utilities functions func genUUIDv4() string { uuid, err := uuid.NewString() check(err) return uuid } func padZeros(thisInt string, maxval int) string { targetLength := len(strconv.Itoa(maxval)) result := thisInt if len(thisInt) < targetLength { padzeros := targetLength - len(thisInt) for i := 0; i < padzeros; i++ { result = "0" + result } } return result } //End of utilities functions func init() { //Check if the required directory exists. If not, create it. if !file_exists("setting.config") { setting, err := os.Create("setting.config") check(err) defer setting.Close() setting.WriteString("") setting.Sync() } if !file_exists("chunks/") { mkdir("chunks/") } if !file_exists("uploads/") { mkdir("uploads/") } if !file_exists("index/") { mkdir("index/") } } func main() { //arozdfs implementation in Golang /* Supported commands: help --> show all the help information [Uploading to arozdfs commands] slice -infile --> declare the input file -storepath --> Relative path from the arozdfs root -slice --> declare the slicing filesize upload -push --> push to a list of clusters and sync file index to other clusters [Download from arozdfs commands] download -outfile --> rebuild a file from cluster storage to local drive open -storepath --> the file chunks tmp folder -uuid --> the uuid which the file is stored -outfile --> filepath for the exported and merged file [File Operations] remove --> remove all chunks related to thie file index rename --> rename all records related to this file move --> move the file to a new path in index directory [System checking commands] checkfile --> check if a file contains all chunks which has at least two copies of each chunks rebuild --> Check all files on the system and fix all chunks which has corrupted migrate */ //For each argument, start the processing switch functgroup := os.Args[1]; functgroup { case "help": showHelp() case "slice": startSlicingProc() case "upload": startUploadProc() case "download": startDownloadProc() case "open": openChunkedFile() case "debug": fmt.Println(padZeros("1", 32)) //Debug function. Change this line for unit testing default: showNotFound() } /* //Examples for using the Go-PHP bridge functions file_put_contents("Hello World.txt", "This is the content of the file.") fmt.Println(file_get_contents("Hello World.txt")) array := explode(",", "Apple,Orange,Pizza") fmt.Println(array) newstring := implode(",", array) fmt.Println(newstring) fmt.Println(in_array("Pizza", array)) fmt.Println(strpos(newstring, "Pizza")) fmt.Println(strtoupper("hello world")) fmt.Println(str_replace("Pizza", "Ramen", newstring)) */ } func startDownloadProc() { } func startSlicingProc() { storepath := "" infile := "" slice := 64 //Default 64MB per file chunk fileUUID := genUUIDv4() for i, arg := range os.Args { if strpos(arg, "-") == 0 { //This is a parameter defining keyword if arg == "-infile" { infile = os.Args[i+1] } else if arg == "-storepath" { storepath = os.Args[i+1] } else if arg == "-slice" { sliceSize, err := strconv.Atoi(os.Args[i+1]) check(err) slice = sliceSize } } } if storepath != "" && infile != "" { fmt.Println(storepath + " " + infile + " " + strconv.Itoa(slice) + " " + fileUUID) splitFileChunks(infile, "chunks/"+storepath+"/", fileUUID, slice) } else { fmt.Println("ERROR. Undefined storepath or infile.") } } func splitFileChunks(rawfile string, outputdir string, outfilename string, chunksize int) bool { if !file_exists(outputdir) { mkdir(outputdir) } fileToBeChunked := rawfile file, err := os.Open(fileToBeChunked) if err != nil { return false } defer file.Close() fileInfo, _ := file.Stat() var fileSize int64 = fileInfo.Size() var fileChunk = float64(chunksize * 1000 * 1000) // chunksize in MB // calculate total number of parts the file will be chunked into totalPartsNum := uint64(math.Ceil(float64(fileSize) / float64(fileChunk))) fmt.Printf("Splitting to %d pieces.\n", totalPartsNum) for i := uint64(0); i < totalPartsNum; i++ { partSize := int(math.Min(fileChunk, float64(fileSize-int64(i*uint64(fileChunk))))) partBuffer := make([]byte, partSize) file.Read(partBuffer) // write to disk fileName := outputdir + outfilename + "_" + padZeros(strconv.FormatUint(i, 10), int(totalPartsNum)) _, err := os.Create(fileName) if err != nil { return false } // write/save buffer to disk ioutil.WriteFile(fileName, partBuffer, os.ModeAppend) fmt.Println("Split to : ", fileName) } return true } func openChunkedFile() { storepath := "" uuid := "" outfile := "" for i, arg := range os.Args { if strpos(arg, "-") == 0 { //This is a parameter defining keyword if arg == "-uuid" { uuid = os.Args[i+1] } else if arg == "-storepath" { storepath = os.Args[i+1] } else if arg == "-outfile" { outfile = os.Args[i+1] } } } if storepath != "" && uuid != "" && outfile != "" { fmt.Println(storepath + " " + uuid + " " + outfile) joinFileChunks(storepath+"/"+uuid, outfile) } else { fmt.Println("ERROR. Undefined storepath, outfile or uuid.") } } func joinFileChunks(fileuuid string, outfilename string) bool { matches, _ := filepath.Glob(fileuuid + "_*") if len(matches) == 0 { fmt.Println("ERROR. No filechunk file for this uuid.") return false } outfile, err := os.Create(outfilename) if err != nil { return false } //For each file chunk, merge them into the output file for j := 0; j < len(matches); j++ { b, _ := ioutil.ReadFile(matches[j]) outfile.Write(b) } return true } func startUploadProc() { for i, arg := range os.Args { // print index and value fmt.Println("item", i, "is", arg) } } func showHelp() { } func showNotFound() { fmt.Println("ERROR. Command not found for function group: " + os.Args[1]) }