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()

	for _, v := range monitors {
		watcher, _ := fsnotify.NewWatcher()
		monitored, _ := v.(string)
		monitored = index.PathSafe(monitored)
		db, _ := sql.Open("sqlite3", index.SlashSuffix(monitored)+".sync/index.db")
		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)
	//watcher.Close()
}
Exemple #2
0
func RunWeb(ip string, port int, monitors map[string]interface{}) {
	m := martini.New()
	route := martini.NewRouter()

	// validate an api key
	m.Use(func(res http.ResponseWriter, req *http.Request) {
		authKey := req.Header.Get("AUTH_KEY")
		if monitors[authKey] == nil {
			res.WriteHeader(http.StatusUnauthorized)
			res.Write([]byte("Unauthorized access."))
		} else {
			monitored, _ := monitors[authKey].(string)
			req.Header.Set("MONITORED", monitored)
		}
	})

	// map json encoder
	m.Use(func(c martini.Context, w http.ResponseWriter) {
		c.MapTo(encoder.JsonEncoder{}, (*encoder.Encoder)(nil))
		w.Header().Set("Content-Type", "application/json")
	})

	route.Get("/dirs", func(enc encoder.Encoder, req *http.Request) (int, []byte) {
		defer func() {
			if err := recover(); err != nil {
				fmt.Println(err)
			}
		}()
		monitored := req.Header.Get("MONITORED")
		lastIndexed, _ := strconv.Atoi(req.FormValue("last_indexed"))
		result := make([]index.IndexedFile, 0)

		db, _ := sql.Open("sqlite3", index.SlashSuffix(monitored)+".sync/index.db")
		defer db.Close()
		psSelectDirs, _ := db.Prepare("SELECT * FROM FILES WHERE FILE_SIZE=-1 AND LAST_INDEXED>?")
		defer psSelectDirs.Close()
		rows, _ := psSelectDirs.Query(lastIndexed)
		defer rows.Close()
		for rows.Next() {
			file := new(index.IndexedFile)
			rows.Scan(&file.FilePath, &file.LastModified, &file.FileSize, &file.FileMode, &file.Status, &file.LastIndexed)
			result = append(result, *file)
		}
		return http.StatusOK, encoder.Must(enc.Encode(result))
	})

	route.Get("/files", func(enc encoder.Encoder, req *http.Request) (int, []byte) {
		monitored := req.Header.Get("MONITORED")
		lastIndexed, _ := strconv.Atoi(req.FormValue("last_indexed"))
		filePath := index.SlashSuffix(index.LikeSafe(req.FormValue("file_path")))
		result := make([]index.IndexedFile, 0)

		db, _ := sql.Open("sqlite3", index.SlashSuffix(monitored)+".sync/index.db")
		defer db.Close()
		psSelectFiles, _ := db.Prepare(`SELECT * FROM FILES
				WHERE LAST_INDEXED>? AND FILE_SIZE>=0 AND STATUS!='updating' AND FILE_PATH LIKE ?`)
		defer psSelectFiles.Close()
		rows, _ := psSelectFiles.Query(lastIndexed, filePath+"%")
		defer rows.Close()
		for rows.Next() {
			file := new(index.IndexedFile)
			rows.Scan(&file.FilePath, &file.LastModified, &file.FileSize, &file.FileMode, &file.Status, &file.LastIndexed)
			result = append(result, *file)
		}
		return http.StatusOK, encoder.Must(enc.Encode(result))
	})

	route.Get("/file_parts", func(enc encoder.Encoder, req *http.Request) (int, []byte) {
		monitored := req.Header.Get("MONITORED")
		filePath := req.FormValue("file_path")
		result := make([]index.IndexedFilePart, 0)

		db, _ := sql.Open("sqlite3", index.SlashSuffix(monitored)+".sync/index.db")
		defer db.Close()
		psSelectFiles, _ := db.Prepare(`SELECT * FROM FILE_PARTS
				WHERE FILE_PATH=? ORDER BY FILE_PATH,SEQ`)
		defer psSelectFiles.Close()
		rows, _ := psSelectFiles.Query(filePath)
		defer rows.Close()
		for rows.Next() {
			filePart := new(index.IndexedFilePart)
			rows.Scan(&filePart.FilePath, &filePart.Seq, &filePart.StartIndex, &filePart.Offset, &filePart.Checksum, &filePart.ChecksumType)
			result = append(result, *filePart)
		}
		return http.StatusOK, encoder.Must(enc.Encode(result))
	})

	route.Get("/download", func(res http.ResponseWriter, req *http.Request) {
		monitored := req.Header.Get("MONITORED")
		filePath := req.FormValue("file_path")
		start, _ := strconv.ParseInt(req.FormValue("start"), 10, 64)
		length, _ := strconv.ParseInt(req.FormValue("length"), 10, 64)

		file, _ := os.Open(index.SlashSuffix(monitored) + filePath)
		defer file.Close()
		file.Seek(start, os.SEEK_SET)
		n, _ := io.CopyN(res, file, length)
		res.Header().Set("Content-Length", strconv.FormatInt(n, 10))
		res.Header().Set("Content-Type", "application/octet-stream")
	})

	m.Action(route.Handle)
	fmt.Println(http.ListenAndServe(fmt.Sprint(ip, ":", port), m))
}
func startWork(ip string, port int, key string, monitored string, maxInterval time.Duration) {
	var lastIndexed int64 = 0
	sleepTime := time.Second
	for {
		time.Sleep(sleepTime)
		dirs := dirsFromServer(ip, port, key, lastIndexed-3600)
		if len(dirs) > 0 {
			for _, dir := range dirs {
				dirMap, _ := dir.(map[string]interface{})
				dirPath, _ := dirMap["FilePath"].(string)
				dirStatus := dirMap["Status"].(string)
				dir := index.PathSafe(index.SlashSuffix(monitored) + dirPath)
				if dirStatus == "deleted" {
					err := os.RemoveAll(dir)
					if err != nil {
						fmt.Println(err)
					}
					continue
				}
				mode, _ := dirMap["FileMode"].(json.Number)
				dirMode, _ := mode.Int64()
				err := os.MkdirAll(dir, os.FileMode(dirMode))
				if err != nil {
					fmt.Println(err)
				}
			}

			files := filesFromServer(ip, port, key, "/", lastIndexed-3600)
			for _, file := range files {
				fileMap, _ := file.(map[string]interface{})
				filePath, _ := fileMap["FilePath"].(string)
				fileStatus := fileMap["Status"].(string)
				indexed, _ := fileMap["LastIndexed"].(json.Number)
				serverIndexed, _ := indexed.Int64()
				if serverIndexed > lastIndexed {
					lastIndexed = serverIndexed
				}

				f := index.PathSafe(index.SlashSuffix(monitored) + filePath)
				if fileStatus == "deleted" {
					err := os.RemoveAll(f)
					if err != nil {
						fmt.Println(err)
					}
					continue
				}
				size, _ := fileMap["FileSize"].(json.Number)
				fileSize, _ := size.Int64()
				if info, err := os.Stat(f); os.IsNotExist(err) {
					// file does not exists, download it
					func() {
						out, _ := os.Create(f)
						defer out.Close()
						downloadFromServer(ip, port, key, filePath, 0, fileSize, out)
					}()
				} else {
					// file exists, analyze it
					modified, _ := fileMap["LastModified"].(json.Number)
					lastModified, _ := modified.Int64()
					if fileSize == info.Size() && lastModified < info.ModTime().Unix() {
						// this file is probably not changed
						continue
					}
					if monitorFilePart {
						// file change, analyse it block by block
						fileParts := filePartsFromServer(ip, port, key, filePath)
						func() {
							out, _ := os.OpenFile(f, os.O_RDWR, os.FileMode(0666))
							defer out.Close()
							out.Truncate(fileSize)
							if len(fileParts) == 0 {
								return
							}
							h := crc32.NewIEEE()
							for _, filePart := range fileParts {
								filePartMap, _ := filePart.(map[string]interface{})
								idx, _ := filePartMap["StartIndex"].(json.Number)
								startIndex, _ := idx.Int64()
								ost, _ := filePartMap["Offset"].(json.Number)
								offset, _ := ost.Int64()
								checksum := filePartMap["Checksum"].(string)

								buf := make([]byte, offset)
								n, _ := out.ReadAt(buf, startIndex)

								h.Reset()
								h.Write(buf[:n])
								v := fmt.Sprint(h.Sum32())
								if checksum == v {
									// block unchanged
									return
								}
								// block changed
								downloadFromServer(ip, port, key, filePath, startIndex, offset, out)
							}
						}()
					} else {
						func() {
							out, _ := os.OpenFile(f, os.O_RDWR, os.FileMode(0666))
							defer out.Close()
							out.Truncate(fileSize)
							downloadFromServer(ip, port, key, filePath, 0, fileSize, out)
						}()
					}
				}
			}
		}
	}
}