func init() { device1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR") device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY") defaultFolderConfig = config.FolderConfiguration{ ID: "default", RawPath: "testdata", Devices: []config.FolderDeviceConfiguration{ { DeviceID: device1, }, }, } _defaultConfig := config.Configuration{ Folders: []config.FolderConfiguration{defaultFolderConfig}, Devices: []config.DeviceConfiguration{ { DeviceID: device1, }, }, Options: config.OptionsConfiguration{ // Don't remove temporaries directly on startup KeepTemporariesH: 1, }, } defaultConfig = config.Wrap("/tmp/test", _defaultConfig) }
func performHandshakeAndValidation(conn *tls.Conn, uri *url.URL) error { if err := conn.Handshake(); err != nil { return err } cs := conn.ConnectionState() if !cs.NegotiatedProtocolIsMutual || cs.NegotiatedProtocol != protocol.ProtocolName { return fmt.Errorf("protocol negotiation error") } q := uri.Query() relayIDs := q.Get("id") if relayIDs != "" { relayID, err := syncthingprotocol.DeviceIDFromString(relayIDs) if err != nil { return fmt.Errorf("relay address contains invalid verification id: %s", err) } certs := cs.PeerCertificates if cl := len(certs); cl != 1 { return fmt.Errorf("unexpected certificate count: %d", cl) } remoteID := syncthingprotocol.NewDeviceID(certs[0].Raw) if remoteID != relayID { return fmt.Errorf("relay id does not match. Expected %v got %v", relayID, remoteID) } } return nil }
func main() { var server string flag.StringVar(&server, "server", "", "Announce server (blank for default set)") flag.DurationVar(&timeout, "timeout", timeout, "Query timeout") flag.Usage = usage flag.Parse() if flag.NArg() != 1 { flag.Usage() os.Exit(64) } id, err := protocol.DeviceIDFromString(flag.Args()[0]) if err != nil { fmt.Println(err) os.Exit(1) } if server != "" { checkServers(id, server) } else { checkServers(id, config.DefaultDiscoveryServers...) } }
func NewGlobal(server string, cert tls.Certificate, addrList AddressLister) (FinderService, error) { server, opts, err := parseOptions(server) if err != nil { return nil, err } var devID protocol.DeviceID if opts.id != "" { devID, err = protocol.DeviceIDFromString(opts.id) if err != nil { return nil, err } } // The http.Client used for announcements. It needs to have our // certificate to prove our identity, and may or may not verify the server // certificate depending on the insecure setting. var announceClient httpClient = &http.Client{ Timeout: requestTimeout, Transport: &http.Transport{ Dial: dialer.Dial, Proxy: http.ProxyFromEnvironment, TLSClientConfig: &tls.Config{ InsecureSkipVerify: opts.insecure, Certificates: []tls.Certificate{cert}, }, }, } if opts.id != "" { announceClient = newIDCheckingHTTPClient(announceClient, devID) } // The http.Client used for queries. We don't need to present our // certificate here, so lets not include it. May be insecure if requested. var queryClient httpClient = &http.Client{ Timeout: requestTimeout, Transport: &http.Transport{ Dial: dialer.Dial, Proxy: http.ProxyFromEnvironment, TLSClientConfig: &tls.Config{ InsecureSkipVerify: opts.insecure, }, }, } if opts.id != "" { queryClient = newIDCheckingHTTPClient(queryClient, devID) } cl := &globalClient{ server: server, addrList: addrList, announceClient: announceClient, queryClient: queryClient, noAnnounce: opts.noAnnounce, stop: make(chan struct{}), } cl.setError(errors.New("not announced")) return cl, nil }
func parseDeviceID(input string) protocol.DeviceID { device, err := protocol.DeviceIDFromString(input) if err != nil { die(input + " is not a valid device id") } return device }
func (d *FileTreeCache) GetEntryDevices(filepath string) ([]protocol.DeviceID, bool) { var devices []protocol.DeviceID found := false d.db.View(func(tx *bolt.Tx) error { edb := tx.Bucket(d.folderBucketKey).Bucket(entryDevicesBucket) d := edb.Get([]byte(filepath)) if d == nil { devices = make([]protocol.DeviceID, 0) } else { found = true var deviceMap map[string]bool rbuf := bytes.NewBuffer(d) dec := gob.NewDecoder(rbuf) dec.Decode(&deviceMap) devices = make([]protocol.DeviceID, len(deviceMap)) i := 0 for k, _ := range deviceMap { devices[i], _ = protocol.DeviceIDFromString(k) i += 1 } } return nil }) return devices, found }
func TestSyncClusterForcedRescan(t *testing.T) { // Use no versioning id, _ := protocol.DeviceIDFromString(id2) cfg, _ := config.Load("h2/config.xml", id) fld := cfg.Folders()["default"] fld.Versioning = config.VersioningConfiguration{} cfg.SetFolder(fld) cfg.Save() testSyncClusterForcedRescan(t) }
func (s *apiService) postSystemResume(w http.ResponseWriter, r *http.Request) { var qs = r.URL.Query() var deviceStr = qs.Get("device") device, err := protocol.DeviceIDFromString(deviceStr) if err != nil { http.Error(w, err.Error(), 500) return } s.model.ResumeDevice(device) }
func TestSyncClusterStaggeredVersioning(t *testing.T) { // Use staggered versioning id, _ := protocol.DeviceIDFromString(id2) cfg, _ := config.Load("h2/config.xml", id) fld := cfg.Folders()["default"] fld.Versioning = config.VersioningConfiguration{ Type: "staggered", } cfg.SetFolder(fld) cfg.Save() testSyncCluster(t) }
func (s *querysrv) handleGET(ctx context.Context, w http.ResponseWriter, req *http.Request) { reqID := ctx.Value("id").(requestID) deviceID, err := protocol.DeviceIDFromString(req.URL.Query().Get("device")) if err != nil { if debug { log.Println(reqID, "bad device param") } globalStats.Error() http.Error(w, "Bad Request", http.StatusBadRequest) return } var ann announcement ann.Seen, err = s.getDeviceSeen(deviceID) negCache := strconv.Itoa(negCacheFor(ann.Seen)) w.Header().Set("Retry-After", negCache) w.Header().Set("Cache-Control", "public, max-age="+negCache) if err != nil { // The device is not in the database. globalStats.Query() http.Error(w, "Not Found", http.StatusNotFound) return } t0 := time.Now() ann.Addresses, err = s.getAddresses(ctx, deviceID) if err != nil { log.Println(reqID, "getAddresses:", err) globalStats.Error() http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } if debug { log.Println(reqID, "getAddresses in", time.Since(t0)) } globalStats.Query() if len(ann.Addresses) == 0 { http.Error(w, "Not Found", http.StatusNotFound) return } globalStats.Answer() w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(ann) }
func TestModelIndexWithRestart(t *testing.T) { // init dir, _ := ioutil.TempDir("", "stf-mt") defer os.RemoveAll(dir) deviceID, _ := protocol.DeviceIDFromString("FFR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR") cfg, database, folder := setup(deviceID, dir) // Arrange model := NewModel(cfg, database) flags := uint32(0) options := []protocol.Option{} files := []protocol.FileInfo{ protocol.FileInfo{Name: "file1"}, protocol.FileInfo{Name: "file2"}, protocol.FileInfo{Name: "dir1", Flags: protocol.FlagDirectory}, protocol.FileInfo{Name: "dir1/dirfile1"}, protocol.FileInfo{Name: "dir1/dirfile2"}, } model.Index(deviceID, folder, files, flags, options) // Act (restart db and model) databasePath := database.Path() database.Close() database, _ = bolt.Open(databasePath, 0600, nil) model = NewModel(cfg, database) // Assert children := model.GetChildren(folder, ".") assertContainsChild(t, children, "file2", 0) assertContainsChild(t, children, "file2", 0) assertContainsChild(t, children, "dir1", protocol.FlagDirectory) if len(children) != 3 { t.Error("expected 3 children, but got", len(children)) } children = model.GetChildren(folder, "dir1") assertContainsChild(t, children, "dir1/dirfile1", 0) assertContainsChild(t, children, "dir1/dirfile2", 0) if len(children) != 2 { t.Error("expected 2 children, but got", len(children)) } assertEntry(t, model.GetEntry(folder, "file1"), "file1", 0) assertEntry(t, model.GetEntry(folder, "file2"), "file2", 0) assertEntry(t, model.GetEntry(folder, "dir1"), "dir1", protocol.FlagDirectory) assertEntry(t, model.GetEntry(folder, "dir1/dirfile1"), "dir1/dirfile1", 0) assertEntry(t, model.GetEntry(folder, "dir1/dirfile2"), "dir1/dirfile2", 0) }
func TestSyncClusterTrashcanVersioning(t *testing.T) { // Use simple versioning id, _ := protocol.DeviceIDFromString(id2) cfg, _ := config.Load("h2/config.xml", id) fld := cfg.Folders()["default"] fld.Versioning = config.VersioningConfiguration{ Type: "trashcan", Params: map[string]string{"cleanoutDays": "1"}, } cfg.SetFolder(fld) cfg.Save() testSyncCluster(t) }
func TestFileTypeChangeSimpleVersioning(t *testing.T) { // Use simple versioning id, _ := protocol.DeviceIDFromString(id2) cfg, _ := config.Load("h2/config.xml", id) fld := cfg.Folders()["default"] fld.Versioning = config.VersioningConfiguration{ Type: "simple", Params: map[string]string{"keep": "5"}, } cfg.SetFolder(fld) cfg.Save() testFileTypeChange(t) }
func TestSymlinks(t *testing.T) { if !symlinksSupported() { t.Skip("symlinks unsupported") } // Use no versioning id, _ := protocol.DeviceIDFromString(id2) cfg, _ := config.Load("h2/config.xml", id) fld := cfg.Folders()["default"] fld.Versioning = config.VersioningConfiguration{} cfg.SetFolder(fld) cfg.Save() testSymlinks(t) }
func (s *apiService) getDeviceID(w http.ResponseWriter, r *http.Request) { qs := r.URL.Query() idStr := qs.Get("id") id, err := protocol.DeviceIDFromString(idStr) if err == nil { sendJSON(w, map[string]string{ "id": id.String(), }) } else { sendJSON(w, map[string]string{ "error": err.Error(), }) } }
func (s *apiService) getDBCompletion(w http.ResponseWriter, r *http.Request) { var qs = r.URL.Query() var folder = qs.Get("folder") var deviceStr = qs.Get("device") device, err := protocol.DeviceIDFromString(deviceStr) if err != nil { http.Error(w, err.Error(), 500) return } sendJSON(w, map[string]float64{ "completion": s.model.Completion(device, folder), }) }
func (s *apiSvc) getDeviceID(w http.ResponseWriter, r *http.Request) { qs := r.URL.Query() idStr := qs.Get("id") id, err := protocol.DeviceIDFromString(idStr) w.Header().Set("Content-Type", "application/json; charset=utf-8") if err == nil { json.NewEncoder(w).Encode(map[string]string{ "id": id.String(), }) } else { json.NewEncoder(w).Encode(map[string]string{ "error": err.Error(), }) } }
func setup(t *testing.T, cacheSize string) (*config.Wrapper, *bolt.DB, config.FolderConfiguration) { dir, _ := ioutil.TempDir("", "stf-mt") configFile, _ := ioutil.TempFile(dir, "config") deviceID, _ := protocol.DeviceIDFromString("FFR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR") realCfg := config.New(deviceID) cfg := config.Wrap(configFile.Name(), realCfg) databasePath := path.Join(path.Dir(cfg.ConfigPath()), "boltdb") database, _ := bolt.Open(databasePath, 0600, nil) folderCfg := config.FolderConfiguration{ ID: folder, CacheSize: cacheSize, } cfg.SetFolder(folderCfg) return cfg, database, folderCfg }
func TestSymlinksSimpleVersioning(t *testing.T) { if !symlinksSupported() { t.Skip("symlinks unsupported") } // Use simple versioning id, _ := protocol.DeviceIDFromString(id2) cfg, _ := config.Load("h2/config.xml", id) fld := cfg.Folders()["default"] fld.Versioning = config.VersioningConfiguration{ Type: "simple", Params: map[string]string{"keep": "5"}, } cfg.SetFolder(fld) cfg.Save() testSymlinks(t) }
func (s *apiSvc) getDBCompletion(w http.ResponseWriter, r *http.Request) { var qs = r.URL.Query() var folder = qs.Get("folder") var deviceStr = qs.Get("device") device, err := protocol.DeviceIDFromString(deviceStr) if err != nil { http.Error(w, err.Error(), 500) return } res := map[string]float64{ "completion": s.model.Completion(device, folder), } w.Header().Set("Content-Type", "application/json; charset=utf-8") json.NewEncoder(w).Encode(res) }
func (s *apiService) getDBCompletion(w http.ResponseWriter, r *http.Request) { var qs = r.URL.Query() var folder = qs.Get("folder") var deviceStr = qs.Get("device") device, err := protocol.DeviceIDFromString(deviceStr) if err != nil { http.Error(w, err.Error(), 500) return } comp := s.model.Completion(device, folder) sendJSON(w, map[string]interface{}{ "completion": comp.CompletionPct, "needBytes": comp.NeedBytes, "globalBytes": comp.GlobalBytes, "needDeletes": comp.NeedDeletes, }) }
func New(myID protocol.DeviceID, myName string) Configuration { var cfg Configuration cfg.Version = CurrentVersion cfg.MyID = myID.String() setDefaults(&cfg) setDefaults(&cfg.GUI) setDefaults(&cfg.Options) thisDevice, _ := protocol.DeviceIDFromString(cfg.MyID) thisDeviceCfg := config.NewDeviceConfiguration(thisDevice, myName) thisDeviceCfg.Addresses = []string{"dynamic"} cfg.Folders = []FolderConfiguration{} cfg.Devices = []config.DeviceConfiguration{thisDeviceCfg} cfg.prepare() usr, _ := user.Current() cfg.MountPoint = path.Join(usr.HomeDir, "SyncthingFUSE") return cfg }
func (s *apiService) makeDevicePauseHandler(paused bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var qs = r.URL.Query() var deviceStr = qs.Get("device") device, err := protocol.DeviceIDFromString(deviceStr) if err != nil { http.Error(w, err.Error(), 500) return } cfg, ok := s.cfg.Devices()[device] if !ok { http.Error(w, "not found", http.StatusNotFound) } cfg.Paused = paused if err := s.cfg.SetDevice(cfg); err != nil { http.Error(w, err.Error(), 500) } } }
func TestOverride(t *testing.T) { // Enable "Master" on s1/default id, _ := protocol.DeviceIDFromString(id1) cfg, _ := config.Load("h1/config.xml", id) fld := cfg.Folders()["default"] fld.Type = config.FolderTypeSendOnly cfg.SetFolder(fld) os.Rename("h1/config.xml", "h1/config.xml.orig") defer osutil.Rename("h1/config.xml.orig", "h1/config.xml") cfg.Save() log.Println("Cleaning...") err := removeAll("s1", "s2", "h1/index*", "h2/index*") if err != nil { t.Fatal(err) } log.Println("Generating files...") err = generateFiles("s1", 100, 20, "../LICENSE") if err != nil { t.Fatal(err) } fd, err := os.Create("s1/testfile.txt") if err != nil { t.Fatal(err) } _, err = fd.WriteString("hello\n") if err != nil { t.Fatal(err) } err = fd.Close() if err != nil { t.Fatal(err) } expected, err := directoryContents("s1") if err != nil { t.Fatal(err) } master := startInstance(t, 1) defer checkedStop(t, master) slave := startInstance(t, 2) defer checkedStop(t, slave) log.Println("Syncing...") rc.AwaitSync("default", master, slave) log.Println("Verifying...") actual, err := directoryContents("s2") if err != nil { t.Fatal(err) } err = compareDirectoryContents(actual, expected) if err != nil { t.Fatal(err) } log.Println("Changing file on slave side...") fd, err = os.OpenFile("s2/testfile.txt", os.O_WRONLY|os.O_APPEND, 0644) if err != nil { t.Fatal(err) } _, err = fd.WriteString("text added to s2\n") if err != nil { t.Fatal(err) } err = fd.Close() if err != nil { t.Fatal(err) } if err := slave.Rescan("default"); err != nil { t.Fatal(err) } log.Println("Waiting for index to send...") time.Sleep(10 * time.Second) log.Println("Hitting Override on master...") if _, err := master.Post("/rest/db/override?folder=default", nil); err != nil { t.Fatal(err) } log.Println("Syncing...") rc.AwaitSync("default", master, slave) // Verify that the override worked fd, err = os.Open("s1/testfile.txt") if err != nil { t.Fatal(err) } bs, err := ioutil.ReadAll(fd) if err != nil { t.Fatal(err) } fd.Close() if strings.Contains(string(bs), "added to s2") { t.Error("Change should not have been synced to master") } fd, err = os.Open("s2/testfile.txt") if err != nil { t.Fatal(err) } bs, err = ioutil.ReadAll(fd) if err != nil { t.Fatal(err) } fd.Close() if strings.Contains(string(bs), "added to s2") { t.Error("Change should have been overridden on slave") } }
func init() { device1, _ = protocol.DeviceIDFromString("AIR6LPZ7K4PTTUXQSMUUCPQ5YWOEDFIIQJUG7772YQXXR5YD6AWQ") device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY") device3, _ = protocol.DeviceIDFromString("LGFPDIT-7SKNNJL-VJZA4FC-7QNCRKA-CE753K7-2BW5QDK-2FOZ7FR-FEP57QJ") device4, _ = protocol.DeviceIDFromString("P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2") }
func init() { remoteDevice0, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR") remoteDevice1, _ = protocol.DeviceIDFromString("I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU") }
package model import ( "io/ioutil" "os" "path" "testing" "github.com/boltdb/bolt" "github.com/burkemw3/syncthingfuse/lib/config" stconfig "github.com/syncthing/syncthing/lib/config" "github.com/syncthing/syncthing/lib/protocol" ) var ( deviceAlice, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR") deviceBob, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY") deviceCarol, _ = protocol.DeviceIDFromString("I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU") ) func TestModelSingleIndex(t *testing.T) { // init dir, _ := ioutil.TempDir("", "stf-mt") defer os.RemoveAll(dir) cfg, database, folder := setup(deviceAlice, dir, deviceBob) // Arrange model := NewModel(cfg, database) files := []protocol.FileInfo{
func main() { log.SetOutput(os.Stdout) log.SetFlags(log.LstdFlags | log.Lshortfile) var connect, relay, dir string var join, test bool flag.StringVar(&connect, "connect", "", "Device ID to which to connect to") flag.BoolVar(&join, "join", false, "Join relay") flag.BoolVar(&test, "test", false, "Generic relay test") flag.StringVar(&relay, "relay", "relay://127.0.0.1:22067", "Relay address") flag.StringVar(&dir, "keys", ".", "Directory where cert.pem and key.pem is stored") flag.Parse() certFile, keyFile := filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem") cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { log.Fatalln("Failed to load X509 key pair:", err) } id := syncthingprotocol.NewDeviceID(cert.Certificate[0]) log.Println("ID:", id) uri, err := url.Parse(relay) if err != nil { log.Fatal(err) } stdin := make(chan string) go stdinReader(stdin) if join { log.Println("Creating client") relay, err := client.NewClient(uri, []tls.Certificate{cert}, nil, 10*time.Second) if err != nil { log.Fatal(err) } log.Println("Created client") go relay.Serve() recv := make(chan protocol.SessionInvitation) go func() { log.Println("Starting invitation receiver") for invite := range relay.Invitations() { select { case recv <- invite: log.Println("Received invitation", invite) default: log.Println("Discarding invitation", invite) } } }() for { conn, err := client.JoinSession(<-recv) if err != nil { log.Fatalln("Failed to join", err) } log.Println("Joined", conn.RemoteAddr(), conn.LocalAddr()) connectToStdio(stdin, conn) log.Println("Finished", conn.RemoteAddr(), conn.LocalAddr()) } } else if connect != "" { id, err := syncthingprotocol.DeviceIDFromString(connect) if err != nil { log.Fatal(err) } invite, err := client.GetInvitationFromRelay(uri, id, []tls.Certificate{cert}, 10*time.Second) if err != nil { log.Fatal(err) } log.Println("Received invitation", invite) conn, err := client.JoinSession(invite) if err != nil { log.Fatalln("Failed to join", err) } log.Println("Joined", conn.RemoteAddr(), conn.LocalAddr()) connectToStdio(stdin, conn) log.Println("Finished", conn.RemoteAddr(), conn.LocalAddr()) } else if test { if client.TestRelay(uri, []tls.Certificate{cert}, time.Second, 2*time.Second, 4) { log.Println("OK") } else { log.Println("FAIL") } } else { log.Fatal("Requires either join or connect") } }
func TestModelSingleIndexUpdate(t *testing.T) { // init dir, _ := ioutil.TempDir("", "stf-mt") defer os.RemoveAll(dir) deviceID, _ := protocol.DeviceIDFromString("FFR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR") cfg, database, folder := setup(deviceID, dir) // Arrange model := NewModel(cfg, database) flags := uint32(0) options := []protocol.Option{} version := protocol.Vector{protocol.Counter{1, 0}} files := []protocol.FileInfo{ protocol.FileInfo{Name: "unchangedFile", Version: version}, protocol.FileInfo{Name: "file2dir", Version: version}, protocol.FileInfo{Name: "removedFile", Version: version}, protocol.FileInfo{Name: "dir1", Flags: protocol.FlagDirectory, Version: version}, protocol.FileInfo{Name: "dir1/dirfile1", Version: version}, protocol.FileInfo{Name: "dir1/dirfile2", Version: version}, protocol.FileInfo{Name: "dir2file", Flags: protocol.FlagDirectory, Version: version}, protocol.FileInfo{Name: "dir2file/file1", Version: version}, protocol.FileInfo{Name: "dir2file/file2", Version: version}, protocol.FileInfo{Name: "file2symlink", Version: version}, } model.Index(deviceID, folder, files, flags, options) // Act version = protocol.Vector{protocol.Counter{1, 1}} files = []protocol.FileInfo{ protocol.FileInfo{Name: "file2dir", Flags: protocol.FlagDirectory, Version: version}, protocol.FileInfo{Name: "removedFile", Flags: protocol.FlagDeleted, Version: version}, protocol.FileInfo{Name: "dir2file", Version: version}, protocol.FileInfo{Name: "dir2file/file1", Flags: protocol.FlagDeleted, Version: version}, protocol.FileInfo{Name: "file2symlink", Flags: protocol.FlagSymlink, Version: version}, } model.IndexUpdate(deviceID, folder, files, flags, options) // Assert children := model.GetChildren(folder, ".") assertContainsChild(t, children, "unchangedFile", 0) assertContainsChild(t, children, "file2dir", protocol.FlagDirectory) assertContainsChild(t, children, "dir1", protocol.FlagDirectory) assertContainsChild(t, children, "dir2file", 0) if len(children) != 4 { t.Error("expected 4 children, but got", len(children)) } children = model.GetChildren(folder, "dir1") assertContainsChild(t, children, "dir1/dirfile1", 0) assertContainsChild(t, children, "dir1/dirfile2", 0) if len(children) != 2 { t.Error("expected 2 children, but got", len(children)) } assertEntry(t, model.GetEntry(folder, "unchangedFile"), "unchangedFile", 0) assertEntry(t, model.GetEntry(folder, "file2dir"), "file2dir", protocol.FlagDirectory) assertEntry(t, model.GetEntry(folder, "dir1"), "dir1", protocol.FlagDirectory) assertEntry(t, model.GetEntry(folder, "dir1/dirfile1"), "dir1/dirfile1", 0) assertEntry(t, model.GetEntry(folder, "dir1/dirfile2"), "dir1/dirfile2", 0) assertEntry(t, model.GetEntry(folder, "dir2file"), "dir2file", 0) }
func (p *Process) eventLoop() { since := 0 notScanned := make(map[string]struct{}) start := time.Now() for { p.eventMut.Lock() if p.stop { p.eventMut.Unlock() return } p.eventMut.Unlock() time.Sleep(250 * time.Millisecond) events, err := p.Events(since) if err != nil { if time.Since(start) < 5*time.Second { // The API has probably not started yet, lets give it some time. continue } // If we're stopping, no need to print the error. p.eventMut.Lock() if p.stop { p.eventMut.Unlock() return } p.eventMut.Unlock() log.Println("eventLoop: events:", err) continue } since = events[len(events)-1].ID for _, ev := range events { switch ev.Type { case "Starting": // The Starting event tells us where the configuration is. Load // it and populate our list of folders. data := ev.Data.(map[string]interface{}) id, err := protocol.DeviceIDFromString(data["myID"].(string)) if err != nil { log.Println("eventLoop: DeviceIdFromString:", err) continue } p.id = id home := data["home"].(string) w, err := config.Load(filepath.Join(home, "config.xml"), protocol.LocalDeviceID) if err != nil { log.Println("eventLoop: Starting:", err) continue } for id := range w.Folders() { p.eventMut.Lock() p.folders = append(p.folders, id) p.eventMut.Unlock() notScanned[id] = struct{}{} } case "StateChanged": // When a folder changes to idle, we tick it off by removing // it from p.notScanned. if !p.startComplete { data := ev.Data.(map[string]interface{}) to := data["to"].(string) if to == "idle" { folder := data["folder"].(string) delete(notScanned, folder) if len(notScanned) == 0 { p.eventMut.Lock() p.startComplete = true p.startCompleteCond.Broadcast() p.eventMut.Unlock() } } } case "LocalIndexUpdated": data := ev.Data.(map[string]interface{}) folder := data["folder"].(string) version, _ := data["version"].(json.Number).Int64() p.eventMut.Lock() m := p.localVersion[folder] if m == nil { m = make(map[string]int64) } m[p.id.String()] = version p.localVersion[folder] = m p.done[folder] = false if debug { l.Debugf("LocalIndexUpdated %v %v done=false\n\t%+v", p.id, folder, m) } p.eventMut.Unlock() case "RemoteIndexUpdated": data := ev.Data.(map[string]interface{}) device := data["device"].(string) folder := data["folder"].(string) version, _ := data["version"].(json.Number).Int64() p.eventMut.Lock() m := p.localVersion[folder] if m == nil { m = make(map[string]int64) } m[device] = version p.localVersion[folder] = m p.done[folder] = false if debug { l.Debugf("RemoteIndexUpdated %v %v done=false\n\t%+v", p.id, folder, m) } p.eventMut.Unlock() case "FolderSummary": data := ev.Data.(map[string]interface{}) folder := data["folder"].(string) summary := data["summary"].(map[string]interface{}) need, _ := summary["needBytes"].(json.Number).Int64() done := need == 0 p.eventMut.Lock() p.done[folder] = done if debug { l.Debugf("Foldersummary %v %v\n\t%+v", p.id, folder, p.done) } p.eventMut.Unlock() } } } }