Parcourir la source

SystemAOB content added

Toby Chui il y a 6 ans
Parent
commit
e082383a33

BIN
put this in SystemAOB functions/arozdfs/arozdfs.exe


+ 116 - 0
put this in SystemAOB functions/arozdfs/autoConfig.php

@@ -0,0 +1,116 @@
+<?php
+include_once("../../../auth.php");
+//This is a generator for aroz system configuration files
+//Do not use this for configuration of user settings.
+if (isset($_GET['configName']) && $_GET['configName'] != ""){
+    //Generate configuration according to config name
+    //include_once($rootPath . "SystemAOB/functions/user/userIsolation.php");
+    //$configPath =  $userConfigDirectory . "SystemAOB/functions/personalization/" . $_GET['configName'] . ".config";
+    $configPath =  "config/" . $_GET['configName'] . ".config";
+    if (file_exists($configPath)){
+        //Config found in user directory. Go ahead and create UI for it.
+        $configContent = file_get_contents($configPath);
+        $config = json_decode($configContent);
+    }else{
+        die("ERROR. Config cannot be found.");
+    }
+}else{
+    die("ERROR. Undefined configName for dynamic template generation.");
+}
+?>
+<html>
+    <head>
+        <meta charset="UTF-8">
+        <link rel="stylesheet" href="../../../script/tocas/tocas.css">
+        <script type='text/javascript' src="../../../script/tocas/tocas.js"></script>
+        <script src="../../../script/jquery.min.js"></script>
+        <script src="../../../script/ao_module.js"></script>
+        <title><?php echo $_GET['configName']; ?> - AutoConfig</title>
+        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    </head>
+    <body>
+        <br>
+        <div class="ts container">
+        <div class="ts segment">
+            <form class="ts form" action="settingModifyHandler.php" method="POST">
+                <input style="display:none;" name="autoConfigBaseConfigurationFilename" type="text" value="<?php echo $_GET['configName'];?>">
+                <?php
+                    function fillInfo($dom, $name, $title, $description, $type, $defaultValue){
+                        $box = str_replace("{name}",$name,$dom);
+                        $box = str_replace("{title}",$title,$box);
+                        $box = str_replace("{description}",$description,$box);
+                        $box = str_replace("{type}",$type,$box);
+                        $box = str_replace("{defaultValue}",$defaultValue,$box);
+                        return $box;
+                    }
+                
+                    foreach ($config as $key => $value) {
+                        //For each config settings, render the template for this.
+                        $name = $key;
+                        $title = $value[0];
+                        $description = $value[1];
+                        $type = $value[2];
+                        $defaultValue = $value[3];
+                        
+                        if ($type == "boolean"){
+                            //Modify the option for checkbox
+                            if ($defaultValue == "true"){
+                                $defaultValue = "checked";
+                            }else{
+                                $defaultValue = "";
+                            }
+                        }
+                        
+                        
+                        //For each setting Type, load it from templates.
+                        if (file_exists("templates/$type.html")){
+                            echo fillInfo(file_get_contents("templates/$type.html"),$name,$title,$description,$type,$defaultValue);
+                        }else{
+                            echo "templates/$type.html" . " not found <br>";
+                        }
+                   }
+                   
+                ?>
+                <input type="submit" class="ts primary button" value="Update"></input>
+            </form>
+        </div>
+		<?php
+		if (isset($_GET['update'])){
+			echo '<div id="feedback" class="ts inverted positive segment" style="display:none;">
+						<p><i class="checkmark icon"></i>Configuration updated successfully</p>
+					</div>';
+		}
+		?>
+		<br><br>
+        <script>
+            var focusedInput = "";
+            //Allow for selecting a file in the system
+            function selectFile(object){
+                var objectUID = $(object).parent().find("input").attr("id");
+                focusedInput = objectUID;
+                if (ao_module_virtualDesktop){
+                    var uid = ao_module_utils.getRandomUID();
+                    ao_module_openFileSelector(uid,"addFileFromSelector",undefined,undefined,false);
+                }else{
+                    var uid = ao_module_utils.getRandomUID();
+                    ao_module_openFileSelectorTab(uid,"../../../",false,"file",addFileFromSelector);
+                }
+            }
+            
+            function addFileFromSelector(fileData){
+                result = JSON.parse(fileData);
+                for (var i=0; i < result.length; i++){
+                    var filename = result[i].filename;
+                    var filepath = result[i].filepath;
+                    $("#" + focusedInput).parent().find("input").val(filepath);
+                }
+            }
+			
+			$(document).ready(function(){
+				if ($("#feedback").length > 0){
+					$("#feedback").slideDown().delay(3000).slideUp();
+				}
+			});
+        </script>
+    </body>
+</html>

