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