Пример #1
0
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)
}
Пример #2
0
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
}
Пример #3
0
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...)
	}
}
Пример #4
0
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
}
Пример #5
0
func parseDeviceID(input string) protocol.DeviceID {
	device, err := protocol.DeviceIDFromString(input)
	if err != nil {
		die(input + " is not a valid device id")
	}
	return device
}
Пример #6
0
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
}
Пример #7
0
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)
}
Пример #8
0
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)
}
Пример #9
0
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)
}
Пример #10
0
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)
}
Пример #11
0
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)
}
Пример #12
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)
}
Пример #13
0
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)
}
Пример #14
0
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)
}
Пример #15
0
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(),
		})
	}
}
Пример #16
0
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),
	})
}
Пример #17
0
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(),
		})
	}
}
Пример #18
0
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
}
Пример #19
0
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)
}
Пример #20
0
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)
}
Пример #21
0
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,
	})
}
Пример #22
0
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
}
Пример #23
0
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)
		}
	}
}
Пример #24
0
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")
	}
}
Пример #25
0
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")
}
Пример #26
0
func init() {
	remoteDevice0, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
	remoteDevice1, _ = protocol.DeviceIDFromString("I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU")
}
Пример #27
0
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{
Пример #28
0
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")
	}
}
Пример #29
0
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)
}
Пример #30
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()
			}
		}
	}
}