+ 0 - 0
put this in SystemAOB functions/arozdfs/checkToken.php


BIN
put this in SystemAOB functions/arozdfs/chunks/mv/68284d2c-cd3b-4f63-9431-a96f0767d8ce_0


BIN
put this in SystemAOB functions/arozdfs/chunks/mv/68284d2c-cd3b-4f63-9431-a96f0767d8ce_1


+ 1 - 0
put this in SystemAOB functions/arozdfs/clusterSetting.config

@@ -0,0 +1 @@
+{"prefix":"AOB","port":"80"}

+ 9 - 0
put this in SystemAOB functions/arozdfs/config/arozdfs.config

@@ -0,0 +1,9 @@
+{
+  "enablearozdfs": ["Enable ArOZDFS", "Enable ArOZ Distributed File Storage System", "boolean", true],
+  "enabledfcs": ["Auto File Chunk Size", "Allow system to dynamically adjust file chunking size depending on file size", "boolean", true],
+  "fixeddfcs": ["Default file chunk size (MB)", "Set the default file chunk size for the file chunking process. Default 64 (MB). This is only effective when 'Autp File Chunk Size' is disabled.","integer",64],
+  "allownologin": ["Allow no login upload","Allow unauthorized clients to upload file to the arozdfs storage pool.", "boolean",false],
+  "checkonlinebeforepush" : ["Check Cluster Online before Push","Perform a fast-ping check to see if target online or not before push. This might take extra preparation time before the push process starts","boolean",true],
+  "useextstorage": ["Use External Storage as Buffer","Store chunk buffer on external storage 1 (\/media\/storage1) instead of internal storage. Data will be lost if you remove the external storage when this option is enabled","boolean",false]
+  
+}

+ 13 - 0
put this in SystemAOB functions/arozdfs/delChunk.php

@@ -0,0 +1,13 @@
+<?php
+if (isset($_GET['chunkuuid']) && $_GET['chunkuuid'] != ""){
+	$storageDir = file_get_contents("storageDirectory.config");
+	if (file_exists($storageDir . str_replace("../","",$_GET['chunkuuid']))){
+		unlink($storageDir . str_replace("../","",$_GET['chunkuuid']));
+		echo "DONE";
+		exit(0);
+	}else{
+		die("ERROR. chunk with given uuid not found.");
+	}
+}
+
+?>

+ 730 - 0
put this in SystemAOB functions/arozdfs/main.go

