diff --git a/.gitignore b/.gitignore index 2f18747..079b514 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,9 @@ bin pkg out .idea -gsyncd.iml \ No newline at end of file +gsyncd.iml +build +.env +/Godeps +/vendor +/demo \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a58eb1f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM busybox:ubuntu-14.04 +MAINTAINER CausticLab + +ENV FILESYNC_RELEASE v0.0.1 + +ADD https://github.com/CausticLab/filesync/releases/download/${RGON_EXEC_RELEASE}/filesync-linux-amd64.tar.gz /tmp/filesync.tar.gz +RUN tar -zxvf /tmp/filesync -C /usr/local/bin \ + && mv /usr/local/bin/filesync-linux-amd64 /usr/local/bin/filesync \ + && chmod +x /usr/local/bin/filesync \ + && rm /tmp/filesync +RUN mkdir /share + +ENTRYPOINT ["/usr/local/bin/filesync"] \ No newline at end of file diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..9370a1a --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,8 @@ +FROM busybox:ubuntu-14.04 +MAINTAINER CausticLab + +ADD build/filesync-linux-amd64 /usr/local/bin/filesync +RUN chmod +x /usr/local/bin/filesync +RUN mkdir /share + +ENTRYPOINT ["/usr/local/bin/filesync"] \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..835790c --- /dev/null +++ b/Makefile @@ -0,0 +1,89 @@ +# These env vars have to be set in the CI +# GITHUB_TOKEN +# DOCKER_HUB_TOKEN + +.PHONY: build deps test release clean push image ci-compile build-dir ci-dist dist-dir ci-release version help + +PROJECT := filesync +PLATFORM := linux +ARCH := amd64 +DOCKER_IMAGE := causticlab/$(PROJECT) + +VERSION := $(shell cat VERSION) +GITSHA := $(shell git rev-parse --short HEAD) + +all: help + +help: + @echo "make build - build binary for the target environment" + @echo "make deps - install build dependencies" + @echo "make vet - run vet & gofmt checks" + @echo "make test - run tests" + @echo "make clean - Duh!" + @echo "make release - tag with version and trigger CI release build" + @echo "make image - build release image" + @echo "make dev-image - build development image" + @echo "make dockerhub - build and push image to Docker Hub" + @echo "make version - show app version" + +build: build-dir + CGO_ENABLED=1 GOOS=$(PLATFORM) GOARCH=$(ARCH) godep go build -ldflags "-X main.Version=$(VERSION) -X main.GitSHA=$(GITSHA)" -o build/$(PROJECT)-$(PLATFORM)-$(ARCH) -v + +deps: + go get golang.org/x/sys/unix + go get github.com/tools/godep + go get github.com/mattn/go-sqlite3 + go get github.com/bitly/go-simplejson + go get github.com/howeyc/fsnotify + go get github.com/codegangsta/martini + go get github.com/codegangsta/martini-contrib/encoder + godep save + +release: + git tag `cat VERSION` + git push origin master --tags + +clean: + go clean + rm -fr ./build + rm -fr ./dist + +dockerhub: image + @echo "Pushing $(DOCKER_IMAGE):$(VERSION)" + docker push $(DOCKER_IMAGE):$(VERSION) + +image: + docker build -t $(DOCKER_IMAGE):$(VERSION) -f Dockerfile . + +dev-image: + docker build -t $(DOCKER_IMAGE):dev -f Dockerfile.dev . + +version: + @echo $(VERSION) $(GITSHA) + +ci-compile: build-dir + CGO_ENABLED=1 GOOS=$(PLATFORM) GOARCH=$(ARCH) go build -ldflags "-X main.Version=$(VERSION) -X main.GitSHA=$(GITSHA) -w -s" -a -o build/$(PROJECT)-$(PLATFORM)-$(ARCH)/$(PROJECT) + +build-dir: + @rm -rf build && mkdir build + +dist-dir: + @rm -rf dist && mkdir dist + +ci-dist: ci-compile dist-dir + $(eval FILES := $(shell ls build)) + @for f in $(FILES); do \ + (cd $(shell pwd)/build/$$f && tar -cvzf ../../dist/$$f.tar.gz *); \ + (cd $(shell pwd)/dist && shasum -a 256 $$f.tar.gz > $$f.sha256); \ + (cd $(shell pwd)/dist && md5sum $$f.tar.gz > $$f.md5); \ + echo $$f; \ + done + @cp -r $(shell pwd)/dist/* $(CIRCLE_ARTIFACTS) + ls $(CIRCLE_ARTIFACTS) + +ci-release: + @previous_tag=$$(git describe --abbrev=0 --tags $(VERSION)^); \ + comparison="$$previous_tag..HEAD"; \ + if [ -z "$$previous_tag" ]; then comparison=""; fi; \ + changelog=$$(git log $$comparison --oneline --no-merges --reverse); \ + github-release $(CIRCLE_PROJECT_USERNAME)/$(CIRCLE_PROJECT_REPONAME) $(VERSION) master "**Changelog**
$$changelog" 'dist/*' diff --git a/README.md b/README.md index 34d3345..6078140 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,115 @@ -Filesync -=== +# Filesync + Filesync is a utility written in Golang which helps you to keep the files on the client up to date with the files on the server. Only the changed parts of files on the server are downloaded. Therefore it's great to synchronize your huge, and frequently changing files. -Installation -=== -`go get github.com/elgs/filesync/gsync` - -Server -=== -Run ---- -`gsync server.json` -Configuration ---- -server.json -```json -{ - "mode": "server", - "ip": "0.0.0.0", - "port": 6776, - "monitors": { - "home_elgs_desktop_a": "/home/elgs/Desktop/a", - "home_elgs_desktop_b": "/home/elgs/Desktop/b" - } -} -``` - - -Client -=== -Run ---- -`gsync client.json` -Configuration ---- -client.json -```json -{ - "mode": "client", - "ip": "127.0.0.1", - "port": 6776, - "monitors": { - "home_elgs_desktop_a": "/home/elgs/Desktop/c", - "home_elgs_desktop_b": "/home/elgs/Desktop/d" - } -} +Forked from github.com/elgs/filesync/gsync + +## Requirements + +Needs access to `glibc` to compile properly, and so `busybox:ubuntu-14.04` is the selected base image. + +## Local Usage + +Install dependencies: + +```sh +make deps +``` + +Run locally with config files (modify paths before running): + +```sh +# Server +go run gsync.go gsync/server.json + +# Client +go run gsync.go gsync/client.json +``` + +Alternatively, set environment variables (examples in [/.env](/.env)): + +```sh +# Server +export FILESYNC_MODE=server +export FILESYNC_PORT=6776 +export FILESYNC_IP=0.0.0.0 +export FILESYNC_PATH=/tmp/share + +go run gsync.go +``` + +Build package (requires `glibc`, won't work on OSX): + +```sh +make build +``` + +Build Docker image: + +```sh +make dev-image +make image ``` + +## Demo + +The [docker-compose.yml](/docker-compose.yml) details a setup with a server and 2 clients. It will create a `./demo/` directory with 3 subfolders: `server`, `client1`, and `client2`. Each subfolder is volumed as `/share/` inside each container. + +As files in `./demo/server` are modified, they will be altered in `./demo/client1` and `./demo/client2`. + +Run Docker-Compose cluster: + +```sh +docker-compose up -d +``` + +Check directories: + +```sh +ls -al ./demo/server +ls -al ./demo/client1 +ls -al ./demo/client2 +``` + +Add a file to server volume: + +```sh +echo "testing 123" > ./demo/server/test1 +``` + +Check directories again: + +```sh +ls -al ./demo/server +ls -al ./demo/client1 +ls -al ./demo/client2 +``` + +At this point, the `./demo/client*` directories should contain a `test1` file. + +## Notes + +### Docker Environment + +While the server configuration can be set to an IP of `0.0.0.0` (accepts traffic from anywhere), the clients need a specific address to connect to. If running locally, the clients can be set to connect to `127.0.0.1` - but this will not work in a Dockerized environment. + +The Docker-Compose.yml file contains `links: [fs-server:fs-server]` which enables the clients to contact the server container at `http://fs-server`. This is supported in a Rancher environment as well. + +### Rancher Environment + +Filesync can be used as a way to share files between hosts. Container deployment can be controlled by assigning labels and using the Rancher scheduling system. + +By labelling the primary host with `filesync=server`, these labels can be used to add a Filesync server and multiple clients: + +```yml +# Server + labels: + io.rancher.scheduler.affinity:host_label: filesync=server + +# Client + labels: + io.rancher.scheduler.global: 'true' + io.rancher.scheduler.affinity:host_label_ne: filesync=server +``` + +The host labelled with `filesync=server` will receive a Filesync server container, and all other hosts (`io.rancher.scheduler.global: 'true'`) not labelled with this (`host_label_ne: filesync=server`) will receive a client container. diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..95e94cd --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +v0.0.1 \ No newline at end of file diff --git a/api/api.go b/api/api.go index 6a4cc15..8d12d46 100644 --- a/api/api.go +++ b/api/api.go @@ -3,9 +3,10 @@ package api import ( "database/sql" "fmt" + "log" "github.com/codegangsta/martini" "github.com/codegangsta/martini-contrib/encoder" - "github.com/elgs/filesync/index" + "filesync/index" "io" "net/http" "os" @@ -37,7 +38,7 @@ func RunWeb(ip string, port int, monitors map[string]interface{}) { route.Get("/dirs", func(enc encoder.Encoder, req *http.Request) (int, []byte) { defer func() { if err := recover(); err != nil { - fmt.Println(err) + log.Println(err) } }() monitored := req.Header.Get("MONITORED") @@ -114,5 +115,5 @@ func RunWeb(ip string, port int, monitors map[string]interface{}) { }) m.Action(route.Handle) - fmt.Println(http.ListenAndServe(fmt.Sprint(ip, ":", port), m)) + log.Println(http.ListenAndServe(fmt.Sprint(ip, ":", port), m)) } diff --git a/config/client.go b/config/client.go index a45cde7..773a3f8 100644 --- a/config/client.go +++ b/config/client.go @@ -3,8 +3,10 @@ package config import ( "encoding/json" "fmt" + "log" simplejson "github.com/bitly/go-simplejson" - "github.com/elgs/filesync/index" + "filesync/index" + vars "filesync/vars" "hash/crc32" "io" "io/ioutil" @@ -16,24 +18,18 @@ import ( var monitorFilePart bool = false -func StartClient(configFile string, done chan bool) { - b, err := ioutil.ReadFile(configFile) - if err != nil { - fmt.Println(configFile, " not found") - go func() { - done <- false - }() - return - } - json, _ := simplejson.NewJson(b) - ip := json.Get("ip").MustString("127.0.0.1") - port := json.Get("port").MustInt(6776) +func StartClient(done chan bool) { + vars := vars.GetConfig(); + log.Println("Starting Filesync client") + for k, v := range vars.Monitors { + monitored, _ := v.(string) - monitors := json.Get("monitors").MustMap() + if(!index.Exists(monitored)){ + log.Println("Path does not exist: ", monitored) + continue + } - for k, v := range monitors { - monitored, _ := v.(string) - go startWork(ip, port, k, monitored, time.Minute) + go startWork(vars.Ip, vars.Port, k, monitored, time.Minute) } } @@ -52,7 +48,7 @@ func startWork(ip string, port int, key string, monitored string, maxInterval ti if dirStatus == "deleted" { err := os.RemoveAll(dir) if err != nil { - fmt.Println(err) + log.Println(err) } continue } @@ -60,7 +56,7 @@ func startWork(ip string, port int, key string, monitored string, maxInterval ti dirMode, _ := mode.Int64() err := os.MkdirAll(dir, os.FileMode(dirMode)) if err != nil { - fmt.Println(err) + log.Println(err) } } @@ -79,7 +75,7 @@ func startWork(ip string, port int, key string, monitored string, maxInterval ti if fileStatus == "deleted" { err := os.RemoveAll(f) if err != nil { - fmt.Println(err) + log.Println(err) } continue } @@ -150,7 +146,7 @@ func startWork(ip string, port int, key string, monitored string, maxInterval ti func downloadFromServer(ip string, port int, key string, filePath string, start int64, length int64, file *os.File) int64 { defer func() { if err := recover(); err != nil { - fmt.Println(err) + log.Println(err) } }() client := &http.Client{} @@ -167,7 +163,7 @@ func downloadFromServer(ip string, port int, key string, filePath string, start func filePartsFromServer(ip string, port int, key string, filePath string) []interface{} { defer func() { if err := recover(); err != nil { - fmt.Println(err) + log.Println(err) } }() client := &http.Client{} @@ -185,7 +181,7 @@ func filePartsFromServer(ip string, port int, key string, filePath string) []int func filesFromServer(ip string, port int, key string, filePath string, lastIndexed int64) []interface{} { defer func() { if err := recover(); err != nil { - fmt.Println(err) + log.Println(err) } }() client := &http.Client{} @@ -203,7 +199,7 @@ func filesFromServer(ip string, port int, key string, filePath string, lastIndex func dirsFromServer(ip string, port int, key string, lastIndexed int64) []interface{} { defer func() { if err := recover(); err != nil { - fmt.Println(err) + log.Println(err) } }() client := &http.Client{} diff --git a/config/server.go b/config/server.go index aeafa84..f25cf16 100644 --- a/config/server.go +++ b/config/server.go @@ -1,41 +1,53 @@ package config import ( + "os" + "log" "database/sql" - "fmt" - simplejson "github.com/bitly/go-simplejson" - "github.com/elgs/filesync/api" - "github.com/elgs/filesync/index" + "filesync/api" + "filesync/index" + vars "filesync/vars" "github.com/howeyc/fsnotify" _ "github.com/mattn/go-sqlite3" - "io/ioutil" ) -func StartServer(configFile string) { - b, err := ioutil.ReadFile(configFile) - if err != nil { - fmt.Println(configFile, " not found") - return - } - json, _ := simplejson.NewJson(b) - ip := json.Get("ip").MustString("127.0.0.1") - port := json.Get("port").MustInt(6776) - - monitors := json.Get("monitors").MustMap() +func StartServer() { + vars := vars.GetConfig(); - for _, v := range monitors { + for _, v := range vars.Monitors { watcher, _ := fsnotify.NewWatcher() monitored, _ := v.(string) monitored = index.PathSafe(monitored) - db, _ := sql.Open("sqlite3", index.SlashSuffix(monitored)+".sync/index.db") + targetPath := index.SlashSuffix(monitored) + dbPath := targetPath + ".sync/index.db" + + if(!index.Exists(monitored)){ + log.Println("Path does not exist, creating: ", monitored) + + if os.MkdirAll(monitored, os.ModePerm) != nil { + log.Fatal("Could not create directory: ", monitored) + continue + } + } + + if(!index.Writable(targetPath)){ + log.Fatal("Path is not writeable: ", targetPath) + } + + db, err := sql.Open("sqlite3", dbPath) + if err != nil { + log.Fatal(err) + } defer db.Close() db.Exec("VACUUM;") + index.InitIndex(monitored, db) go index.ProcessEvent(watcher, monitored) index.WatchRecursively(watcher, monitored, monitored) + } - fmt.Println("Serving now...") - api.RunWeb(ip, port, monitors) + log.Println("Serving now...") + api.RunWeb(vars.Ip, vars.Port, vars.Monitors) //watcher.Close() } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..77f2f27 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,44 @@ +version: '2' + +services: + fs-server: + image: "causticlab/filesync:dev" + tty: true + stdin_open: true + labels: + io.rancher.scheduler.affinity:host_label: rgon=primary + environment: + FILESYNC_MODE: 'server' + FILESYNC_PATH: '/share' + volumes: + - ./demo/server:/share + fs-client1: + image: "causticlab/filesync:dev" + tty: true + stdin_open: true + links: + - fs-server:fs-server + labels: + io.rancher.scheduler.global: 'true' + io.rancher.scheduler.affinity:host_label_ne: rgon=primary + environment: + FILESYNC_MODE: 'client' + FILESYNC_IP: 'fs-server' + FILESYNC_PATH: '/share' + volumes: + - ./demo/client1:/share + fs-client2: + image: "causticlab/filesync:dev" + tty: true + stdin_open: true + links: + - fs-server:fs-server + labels: + io.rancher.scheduler.global: 'true' + io.rancher.scheduler.affinity:host_label_ne: rgon=primary + environment: + FILESYNC_MODE: 'client' + FILESYNC_IP: 'fs-server' + FILESYNC_PATH: '/share' + volumes: + - ./demo/client2:/share \ No newline at end of file diff --git a/gsync.go b/gsync.go new file mode 100644 index 0000000..a06a5f4 --- /dev/null +++ b/gsync.go @@ -0,0 +1,28 @@ +package main + +import ( + "log" + vars "filesync/vars" + "filesync/config" + "runtime" +) + +func main() { + runtime.GOMAXPROCS(runtime.NumCPU()) + log.Println("CPUs: ", runtime.NumCPU()) + done := make(chan bool) + start(done) + <-done +} + +func start(done chan bool) { + vars.Init(); + vars := vars.GetConfig(); + log.Printf("Fileshare Config:\n%+v\n", vars) + + if vars.Mode == "server" { + config.StartServer() + } else if vars.Mode == "client" { + config.StartClient(done) + } +} diff --git a/gsync/gsync.go b/gsync/gsync.go deleted file mode 100644 index f740c4a..0000000 --- a/gsync/gsync.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "fmt" - simplejson "github.com/bitly/go-simplejson" - "github.com/elgs/filesync/config" - "io/ioutil" - "os" - "runtime" -) - -func main() { - runtime.GOMAXPROCS(runtime.NumCPU()) - fmt.Println("CPUs: ", runtime.NumCPU()) - input := args() - done := make(chan bool) - if len(input) >= 1 { - start(input[0], done) - } - <-done -} - -func start(configFile string, done chan bool) { - b, err := ioutil.ReadFile(configFile) - if err != nil { - fmt.Println(configFile, " not found") - go func() { - done <- false - }() - return - } - json, _ := simplejson.NewJson(b) - mode := json.Get("mode").MustString("server") - if mode == "server" { - config.StartServer(configFile) - } else if mode == "client" { - config.StartClient(configFile, done) - } -} - -func args() []string { - ret := []string{} - if len(os.Args) <= 1 { - ret = append(ret, "gsync.json") - } else { - for i := 1; i < len(os.Args); i++ { - ret = append(ret, os.Args[i]) - } - } - return ret -} diff --git a/index/index.go b/index/index.go index e6b08ef..33231a6 100644 --- a/index/index.go +++ b/index/index.go @@ -2,6 +2,7 @@ package index import ( "database/sql" + "log" "fmt" "github.com/howeyc/fsnotify" "hash/crc32" @@ -11,6 +12,7 @@ import ( "regexp" "strings" "time" + "golang.org/x/sys/unix" ) type IndexedFile struct { @@ -39,12 +41,12 @@ var monitorFilePart bool = false func ProcessFileDelete(thePath string, monitored string) { if ignore(thePath, monitored) { - fmt.Println("Ignored: ", thePath) + //log.Println("Ignored: ", thePath) return } defer func() { if err := recover(); err != nil { - fmt.Println(err) + log.Println(err) } }() thePath = PathSafe(thePath) @@ -82,16 +84,16 @@ func ProcessFileDelete(thePath string, monitored string) { func ProcessDirChange(thePath string, info os.FileInfo, monitored string) { if ignore(thePath, monitored) { - fmt.Println("Ignored: ", thePath) + //log.Println("Ignored: ", thePath) return } defer func() { if err := recover(); err != nil { - fmt.Println(err) + log.Println(err) } }() if info == nil { - fmt.Println("Dir no longer exists: " + thePath) + log.Println("Dir no longer exists: " + thePath) return } thePath = PathSafe(thePath) @@ -108,16 +110,16 @@ func ProcessDirChange(thePath string, info os.FileInfo, monitored string) { func ProcessFileChange(thePath string, info os.FileInfo, monitored string) { if ignore(thePath, monitored) { - fmt.Println("Ignored: ", thePath) + //log.Println("Ignored: ", thePath) return } defer func() { if err := recover(); err != nil { - fmt.Println(err) + log.Println(err) } }() if info == nil { - fmt.Println("File no longer exists: " + thePath) + log.Println("File no longer exists: " + thePath) return } thePath = PathSafe(thePath) @@ -238,7 +240,7 @@ func ProcessFileChange(thePath string, info os.FileInfo, monitored string) { func WatchRecursively(watcher *fsnotify.Watcher, root string, monitored string) error { if ignore(root, monitored) { - fmt.Println("Ignored: ", root) + //log.Println("Ignored: ", root) return nil } @@ -265,7 +267,7 @@ func WatchRecursively(watcher *fsnotify.Watcher, root string, monitored string) defer db.Close() //fmt.Println(path) if ignore(path, monitored) { - fmt.Println("Ignored: ", path) + //log.Println("Ignored: ", path) return nil } var thePath string @@ -302,7 +304,7 @@ func WatchRecursively(watcher *fsnotify.Watcher, root string, monitored string) // remove zombies for k, v := range mapFiles { if k != "/" && v.Status == "ready" { - fmt.Println("Zombie removed: ", v.FilePath) + log.Println("Zombie removed: ", v.FilePath) ProcessFileDelete(monitored+k, monitored) } } @@ -329,7 +331,7 @@ func LikeSafe(path string) string { func InitIndex(monitored string, db *sql.DB) error { var ret error = nil - exists := exists(SlashSuffix(monitored) + ".sync/index.db") + exists := Exists(SlashSuffix(monitored) + ".sync/index.db") if !exists { os.MkdirAll(SlashSuffix(monitored)+".sync/", (os.FileMode)(0755)) if monitorFilePart { @@ -362,7 +364,7 @@ func InitIndex(monitored string, db *sql.DB) error { } // exists returns whether the given file or directory exists or not -func exists(path string) bool { +func Exists(path string) bool { _, err := os.Stat(path) if err == nil { return true @@ -407,7 +409,7 @@ func ProcessEvent(watcher *fsnotify.Watcher, monitored string) { ProcessFileDelete(ev.Name, monitored) //fmt.Println("Deleted: " + ev.Name) } else if ev.IsRename() { - if exists(ev.Name) { + if Exists(ev.Name) { if info.IsDir() { WatchRecursively(watcher, ev.Name, monitored) //fmt.Println("Created dir: " + ev.Name) @@ -420,10 +422,14 @@ func ProcessEvent(watcher *fsnotify.Watcher, monitored string) { } } case err := <-watcher.Error: - fmt.Println("error:", err) + log.Println("error: ", err) case <-time.After(time.Minute): //fmt.Println("I'm idle, so I decided to do a patrol") go WatchRecursively(watcher, monitored, monitored) } } } + +func Writable(path string) bool { + return unix.Access(path, unix.W_OK) == nil +} \ No newline at end of file diff --git a/vars/vars.go b/vars/vars.go new file mode 100644 index 0000000..df476ce --- /dev/null +++ b/vars/vars.go @@ -0,0 +1,96 @@ +package vars + +import ( + "os" + "fmt" + "log" + "strconv" + "io/ioutil" + simplejson "github.com/bitly/go-simplejson" +) + +type ConfigVars struct{ + Mode string + Ip string + Port int + Monitors map[string]interface{} +} +var config ConfigVars + +func Init() { + var configFile string + + input := Args() + if len(input) >= 1 { + configFile = input[0] + } + + if(configFile != ""){ + fmt.Println("HERE ", configFile) + b, err := ioutil.ReadFile(configFile) + if err != nil { + fmt.Println(configFile, " not found") + //return + } else { + json, _ := simplejson.NewJson(b) + config.Mode = json.Get("mode").MustString() + config.Ip = json.Get("ip").MustString() + config.Port = json.Get("port").MustInt() + config.Monitors = json.Get("monitors").MustMap() + } + } else { + config.Mode = os.Getenv("FILESYNC_MODE") + config.Ip = os.Getenv("FILESYNC_IP") + config.Port, _ = strconv.Atoi(os.Getenv("FILESYNC_PORT")) + + config.Monitors = make(map[string]interface{}) + config.Monitors["default"] = os.Getenv("FILESYNC_PATH") + } + + if(config.Mode == ""){ + config.Mode = "server" + } + + if(config.Ip == ""){ + config.Ip = "0.0.0.0" + } + + if(config.Port <= 0){ + config.Port = 6776 + } + + if (len(config.Monitors) == 1) && (config.Monitors["default"] == ""){ + log.Println("No paths to monitor - defaulting to /share") + + config.Monitors = make(map[string]interface{}) + config.Monitors["default"] = "/share" + } +} + +func GetConfig() ConfigVars{ + return config +} + +func Args() []string { + ret := []string{} + if len(os.Args) >= 1 { + for i := 1; i < len(os.Args); i++ { + ret = append(ret, os.Args[i]) + } + } + return ret +} + + + + + + + + + + + + + +