@@ -0,0 +1,730 @@
+package main
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"math"
+	"mime/multipart"
+	"net/http"
+	"os"
+	"path"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"time"
+
+	"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(fullpath string) string {
+	return filepath.Base(fullpath)
+}
+
+//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
+
+}
+
+type clusterConfig struct {
+	Prefix string `json:"prefix"`
+	Port   string `json:"port"`
+}
+
+//End of utilities functions
+//System constants
+const clusterServices = "../cluster/"
+const delChunkScript = "SystemAOB/functions/arozdfs/delChunk.php?chunkuuid="
+const requestScript = "SystemAOB/functions/arozdfs/request.php?chunkuuid="
+const uploadScript = "SystemAOB/functions/arozdfs/upload.php"
+const clusterSetting = "clusterSetting.config"
+
+var config clusterConfig
+
+func init() {
+	//Check if the required directory exists. If not, create it.
+	if !file_exists("chunks/") {
+		mkdir("chunks/")
+	}
+	if !file_exists("uploads/") {
+		mkdir("uploads/")
+	}
+	if !file_exists("index/") {
+		mkdir("index/")
+	}
+	if !file_exists("tmp/") {
+		mkdir("tmp/")
+	}
+	if !file_exists("remoteDisks.config") {
+		file_put_contents("remoteDisks.config", "")
+	}
+
+	//Load config from clusterSetting.config
+	jsonFile, _ := os.Open(clusterSetting)
+	byteValue, _ := ioutil.ReadAll(jsonFile)
+	json.Unmarshal(byteValue, &config)
+}
+
+func main() {
+	//arozdfs implementation in Golang
+	//Refer to the help section for the usable commands and parameters
+
+	if len(os.Args) == 1 {
+		fmt.Println("ERROR. Undefined function group or operations. Type 'arozdfs help' for usage instructions. ")
+		return
+	}
+
+	//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 "remove":
+		removeFile()
+	case "debug":
+		fmt.Println(config.Port + "/" + config.Prefix) //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() {
+	vdir := ""
+	storepath := "tmp/"
+	for i, arg := range os.Args {
+		if strpos(arg, "-") == 0 {
+			//This is a parameter defining keyword
+			if arg == "-vdir" {
+				vdir = os.Args[i+1]
+			} else if arg == "-storepath" {
+				storepath = os.Args[i+1]
+				//Check if the storepath is end with /. if not, append it into the pathname
+				if storepath[len(storepath)-1:] != "/" {
+					storepath = storepath + "/"
+				}
+			}
+		}
+	}
+	if vdir != "" {
+		//Go ahead the download process and get the content of the file
+		fc := strings.Trim(str_replace("\r\n", "\n", file_get_contents("index/"+vdir+".index")), "\n")
+		datachunks := explode("\n", fc)
+		var filelist []string
+		var locations []string
+
+		for i := 0; i < len(datachunks); i++ {
+			tmp := explode(",", datachunks[i])
+			filechunk := tmp[0]
+			locationUUID := tmp[1]
+			filelist = append(filelist, filechunk)
+			thisip := resolveUUID(locationUUID)
+			clusterConfig := ":" + string(config.Port) + "/" + string(config.Prefix) + "/"
+			fullip := "http://" + thisip + clusterConfig
+			locations = append(locations, fullip)
+		}
+		//fmt.Println(filelist)
+		//fmt.Println(locations)
+
+		//Start the request process
+		for j := 0; j < len(filelist); j++ {
+			//Multithreading download for each fileitem
+			filename := filelist[j]
+			targetURL := locations[j] + requestScript + string(filename)
+			go downloadFileChunkWithOutput(storepath+filename, targetURL, filename)
+		}
+
+		fileUUID := explode("_", filelist[0])[0] //Getting the first part of a file with uuid, e.g. {uuid}_0 --> get only the {uuid} part
+		//Wait for the go routine to finish
+		downloadFinishIndicators, _ := filepath.Glob(storepath + fileUUID + "_*.done")
+		for len(downloadFinishIndicators) < len(filelist) {
+			time.Sleep(time.Duration(500) * time.Millisecond)
+			downloadFinishIndicators, _ = filepath.Glob(storepath + fileUUID + "_*.done")
+		}
+		//Clear up all indicators
+		for k := 0; k < len(downloadFinishIndicators); k++ {
+			os.Remove(downloadFinishIndicators[k])
+		}
+		fmt.Println("[OK] All chunks downloaded")
+	} else {
+		fmt.Println("ERROR. vdir cannot be empty")
+		os.Exit(0)
+	}
+}
+
+func downloadFileChunkWithOutput(filepath string, url string, filename string) {
+	if DownloadFile(filepath, url) {
+		fmt.Println("[OK] " + filename)
+		file_put_contents(filepath+".done", "")
+	}
+}
+
+func DownloadFile(filepath string, url string) bool {
+
+	// Get the data
+	resp, err := http.Get(url)
+	if err != nil {
+		return false
+	}
+	defer resp.Body.Close()
+
+	// Create the file
+	out, err := os.Create(filepath)
+	if err != nil {
+		return false
+	}
+	defer out.Close()
+	// Write the body to file
+	_, err = io.Copy(out, resp.Body)
+	return true
+
+}
+
+func startSlicingProc() {
+	infile := ""
+	slice := 64 //Default 64MB per file chunk
+	fileUUID := genUUIDv4()
+	storepath := fileUUID + "/"
+	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]
+				//Check if the storepath is end with /. if not, append it into the pathname
+				if storepath[len(storepath)-1:] != "/" {
+					storepath = storepath + "/"
+				}
+			} else if arg == "-slice" {
+				sliceSize, err := strconv.Atoi(os.Args[i+1])
+				check(err)
+				slice = sliceSize
+			}
+		}
+	}
+	if slice <= 0 {
+		fmt.Println("ERROR. slice size cannot be smaller or equal to 0")
+		os.Exit(0)
+	}
+	if storepath != "" && infile != "" {
+		//fmt.Println(storepath + " " + infile + " " + strconv.Itoa(slice) + " " + fileUUID)
+		splitFileChunks(infile, "chunks/"+storepath, fileUUID, slice)
+		//fmt.Println(fileUUID)
+	} 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 * 1024 * 1024) // chunksize in MB
+
+	// calculate total number of parts the file will be chunked into
+
+	totalPartsNum := uint64(math.Ceil(float64(fileSize) / float64(fileChunk)))
+	fmt.Printf("[Info] 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("[Export] ", fileName)
+	}
+	return true
+}
+
+func openChunkedFile() {
+	storepath := "tmp/"
+	uuid := ""
+	outfile := ""
+	removeAfterMerge := 0
+	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]
+				//Check if the storepath is end with /. if not, append it into the pathname
+				if storepath[len(storepath)-1:] != "/" {
+					storepath = storepath + "/"
+				}
+			} else if arg == "-outfile" {
+				outfile = os.Args[i+1]
+			} else if arg == "-c" {
+				//Remove the file chunks after the merging process
+				removeAfterMerge = 1
+			}
+		}
+	}
+	if storepath != "" && uuid != "" && outfile != "" {
+		//fmt.Println(storepath + " " + uuid + " " + outfile)
+		if joinFileChunks(storepath+uuid, outfile) {
+			//Do checksum here
+
+			//Remove all files if -c is used
+			if removeAfterMerge == 1 {
+				matches, _ := filepath.Glob(storepath + uuid + "_*")
+				for j := 0; j < len(matches); j++ {
+					os.Remove(matches[j])
+				}
+			}
+		} else {
+			fmt.Println("ERROR. Unable to merge file chunks.")
+		}
+	} 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() {
+	push := "remoteDisks.config"
+	storepath := "chunks/"
+	uuid := ""
+	vdir := ""
+	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]
+				//Check if the storepath is end with /. if not, append it into the pathname
+				if storepath[len(storepath)-1:] != "/" {
+					storepath = "chunks/" + storepath + "/"
+				}
+			} else if arg == "-vdir" {
+				vdir = os.Args[i+1]
+			} else if arg == "-push" {
+				//Remove the file chunks after the merging process
+				push = os.Args[i+1]
+			}
+		}
+	}
+	//Check if the input data are valid
+	if uuid == "" || vdir == "" {
+		fmt.Println("ERROR. Undefined uuid or vdir.")
+		os.Exit(0)
+	}
+	if !file_exists(clusterSetting) {
+		fmt.Println("ERROR. clusterSetting configuration not found")
+		os.Exit(0)
+	}
+	if file_exists("index/" + vdir + string(".index")) {
+		fmt.Println("ERROR. Given file already exists in vdir. Please use remove before uploading a new file on the same vdir location.")
+		os.Exit(0)
+	}
+
+	//Starting the uuid to ip conversion process
+
+	var ipList []string
+	var uuiddata []string
+	var uploadUUIDList []string
+	//Read cluster uuid list from remoteDisks.config
+	if file_exists(push) {
+		clusteruuids := file_get_contents(push)
+		if trim(clusteruuids) == "" {
+			fmt.Println("ERROR. remoteDisks not found or it is empty! ")
+			os.Exit(0)
+		}
+		clusteruuids = trim(strings.Trim(clusteruuids, "\n"))
+		uuiddata = explode("\n", clusteruuids)
+		//Generate iplist and ready for posting file chunks
+		for i := 0; i < len(uuiddata); i++ {
+			thisuuid := uuiddata[i%len(uuiddata)]
+			uploadUUIDList = append(uploadUUIDList, thisuuid)
+			thisip := resolveUUID(thisuuid)
+			clusterConfig := ":" + string(config.Port) + "/" + string(config.Prefix) + "/"
+			fullip := "http://" + thisip + clusterConfig
+			ipList = append(ipList, fullip)
+		}
+	} else {
+		fmt.Println("ERROR. remoteDisks not found or it is empty! ")
+		os.Exit(0)
+	}
+
+	//Handshake with clusters, create auth token if needed
+	if !createToken(ipList) {
+		fmt.Println("ERROR. Problem occured while trying to create token for one of the cluster's host. Upload process terminated.")
+		os.Exit(0)
+	}
+
+	//Ready to push. Create index file.
+	file_put_contents("index/"+vdir+string(".index"), "")
+	fileList, _ := filepath.Glob(storepath + uuid + "_*")
+	//Make a directory for storing the result of the upload
+	if !file_exists(storepath + ".upload/") {
+		mkdir(storepath + ".upload/")
+	}
+	for i := 0; i < len(fileList); i++ {
+		uploadIP := (ipList[i%len(ipList)])
+		uploadUUID := (uploadUUIDList[i%len(ipList)])
+		go SendPostRequest(uploadIP+uploadScript, fileList[i], "file", storepath+".upload/"+basename(fileList[i])+".done", uploadUUID)
+	}
+	//Retry for error chunks. Not implemented yet
+
+	//Wait for all upload process to end
+	uploadFinishIndicators, _ := filepath.Glob(storepath + ".upload/" + uuid + "_*.done")
+	for len(uploadFinishIndicators) < len(fileList) {
+		time.Sleep(time.Duration(500) * time.Millisecond)
+		uploadFinishIndicators, _ = filepath.Glob(storepath + ".upload/" + uuid + "_*.done")
+	}
+
+	//Write the upload results to index file
+	for j := 0; j < len(uploadFinishIndicators); j++ {
+		f, _ := os.OpenFile("index/"+vdir+string(".index"), os.O_APPEND|os.O_WRONLY, 0600)
+		defer f.Close()
+		f.WriteString(str_replace(".done", "", basename(uploadFinishIndicators[j])))
+		f.WriteString(",")
+		f.WriteString(file_get_contents(uploadFinishIndicators[j]))
+		f.WriteString("\n")
+	}
+
+	//Clear up all indicators
+	for k := 0; k < len(uploadFinishIndicators); k++ {
+		os.Remove(uploadFinishIndicators[k])
+	}
+	os.Remove(storepath + ".upload/")
+
+	fmt.Println("[OK] All chunks uploaded.")
+}
+
+func createToken(ipList []string) bool {
+	//Not implemented
+	return true
+}
+
+func resolveUUID(uuid string) string {
+	tmp := []byte(uuid)
+	uuid = string(bytes.Trim(tmp, "\xef\xbb\xbf"))
+	uuid = strings.Trim(strings.Trim(uuid, "\n"), "\r")
+	if file_exists(clusterServices + "mappers/") {
+		if file_exists(clusterServices + "/mappers/" + uuid + ".inf") {
+			return file_get_contents(clusterServices + "/mappers/" + uuid + ".inf")
+		} else {
+			fmt.Println("ERROR. UUID not found. Please perform a scan first before using arozdfs functions")
+		}
+	} else {
+		fmt.Println("ERROR. Unable to resolve UUID to IP: cluster services not found. Continuing with UUID as IP address.")
+
+	}
+	return uuid
+}
+
+func SendPostRequest(url string, filename string, fieldname string, resultName string, targetUUID string) []byte {
+	file, err := os.Open(filename)
+
+	if err != nil {
+		panic(err)
+	}
+	defer file.Close()
+
+	body := &bytes.Buffer{}
+	writer := multipart.NewWriter(body)
+	part, err := writer.CreateFormFile(fieldname, filepath.Base(file.Name()))
+
+	if err != nil {
+		panic(err)
+	}
+
+	io.Copy(part, file)
+	writer.Close()
+	request, err := http.NewRequest("POST", url, body)
+
+	if err != nil {
+		panic(err)
+	}
+
+	request.Header.Add("Content-Type", writer.FormDataContentType())
+	client := &http.Client{}
+
+	response, err := client.Do(request)
+
+	if err != nil {
+		panic(err)
+	}
+	defer response.Body.Close()
+
+	content, err := ioutil.ReadAll(response.Body)
+
+	if err != nil {
+		panic(err)
+	}
+
+	//Upload suceed. Create a .done file to indicate this file is done uploading
+	file_put_contents(resultName, string(targetUUID))
+	return content
+}
+
+func removeFile() {
+	fileindex := ""
+	if len(os.Args) == 3 {
+		fileindex = os.Args[2]
+	}
+	if fileindex == "" {
+		fmt.Println("ERROR. undefined file index. Usage: arozdfs file.ext (Root as ./index)")
+		os.Exit(0)
+	}
+
+	indexFileRealpath := "index/" + fileindex + ".index"
+	if !file_exists(indexFileRealpath) {
+		fmt.Println("ERROR. fileindex not found in " + indexFileRealpath)
+		os.Exit(0)
+	}
+
+	//Everything checked and go ahead to load the list into variables
+	var filelist []string
+	var targetUUIDs []string
+	fc := strings.Trim(str_replace("\r\n", "\n", file_get_contents(indexFileRealpath)), "\n")
+	datachunks := explode("\n", fc)
+	for i := 0; i < len(datachunks); i++ {
+		thisChunk := datachunks[i]
+		thisChunk = strings.Trim(strings.Trim(thisChunk, "\n"), "\r")
+		chunkdata := explode(",", thisChunk)
+		filelist = append(filelist, chunkdata[0])
+		targetUUIDs = append(targetUUIDs, "http://"+resolveUUID(chunkdata[1])+":"+config.Port+"/"+config.Prefix+"/")
+	}
+
+	//fmt.Println(filelist)
+	//fmt.Println(targetUUIDs)
+
+	//Remove the chunks on each endpoints
+	failed := len(filelist)
+	var failedChunk []string
+	for j := 0; j < len(filelist); j++ {
+		targetEndpoint := targetUUIDs[j] + delChunkScript + filelist[j]
+		resp, err := http.Get(targetEndpoint)
+		if err != nil {
+			// handle error
+			fmt.Println("ERROR. Unable to connect to endpoint: " + targetEndpoint + ". Continue with the rest of the endpoints.")
+		}
+		body, _ := ioutil.ReadAll(resp.Body)
+		fmt.Println("[REPLY] " + string(body) + " for " + filelist[j])
+		if trim(string(body)) == "DONE" {
+			failed--
+		} else {
+			failedChunk = append(failedChunk, filelist[j])
+		}
+		resp.Body.Close()
+	}
+	if failed == 0 {
+		fmt.Println("[OK] All file chunks has been removed from the clusters")
+		os.Remove(indexFileRealpath)
+	} else {
+		fmt.Println("[WARNING] Unable to remove at least one chunks from cluster. Index file is not removed.")
+		fmt.Println(failedChunk)
+	}
+
+}
+
+func showHelp() {
+	fmt.Println(`[arozdfs - Distributed File Storage Management Tool for ArOZ Online Cloud System]
+	This is a command line tool build for the ArOZ Online distributed cloud platform file chunking and redundant data storage. 
+	Please refer to the ArOZ Online Documentaion for more information.
+	`)
+	fmt.Println(`Supported commands:
+	help --> show all the help information
+
+	[Uploading to arozdfs commands]
+	slice
+	-infile <filename> --> declare the input file
+	-slice <filesize> --> declare the slicing filesize
+	-storepath <pathname> (Optional) --> Relative path for storing the sliced chunk files, default ./{file-uuid}
+
+	upload
+	-storepath <pathname> --> The location where the file chunks are stored, root start at ./chunks, not recommend for leaving this empty
+	-uuid <file uuid> --> uuid of the file to be uploaded
+	-vdir <file.index> --> where the file.index should be stored. (Use for file / folder navigation)
+	-push <remoteDisks.config> (Optional) --> push to a list of clusters and sync file index to other clusters, default ./remoteDisks.config
+
+	[Download from arozdfs commands]
+	download
+	-vdir <file.index> --> file.index location
+	-storepath <tmp directory> (Optional) --> define a special directory for caching the downloaded data chunks, default ./tmp
+
+	open
+	-uuid <file uuid> --> the uuid which the file is stored
+	-outfile <filename> --> filepath for the exported and merged file
+	-storepath <tmp directory> (Optional)--> the file chunks tmp folder, default ./tmp
+	-c (Optional) --> remove all stored file chunks after merging the file chunks.
+
+	[File Operations]
+	remove <file.index> --> remove all chunks related to this file index
+	rename <file.index> <newfile.index> --> rename all records related to this file
+	move <filepath/file.index> <newpath/file.index> --> move the file to a new path in index directory
+
+
+	[System checking commands]
+	checkfile <file.index> --> 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 <remoteDisks.config> --> Move all chunks from this host to other servers in the list.`)
+}
+
+func showNotFound() {
+	fmt.Println("ERROR. Command not found: " + os.Args[1])
+}

+ 2 - 0
put this in SystemAOB functions/arozdfs/remoteDisks.config

@@ -0,0 +1,2 @@
+9f269d38-07c4-460e-b477-26066e59f1c9
+aa2acf42-d0b9-4441-8351-7fa84a5dc26d

+ 23 - 0
put this in SystemAOB functions/arozdfs/request.php

@@ -0,0 +1,23 @@
+<?php
+//Include auth here
+//To be implemented
+include_once("checkToken.php");
+$storageDir = file_get_contents("storageDirectory.config");
+if (in_array("mod_xsendfile",apache_get_modules())){
+	if (isset($_GET['chunkuuid'])){
+		$path = str_replace("../","",$storageDir . $_GET['chunkuuid']);
+		if (file_exists($path)){
+			header("X-Sendfile: $path");
+			header("Content-Type: application/octet-stream");
+			header("Content-Disposition: attachment; filename=\"$path\"");
+			exit;
+		}else{
+			die("ERROR. File not exists.");
+		}
+	}
+}else{
+	die("ERROR. mod_xsendfile not installed and it is required.");
+}
+
+
+?>

+ 31 - 0
put this in SystemAOB functions/arozdfs/settingModifyHandler.php

@@ -0,0 +1,31 @@
+<?php
+include_once("../../../auth.php");
+$configName = $_POST["autoConfigBaseConfigurationFilename"];
+if (!file_exists("config/" . $configName . ".config")){
+	die("ERROR. Required config file not found in default config setting directory.");
+}
+$config = file_get_contents("config/" . $configName . ".config");
+$config = json_decode($config,true);
+//As checkbox will not pass through values, default values for all boolean should be false.
+foreach ($config as $key => $value) {
+	if ($config[$key][2] == "boolean"){
+		$config[$key][3] = "false";
+	}
+}
+foreach ($_POST as $key => $value) {
+	if ($key != "autoConfigBaseConfigurationFilename"){
+		//This is not the system defined config value. Write the rest of the content in.
+		if ($config[$key][2] == "boolean"){
+			//This is boolean. Change this from "on" to "true" if this value received
+			$config[$key][3] = "true";
+		}else{
+			$config[$key][3] = $value;
+		}
+	}
+}
+
+file_put_contents("config/" . $configName . ".config",json_encode($config));
+header("Location: autoConfig.php?configName=" . $configName . "&update=" . time());
+exit(0);
+
+?>

+ 1 - 0
put this in SystemAOB functions/arozdfs/storageDirectory.config

@@ -0,0 +1 @@
+storage/

+ 7 - 0
put this in SystemAOB functions/arozdfs/templates/boolean.html

@@ -0,0 +1,7 @@
+<div class="field">
+	<div class="ts toggle checkbox">
+		<input type="checkbox" id="{name}" name="{name}" {defaultValue}>
+		<label for="{name}">{title}</label>
+	</div>
+	<small>{description}</small>
+</div>

+ 5 - 0
put this in SystemAOB functions/arozdfs/templates/html.html

@@ -0,0 +1,5 @@
+<div class="field">
+	<label>{title}</label>
+	<textarea id="{name}" name="{name}" rows="5">{defaultValue}</textarea>
+	<small>{description} (Text and HTML only)</small>
+</div>

+ 7 - 0
put this in SystemAOB functions/arozdfs/templates/integer.html

@@ -0,0 +1,7 @@
+<div class="field">
+	<label>{title}</label>
+	<div class="ts fluid input">
+		<input id="{name}" name="{name}" type="number" value="{defaultValue}">
+	</div>
+	<small>{description} (Integer only)</small>
+</div>

+ 7 - 0
put this in SystemAOB functions/arozdfs/templates/text.html

@@ -0,0 +1,7 @@
+<div class="field">
+	<label>{title}</label>
+	<div class="ts fluid input">
+		<input id="{name}" name="{name}" type="text" value="{defaultValue}">
+	</div>
+	<small>{description} (Text only)</small>
+</div>

+ 62 - 0
put this in SystemAOB functions/arozdfs/upload.php

@@ -0,0 +1,62 @@
+<?php
+header('Access-Control-Allow-Origin: *');
+include_once("checkToken.php");
+//Create the storage directory if not exists
+$storageDir = trim(file_get_contents("storageDirectory.config"));
+if (!file_exists($storageDir)){
+	mkdir($storageDir,0777,true);
+}
+
+//Check if the GET variable for username and password is valid
+/*
+if (isset($_GET['username']) && $_GET['username'] != "" && isset($_GET['usrpw']) && $_GET['usrpw'] != ""){
+	$username = $_GET['username'];
+	$pw = hash('sha512', $_GET['usrpw']);
+	$pw = trim(strtoupper($pw));
+}else{
+	die("ERROR. Unable to perform auth process.");
+}
+*/
+//Check where is the config file located without auth.php
+if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+	$sysConfigDir = "C:/AOB/";
+}else{
+	$sysConfigDir = "/etc/AOB/";
+}
+if (file_exists("../../../root.inf") && filesize("../../../root.inf") > 0){
+	//This user uses a specially defined path for directory
+	$sysConfigDir = file_get_contents("../../../root.inf");
+}
+
+//Handle authentication
+/*
+$authFile = $sysConfigDir . "whitelist.config";
+$db = file_get_contents($authFile);
+$db = trim($db);
+$db = explode("\n",$db);
+$valudUser = false;
+foreach ($db as $item){
+	$item = trim($item);
+	$data = explode(",",$item);
+	if ($data[0] == $username && $data[1] == $pw){
+		$valudUser = true;
+	}
+}
+
+if (!$valudUser){
+	die("ERROR. Incorrect username or password." . $pw);
+}
+*/
+//Upload handling code
+$target_dir = $storageDir;
+$target_file = $target_dir . basename($_FILES["file"]["name"]);
+if (strpos($target_file,".") !== false){
+	die("ERROR. You cannot upload non-file chunks here");
+}
+// Check if image file is a actual image or fake image
+if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) {
+	echo "DONE";
+} else {
+	echo "ERROR. Unable to move uploaded files. Is your hard drive fulled?";
+}
+?>