all: Refactor the protocol/model interface a bit (ref #8981) (#9007)

This commit is contained in:
Jakob Borg 2023-07-29 10:24:44 +02:00 committed by GitHub
parent b806026990
commit 9d21b91124
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 431 additions and 359 deletions

View File

@ -58,7 +58,7 @@ var (
func init() { func init() {
dev1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR") dev1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
apiCfg.GUIReturns(config.GUIConfiguration{APIKey: testAPIKey}) apiCfg.GUIReturns(config.GUIConfiguration{APIKey: testAPIKey, RawAddress: "127.0.0.1:0"})
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -496,7 +496,9 @@ func TestAPIServiceRequests(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(cases[0].URL, func(t *testing.T) { t.Run(cases[0].URL, func(t *testing.T) {
t.Parallel()
testHTTPRequest(t, baseURL, tc, testAPIKey) testHTTPRequest(t, baseURL, tc, testAPIKey)
}) })
} }
@ -559,6 +561,7 @@ func TestHTTPLogin(t *testing.T) {
cfg.GUIReturns(config.GUIConfiguration{ cfg.GUIReturns(config.GUIConfiguration{
User: "üser", User: "üser",
Password: "$2a$10$IdIZTxTg/dCNuNEGlmLynOjqg4B1FvDKuIV5e0BB3pnWVHNb8.GSq", // bcrypt of "räksmörgås" in UTF-8 Password: "$2a$10$IdIZTxTg/dCNuNEGlmLynOjqg4B1FvDKuIV5e0BB3pnWVHNb8.GSq", // bcrypt of "räksmörgås" in UTF-8
RawAddress: "127.0.0.1:0",
APIKey: testAPIKey, APIKey: testAPIKey,
}) })
baseURL, cancel, err := startHTTP(cfg) baseURL, cancel, err := startHTTP(cfg)
@ -1050,12 +1053,12 @@ func TestHostCheck(t *testing.T) {
t.Error("Incorrect host header, check disabled: expected 200 OK, not", resp.Status) t.Error("Incorrect host header, check disabled: expected 200 OK, not", resp.Status)
} }
if !testing.Short() {
// A server bound to a wildcard address also doesn't do the check // A server bound to a wildcard address also doesn't do the check
cfg = newMockedConfig() cfg = newMockedConfig()
cfg.GUIReturns(config.GUIConfiguration{ cfg.GUIReturns(config.GUIConfiguration{
RawAddress: "0.0.0.0:0", RawAddress: "0.0.0.0:0",
InsecureSkipHostCheck: true,
}) })
baseURL, cancel, err = startHTTP(cfg) baseURL, cancel, err = startHTTP(cfg)
if err != nil { if err != nil {
@ -1075,6 +1078,7 @@ func TestHostCheck(t *testing.T) {
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
t.Error("Incorrect host header, wildcard bound: expected 200 OK, not", resp.Status) t.Error("Incorrect host header, wildcard bound: expected 200 OK, not", resp.Status)
} }
}
// This should all work over IPv6 as well // This should all work over IPv6 as well

View File

@ -32,12 +32,12 @@ func newFakeConnection(id protocol.DeviceID, model Model) *fakeConnection {
f.RequestCalls(func(ctx context.Context, folder, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) { f.RequestCalls(func(ctx context.Context, folder, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
return f.fileData[name], nil return f.fileData[name], nil
}) })
f.IDReturns(id) f.DeviceIDReturns(id)
f.CloseCalls(func(err error) { f.CloseCalls(func(err error) {
f.closeOnce.Do(func() { f.closeOnce.Do(func() {
close(f.closed) close(f.closed)
}) })
model.Closed(id, err) model.Closed(f, err)
f.ClosedReturns(f.closed) f.ClosedReturns(f.closed)
}) })
return f return f
@ -157,7 +157,7 @@ func (f *fakeConnection) sendIndexUpdate() {
for i := range f.files { for i := range f.files {
toSend[i] = prepareFileInfoForIndex(f.files[i]) toSend[i] = prepareFileInfoForIndex(f.files[i])
} }
f.model.IndexUpdate(f.id, f.folder, toSend) f.model.IndexUpdate(f, f.folder, toSend)
} }
func addFakeConn(m *testModel, dev protocol.DeviceID, folderID string) *fakeConnection { func addFakeConn(m *testModel, dev protocol.DeviceID, folderID string) *fakeConnection {
@ -165,7 +165,7 @@ func addFakeConn(m *testModel, dev protocol.DeviceID, folderID string) *fakeConn
fc.folder = folderID fc.folder = folderID
m.AddConnection(fc, protocol.Hello{}) m.AddConnection(fc, protocol.Hello{})
m.ClusterConfig(dev, protocol.ClusterConfig{ m.ClusterConfig(fc, protocol.ClusterConfig{
Folders: []protocol.Folder{ Folders: []protocol.Folder{
{ {
ID: folderID, ID: folderID,

View File

@ -30,7 +30,7 @@ func TestRecvOnlyRevertDeletes(t *testing.T) {
defer wcfgCancel() defer wcfgCancel()
ffs := f.Filesystem(nil) ffs := f.Filesystem(nil)
defer cleanupModel(m) defer cleanupModel(m)
addFakeConn(m, device1, f.ID) conn := addFakeConn(m, device1, f.ID)
// Create some test data // Create some test data
@ -45,7 +45,7 @@ func TestRecvOnlyRevertDeletes(t *testing.T) {
// Send and index update for the known stuff // Send and index update for the known stuff
must(t, m.Index(device1, "ro", knownFiles)) must(t, m.Index(conn, "ro", knownFiles))
f.updateLocalsFromScanning(knownFiles) f.updateLocalsFromScanning(knownFiles)
size := globalSize(t, m, "ro") size := globalSize(t, m, "ro")
@ -112,7 +112,7 @@ func TestRecvOnlyRevertNeeds(t *testing.T) {
defer wcfgCancel() defer wcfgCancel()
ffs := f.Filesystem(nil) ffs := f.Filesystem(nil)
defer cleanupModel(m) defer cleanupModel(m)
addFakeConn(m, device1, f.ID) conn := addFakeConn(m, device1, f.ID)
// Create some test data // Create some test data
@ -122,7 +122,7 @@ func TestRecvOnlyRevertNeeds(t *testing.T) {
// Send and index update for the known stuff // Send and index update for the known stuff
must(t, m.Index(device1, "ro", knownFiles)) must(t, m.Index(conn, "ro", knownFiles))
f.updateLocalsFromScanning(knownFiles) f.updateLocalsFromScanning(knownFiles)
// Scan the folder. // Scan the folder.
@ -202,7 +202,7 @@ func TestRecvOnlyUndoChanges(t *testing.T) {
defer wcfgCancel() defer wcfgCancel()
ffs := f.Filesystem(nil) ffs := f.Filesystem(nil)
defer cleanupModel(m) defer cleanupModel(m)
addFakeConn(m, device1, f.ID) conn := addFakeConn(m, device1, f.ID)
// Create some test data // Create some test data
@ -212,7 +212,7 @@ func TestRecvOnlyUndoChanges(t *testing.T) {
// Send an index update for the known stuff // Send an index update for the known stuff
must(t, m.Index(device1, "ro", knownFiles)) must(t, m.Index(conn, "ro", knownFiles))
f.updateLocalsFromScanning(knownFiles) f.updateLocalsFromScanning(knownFiles)
// Scan the folder. // Scan the folder.
@ -272,7 +272,7 @@ func TestRecvOnlyDeletedRemoteDrop(t *testing.T) {
defer wcfgCancel() defer wcfgCancel()
ffs := f.Filesystem(nil) ffs := f.Filesystem(nil)
defer cleanupModel(m) defer cleanupModel(m)
addFakeConn(m, device1, f.ID) conn := addFakeConn(m, device1, f.ID)
// Create some test data // Create some test data
@ -282,7 +282,7 @@ func TestRecvOnlyDeletedRemoteDrop(t *testing.T) {
// Send an index update for the known stuff // Send an index update for the known stuff
must(t, m.Index(device1, "ro", knownFiles)) must(t, m.Index(conn, "ro", knownFiles))
f.updateLocalsFromScanning(knownFiles) f.updateLocalsFromScanning(knownFiles)
// Scan the folder. // Scan the folder.
@ -337,7 +337,7 @@ func TestRecvOnlyRemoteUndoChanges(t *testing.T) {
defer wcfgCancel() defer wcfgCancel()
ffs := f.Filesystem(nil) ffs := f.Filesystem(nil)
defer cleanupModel(m) defer cleanupModel(m)
addFakeConn(m, device1, f.ID) conn := addFakeConn(m, device1, f.ID)
// Create some test data // Create some test data
@ -347,7 +347,7 @@ func TestRecvOnlyRemoteUndoChanges(t *testing.T) {
// Send an index update for the known stuff // Send an index update for the known stuff
must(t, m.Index(device1, "ro", knownFiles)) must(t, m.Index(conn, "ro", knownFiles))
f.updateLocalsFromScanning(knownFiles) f.updateLocalsFromScanning(knownFiles)
// Scan the folder. // Scan the folder.
@ -402,7 +402,7 @@ func TestRecvOnlyRemoteUndoChanges(t *testing.T) {
return true return true
}) })
snap.Release() snap.Release()
must(t, m.IndexUpdate(device1, "ro", files)) must(t, m.IndexUpdate(conn, "ro", files))
// Ensure the pull to resolve conflicts (content identical) happened // Ensure the pull to resolve conflicts (content identical) happened
must(t, f.doInSync(func() error { must(t, f.doInSync(func() error {
@ -427,7 +427,7 @@ func TestRecvOnlyRevertOwnID(t *testing.T) {
defer wcfgCancel() defer wcfgCancel()
ffs := f.Filesystem(nil) ffs := f.Filesystem(nil)
defer cleanupModel(m) defer cleanupModel(m)
addFakeConn(m, device1, f.ID) conn := addFakeConn(m, device1, f.ID)
// Create some test data // Create some test data
@ -470,7 +470,7 @@ func TestRecvOnlyRevertOwnID(t *testing.T) {
}() }()
// Receive an index update with an older version, but valid and then revert // Receive an index update with an older version, but valid and then revert
must(t, m.Index(device1, f.ID, []protocol.FileInfo{fi})) must(t, m.Index(conn, f.ID, []protocol.FileInfo{fi}))
f.Revert() f.Revert()
select { select {

View File

@ -1278,7 +1278,7 @@ func TestPullSymlinkOverExistingWindows(t *testing.T) {
m, f, wcfgCancel := setupSendReceiveFolder(t) m, f, wcfgCancel := setupSendReceiveFolder(t)
defer wcfgCancel() defer wcfgCancel()
addFakeConn(m, device1, f.ID) conn := addFakeConn(m, device1, f.ID)
name := "foo" name := "foo"
if fd, err := f.mtimefs.Create(name); err != nil { if fd, err := f.mtimefs.Create(name); err != nil {
@ -1296,7 +1296,7 @@ func TestPullSymlinkOverExistingWindows(t *testing.T) {
if !ok { if !ok {
t.Fatal("file missing") t.Fatal("file missing")
} }
must(t, m.Index(device1, f.ID, []protocol.FileInfo{{Name: name, Type: protocol.FileInfoTypeSymlink, Version: file.Version.Update(device1.Short())}})) must(t, m.Index(conn, f.ID, []protocol.FileInfo{{Name: name, Type: protocol.FileInfoTypeSymlink, Version: file.Version.Update(device1.Short())}}))
scanChan := make(chan string) scanChan := make(chan string)

View File

@ -56,10 +56,10 @@ func newIndexHandler(conn protocol.Connection, downloads *deviceDownloadState, f
// the IndexID, or something else weird has // the IndexID, or something else weird has
// happened. We send a full index to reset the // happened. We send a full index to reset the
// situation. // situation.
l.Infof("Device %v folder %s is delta index compatible, but seems out of sync with reality", conn.ID().Short(), folder.Description()) l.Infof("Device %v folder %s is delta index compatible, but seems out of sync with reality", conn.DeviceID().Short(), folder.Description())
startSequence = 0 startSequence = 0
} else { } else {
l.Debugf("Device %v folder %s is delta index compatible (mlv=%d)", conn.ID().Short(), folder.Description(), startInfo.local.MaxSequence) l.Debugf("Device %v folder %s is delta index compatible (mlv=%d)", conn.DeviceID().Short(), folder.Description(), startInfo.local.MaxSequence)
startSequence = startInfo.local.MaxSequence startSequence = startInfo.local.MaxSequence
} }
} else if startInfo.local.IndexID != 0 { } else if startInfo.local.IndexID != 0 {
@ -67,10 +67,10 @@ func newIndexHandler(conn protocol.Connection, downloads *deviceDownloadState, f
// not the right one. Either they are confused or we // not the right one. Either they are confused or we
// must have reset our database since last talking to // must have reset our database since last talking to
// them. We'll start with a full index transfer. // them. We'll start with a full index transfer.
l.Infof("Device %v folder %s has mismatching index ID for us (%v != %v)", conn.ID().Short(), folder.Description(), startInfo.local.IndexID, myIndexID) l.Infof("Device %v folder %s has mismatching index ID for us (%v != %v)", conn.DeviceID().Short(), folder.Description(), startInfo.local.IndexID, myIndexID)
startSequence = 0 startSequence = 0
} else { } else {
l.Debugf("Device %v folder %s has no index ID for us", conn.ID().Short(), folder.Description()) l.Debugf("Device %v folder %s has no index ID for us", conn.DeviceID().Short(), folder.Description())
} }
// This is the other side's description of themselves. We // This is the other side's description of themselves. We
@ -78,23 +78,23 @@ func newIndexHandler(conn protocol.Connection, downloads *deviceDownloadState, f
// otherwise we drop our old index data and expect to get a // otherwise we drop our old index data and expect to get a
// completely new set. // completely new set.
theirIndexID := fset.IndexID(conn.ID()) theirIndexID := fset.IndexID(conn.DeviceID())
if startInfo.remote.IndexID == 0 { if startInfo.remote.IndexID == 0 {
// They're not announcing an index ID. This means they // They're not announcing an index ID. This means they
// do not support delta indexes and we should clear any // do not support delta indexes and we should clear any
// information we have from them before accepting their // information we have from them before accepting their
// index, which will presumably be a full index. // index, which will presumably be a full index.
l.Debugf("Device %v folder %s does not announce an index ID", conn.ID().Short(), folder.Description()) l.Debugf("Device %v folder %s does not announce an index ID", conn.DeviceID().Short(), folder.Description())
fset.Drop(conn.ID()) fset.Drop(conn.DeviceID())
} else if startInfo.remote.IndexID != theirIndexID { } else if startInfo.remote.IndexID != theirIndexID {
// The index ID we have on file is not what they're // The index ID we have on file is not what they're
// announcing. They must have reset their database and // announcing. They must have reset their database and
// will probably send us a full index. We drop any // will probably send us a full index. We drop any
// information we have and remember this new index ID // information we have and remember this new index ID
// instead. // instead.
l.Infof("Device %v folder %s has a new index ID (%v)", conn.ID().Short(), folder.Description(), startInfo.remote.IndexID) l.Infof("Device %v folder %s has a new index ID (%v)", conn.DeviceID().Short(), folder.Description(), startInfo.remote.IndexID)
fset.Drop(conn.ID()) fset.Drop(conn.DeviceID())
fset.SetIndexID(conn.ID(), startInfo.remote.IndexID) fset.SetIndexID(conn.DeviceID(), startInfo.remote.IndexID)
} }
return &indexHandler{ return &indexHandler{
@ -129,12 +129,12 @@ func (s *indexHandler) waitForFileset(ctx context.Context) (*db.FileSet, error)
} }
func (s *indexHandler) Serve(ctx context.Context) (err error) { func (s *indexHandler) Serve(ctx context.Context) (err error) {
l.Debugf("Starting index handler for %s to %s at %s (slv=%d)", s.folder, s.conn.ID(), s.conn, s.prevSequence) l.Debugf("Starting index handler for %s to %s at %s (slv=%d)", s.folder, s.conn.DeviceID().Short(), s.conn, s.prevSequence)
stop := make(chan struct{}) stop := make(chan struct{})
defer func() { defer func() {
err = svcutil.NoRestartErr(err) err = svcutil.NoRestartErr(err)
l.Debugf("Exiting index handler for %s to %s at %s: %v", s.folder, s.conn.ID(), s.conn, err) l.Debugf("Exiting index handler for %s to %s at %s: %v", s.folder, s.conn.DeviceID().Short(), s.conn, err)
close(stop) close(stop)
}() }()
@ -308,7 +308,7 @@ func (s *indexHandler) sendIndexTo(ctx context.Context, fset *db.FileSet) error
} }
func (s *indexHandler) receive(fs []protocol.FileInfo, update bool, op string) error { func (s *indexHandler) receive(fs []protocol.FileInfo, update bool, op string) error {
deviceID := s.conn.ID() deviceID := s.conn.DeviceID()
s.cond.L.Lock() s.cond.L.Lock()
paused := s.paused paused := s.paused
@ -369,7 +369,7 @@ func prepareFileInfoForIndex(f protocol.FileInfo) protocol.FileInfo {
} }
func (s *indexHandler) String() string { func (s *indexHandler) String() string {
return fmt.Sprintf("indexHandler@%p for %s to %s at %s", s, s.folder, s.conn.ID().Short(), s.conn) return fmt.Sprintf("indexHandler@%p for %s to %s at %s", s, s.folder, s.conn.DeviceID().Short(), s.conn)
} }
type indexHandlerRegistry struct { type indexHandlerRegistry struct {
@ -414,7 +414,7 @@ func newIndexHandlerRegistry(conn protocol.Connection, downloads *deviceDownload
} }
func (r *indexHandlerRegistry) String() string { func (r *indexHandlerRegistry) String() string {
return fmt.Sprintf("indexHandlerRegistry/%v", r.conn.ID().Short()) return fmt.Sprintf("indexHandlerRegistry/%v", r.conn.DeviceID().Short())
} }
func (r *indexHandlerRegistry) GetSupervisor() *suture.Supervisor { func (r *indexHandlerRegistry) GetSupervisor() *suture.Supervisor {
@ -447,11 +447,11 @@ func (r *indexHandlerRegistry) AddIndexInfo(folder string, startInfo *clusterCon
if is, ok := r.indexHandlers[folder]; ok { if is, ok := r.indexHandlers[folder]; ok {
r.sup.RemoveAndWait(is.token, 0) r.sup.RemoveAndWait(is.token, 0)
delete(r.indexHandlers, folder) delete(r.indexHandlers, folder)
l.Debugf("Removed index sender for device %v and folder %v due to added pending", r.conn.ID().Short(), folder) l.Debugf("Removed index sender for device %v and folder %v due to added pending", r.conn.DeviceID().Short(), folder)
} }
folderState, ok := r.folderStates[folder] folderState, ok := r.folderStates[folder]
if !ok { if !ok {
l.Debugf("Pending index handler for device %v and folder %v", r.conn.ID().Short(), folder) l.Debugf("Pending index handler for device %v and folder %v", r.conn.DeviceID().Short(), folder)
r.startInfos[folder] = startInfo r.startInfos[folder] = startInfo
return return
} }
@ -464,13 +464,13 @@ func (r *indexHandlerRegistry) Remove(folder string) {
r.mut.Lock() r.mut.Lock()
defer r.mut.Unlock() defer r.mut.Unlock()
l.Debugf("Removing index handler for device %v and folder %v", r.conn.ID().Short(), folder) l.Debugf("Removing index handler for device %v and folder %v", r.conn.DeviceID().Short(), folder)
if is, ok := r.indexHandlers[folder]; ok { if is, ok := r.indexHandlers[folder]; ok {
r.sup.RemoveAndWait(is.token, 0) r.sup.RemoveAndWait(is.token, 0)
delete(r.indexHandlers, folder) delete(r.indexHandlers, folder)
} }
delete(r.startInfos, folder) delete(r.startInfos, folder)
l.Debugf("Removed index handler for device %v and folder %v", r.conn.ID().Short(), folder) l.Debugf("Removed index handler for device %v and folder %v", r.conn.DeviceID().Short(), folder)
} }
// RemoveAllExcept stops all running index handlers and removes those pending to be started, // RemoveAllExcept stops all running index handlers and removes those pending to be started,
@ -484,13 +484,13 @@ func (r *indexHandlerRegistry) RemoveAllExcept(except map[string]remoteFolderSta
if _, ok := except[folder]; !ok { if _, ok := except[folder]; !ok {
r.sup.RemoveAndWait(is.token, 0) r.sup.RemoveAndWait(is.token, 0)
delete(r.indexHandlers, folder) delete(r.indexHandlers, folder)
l.Debugf("Removed index handler for device %v and folder %v (removeAllExcept)", r.conn.ID().Short(), folder) l.Debugf("Removed index handler for device %v and folder %v (removeAllExcept)", r.conn.DeviceID().Short(), folder)
} }
} }
for folder := range r.startInfos { for folder := range r.startInfos {
if _, ok := except[folder]; !ok { if _, ok := except[folder]; !ok {
delete(r.startInfos, folder) delete(r.startInfos, folder)
l.Debugf("Removed pending index handler for device %v and folder %v (removeAllExcept)", r.conn.ID().Short(), folder) l.Debugf("Removed pending index handler for device %v and folder %v (removeAllExcept)", r.conn.DeviceID().Short(), folder)
} }
} }
} }
@ -499,7 +499,7 @@ func (r *indexHandlerRegistry) RemoveAllExcept(except map[string]remoteFolderSta
// changes. The exception being if the folder is removed entirely, then call // changes. The exception being if the folder is removed entirely, then call
// Remove. The fset and runner arguments may be nil, if given folder is paused. // Remove. The fset and runner arguments may be nil, if given folder is paused.
func (r *indexHandlerRegistry) RegisterFolderState(folder config.FolderConfiguration, fset *db.FileSet, runner service) { func (r *indexHandlerRegistry) RegisterFolderState(folder config.FolderConfiguration, fset *db.FileSet, runner service) {
if !folder.SharedWith(r.conn.ID()) { if !folder.SharedWith(r.conn.DeviceID()) {
r.Remove(folder.ID) r.Remove(folder.ID)
return return
} }
@ -516,13 +516,13 @@ func (r *indexHandlerRegistry) RegisterFolderState(folder config.FolderConfigura
// folderPausedLocked stops a running index handler. // folderPausedLocked stops a running index handler.
// It is a noop if the folder isn't known or has not been started yet. // It is a noop if the folder isn't known or has not been started yet.
func (r *indexHandlerRegistry) folderPausedLocked(folder string) { func (r *indexHandlerRegistry) folderPausedLocked(folder string) {
l.Debugf("Pausing index handler for device %v and folder %v", r.conn.ID().Short(), folder) l.Debugf("Pausing index handler for device %v and folder %v", r.conn.DeviceID().Short(), folder)
delete(r.folderStates, folder) delete(r.folderStates, folder)
if is, ok := r.indexHandlers[folder]; ok { if is, ok := r.indexHandlers[folder]; ok {
is.pause() is.pause()
l.Debugf("Paused index handler for device %v and folder %v", r.conn.ID().Short(), folder) l.Debugf("Paused index handler for device %v and folder %v", r.conn.DeviceID().Short(), folder)
} else { } else {
l.Debugf("No index handler for device %v and folder %v to pause", r.conn.ID().Short(), folder) l.Debugf("No index handler for device %v and folder %v to pause", r.conn.DeviceID().Short(), folder)
} }
} }
@ -541,16 +541,16 @@ func (r *indexHandlerRegistry) folderRunningLocked(folder config.FolderConfigura
if isOk { if isOk {
r.sup.RemoveAndWait(is.token, 0) r.sup.RemoveAndWait(is.token, 0)
delete(r.indexHandlers, folder.ID) delete(r.indexHandlers, folder.ID)
l.Debugf("Removed index handler for device %v and folder %v in resume", r.conn.ID().Short(), folder.ID) l.Debugf("Removed index handler for device %v and folder %v in resume", r.conn.DeviceID().Short(), folder.ID)
} }
r.startLocked(folder, fset, runner, info) r.startLocked(folder, fset, runner, info)
delete(r.startInfos, folder.ID) delete(r.startInfos, folder.ID)
l.Debugf("Started index handler for device %v and folder %v in resume", r.conn.ID().Short(), folder.ID) l.Debugf("Started index handler for device %v and folder %v in resume", r.conn.DeviceID().Short(), folder.ID)
} else if isOk { } else if isOk {
l.Debugf("Resuming index handler for device %v and folder %v", r.conn.ID().Short(), folder) l.Debugf("Resuming index handler for device %v and folder %v", r.conn.DeviceID().Short(), folder)
is.resume(fset, runner) is.resume(fset, runner)
} else { } else {
l.Debugf("Not resuming index handler for device %v and folder %v as none is paused and there is no start info", r.conn.ID().Short(), folder.ID) l.Debugf("Not resuming index handler for device %v and folder %v as none is paused and there is no start info", r.conn.DeviceID().Short(), folder.ID)
} }
} }
@ -560,7 +560,7 @@ func (r *indexHandlerRegistry) ReceiveIndex(folder string, fs []protocol.FileInf
is, isOk := r.indexHandlers[folder] is, isOk := r.indexHandlers[folder]
if !isOk { if !isOk {
l.Infof("%v for nonexistent or paused folder %q", op, folder) l.Infof("%v for nonexistent or paused folder %q", op, folder)
return ErrFolderMissing return fmt.Errorf("%s: %w", folder, ErrFolderMissing)
} }
return is.receive(fs, update, op) return is.receive(fs, update, op)
} }

View File

@ -44,16 +44,16 @@ type Model struct {
arg1 string arg1 string
arg2 string arg2 string
} }
ClosedStub func(protocol.DeviceID, error) ClosedStub func(protocol.Connection, error)
closedMutex sync.RWMutex closedMutex sync.RWMutex
closedArgsForCall []struct { closedArgsForCall []struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 error arg2 error
} }
ClusterConfigStub func(protocol.DeviceID, protocol.ClusterConfig) error ClusterConfigStub func(protocol.Connection, protocol.ClusterConfig) error
clusterConfigMutex sync.RWMutex clusterConfigMutex sync.RWMutex
clusterConfigArgsForCall []struct { clusterConfigArgsForCall []struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 protocol.ClusterConfig arg2 protocol.ClusterConfig
} }
clusterConfigReturns struct { clusterConfigReturns struct {
@ -200,10 +200,10 @@ type Model struct {
dismissPendingFolderReturnsOnCall map[int]struct { dismissPendingFolderReturnsOnCall map[int]struct {
result1 error result1 error
} }
DownloadProgressStub func(protocol.DeviceID, string, []protocol.FileDownloadProgressUpdate) error DownloadProgressStub func(protocol.Connection, string, []protocol.FileDownloadProgressUpdate) error
downloadProgressMutex sync.RWMutex downloadProgressMutex sync.RWMutex
downloadProgressArgsForCall []struct { downloadProgressArgsForCall []struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 string arg2 string
arg3 []protocol.FileDownloadProgressUpdate arg3 []protocol.FileDownloadProgressUpdate
} }
@ -303,10 +303,10 @@ type Model struct {
result1 []*model.TreeEntry result1 []*model.TreeEntry
result2 error result2 error
} }
IndexStub func(protocol.DeviceID, string, []protocol.FileInfo) error IndexStub func(protocol.Connection, string, []protocol.FileInfo) error
indexMutex sync.RWMutex indexMutex sync.RWMutex
indexArgsForCall []struct { indexArgsForCall []struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 string arg2 string
arg3 []protocol.FileInfo arg3 []protocol.FileInfo
} }
@ -316,10 +316,10 @@ type Model struct {
indexReturnsOnCall map[int]struct { indexReturnsOnCall map[int]struct {
result1 error result1 error
} }
IndexUpdateStub func(protocol.DeviceID, string, []protocol.FileInfo) error IndexUpdateStub func(protocol.Connection, string, []protocol.FileInfo) error
indexUpdateMutex sync.RWMutex indexUpdateMutex sync.RWMutex
indexUpdateArgsForCall []struct { indexUpdateArgsForCall []struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 string arg2 string
arg3 []protocol.FileInfo arg3 []protocol.FileInfo
} }
@ -447,10 +447,10 @@ type Model struct {
result1 []db.FileInfoTruncated result1 []db.FileInfoTruncated
result2 error result2 error
} }
RequestStub func(protocol.DeviceID, string, string, int32, int32, int64, []byte, uint32, bool) (protocol.RequestResponse, error) RequestStub func(protocol.Connection, string, string, int32, int32, int64, []byte, uint32, bool) (protocol.RequestResponse, error)
requestMutex sync.RWMutex requestMutex sync.RWMutex
requestArgsForCall []struct { requestArgsForCall []struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 string arg2 string
arg3 string arg3 string
arg4 int32 arg4 int32
@ -728,10 +728,10 @@ func (fake *Model) BringToFrontArgsForCall(i int) (string, string) {
return argsForCall.arg1, argsForCall.arg2 return argsForCall.arg1, argsForCall.arg2
} }
func (fake *Model) Closed(arg1 protocol.DeviceID, arg2 error) { func (fake *Model) Closed(arg1 protocol.Connection, arg2 error) {
fake.closedMutex.Lock() fake.closedMutex.Lock()
fake.closedArgsForCall = append(fake.closedArgsForCall, struct { fake.closedArgsForCall = append(fake.closedArgsForCall, struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 error arg2 error
}{arg1, arg2}) }{arg1, arg2})
stub := fake.ClosedStub stub := fake.ClosedStub
@ -748,24 +748,24 @@ func (fake *Model) ClosedCallCount() int {
return len(fake.closedArgsForCall) return len(fake.closedArgsForCall)
} }
func (fake *Model) ClosedCalls(stub func(protocol.DeviceID, error)) { func (fake *Model) ClosedCalls(stub func(protocol.Connection, error)) {
fake.closedMutex.Lock() fake.closedMutex.Lock()
defer fake.closedMutex.Unlock() defer fake.closedMutex.Unlock()
fake.ClosedStub = stub fake.ClosedStub = stub
} }
func (fake *Model) ClosedArgsForCall(i int) (protocol.DeviceID, error) { func (fake *Model) ClosedArgsForCall(i int) (protocol.Connection, error) {
fake.closedMutex.RLock() fake.closedMutex.RLock()
defer fake.closedMutex.RUnlock() defer fake.closedMutex.RUnlock()
argsForCall := fake.closedArgsForCall[i] argsForCall := fake.closedArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2 return argsForCall.arg1, argsForCall.arg2
} }
func (fake *Model) ClusterConfig(arg1 protocol.DeviceID, arg2 protocol.ClusterConfig) error { func (fake *Model) ClusterConfig(arg1 protocol.Connection, arg2 protocol.ClusterConfig) error {
fake.clusterConfigMutex.Lock() fake.clusterConfigMutex.Lock()
ret, specificReturn := fake.clusterConfigReturnsOnCall[len(fake.clusterConfigArgsForCall)] ret, specificReturn := fake.clusterConfigReturnsOnCall[len(fake.clusterConfigArgsForCall)]
fake.clusterConfigArgsForCall = append(fake.clusterConfigArgsForCall, struct { fake.clusterConfigArgsForCall = append(fake.clusterConfigArgsForCall, struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 protocol.ClusterConfig arg2 protocol.ClusterConfig
}{arg1, arg2}) }{arg1, arg2})
stub := fake.ClusterConfigStub stub := fake.ClusterConfigStub
@ -787,13 +787,13 @@ func (fake *Model) ClusterConfigCallCount() int {
return len(fake.clusterConfigArgsForCall) return len(fake.clusterConfigArgsForCall)
} }
func (fake *Model) ClusterConfigCalls(stub func(protocol.DeviceID, protocol.ClusterConfig) error) { func (fake *Model) ClusterConfigCalls(stub func(protocol.Connection, protocol.ClusterConfig) error) {
fake.clusterConfigMutex.Lock() fake.clusterConfigMutex.Lock()
defer fake.clusterConfigMutex.Unlock() defer fake.clusterConfigMutex.Unlock()
fake.ClusterConfigStub = stub fake.ClusterConfigStub = stub
} }
func (fake *Model) ClusterConfigArgsForCall(i int) (protocol.DeviceID, protocol.ClusterConfig) { func (fake *Model) ClusterConfigArgsForCall(i int) (protocol.Connection, protocol.ClusterConfig) {
fake.clusterConfigMutex.RLock() fake.clusterConfigMutex.RLock()
defer fake.clusterConfigMutex.RUnlock() defer fake.clusterConfigMutex.RUnlock()
argsForCall := fake.clusterConfigArgsForCall[i] argsForCall := fake.clusterConfigArgsForCall[i]
@ -1484,7 +1484,7 @@ func (fake *Model) DismissPendingFolderReturnsOnCall(i int, result1 error) {
}{result1} }{result1}
} }
func (fake *Model) DownloadProgress(arg1 protocol.DeviceID, arg2 string, arg3 []protocol.FileDownloadProgressUpdate) error { func (fake *Model) DownloadProgress(arg1 protocol.Connection, arg2 string, arg3 []protocol.FileDownloadProgressUpdate) error {
var arg3Copy []protocol.FileDownloadProgressUpdate var arg3Copy []protocol.FileDownloadProgressUpdate
if arg3 != nil { if arg3 != nil {
arg3Copy = make([]protocol.FileDownloadProgressUpdate, len(arg3)) arg3Copy = make([]protocol.FileDownloadProgressUpdate, len(arg3))
@ -1493,7 +1493,7 @@ func (fake *Model) DownloadProgress(arg1 protocol.DeviceID, arg2 string, arg3 []
fake.downloadProgressMutex.Lock() fake.downloadProgressMutex.Lock()
ret, specificReturn := fake.downloadProgressReturnsOnCall[len(fake.downloadProgressArgsForCall)] ret, specificReturn := fake.downloadProgressReturnsOnCall[len(fake.downloadProgressArgsForCall)]
fake.downloadProgressArgsForCall = append(fake.downloadProgressArgsForCall, struct { fake.downloadProgressArgsForCall = append(fake.downloadProgressArgsForCall, struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 string arg2 string
arg3 []protocol.FileDownloadProgressUpdate arg3 []protocol.FileDownloadProgressUpdate
}{arg1, arg2, arg3Copy}) }{arg1, arg2, arg3Copy})
@ -1516,13 +1516,13 @@ func (fake *Model) DownloadProgressCallCount() int {
return len(fake.downloadProgressArgsForCall) return len(fake.downloadProgressArgsForCall)
} }
func (fake *Model) DownloadProgressCalls(stub func(protocol.DeviceID, string, []protocol.FileDownloadProgressUpdate) error) { func (fake *Model) DownloadProgressCalls(stub func(protocol.Connection, string, []protocol.FileDownloadProgressUpdate) error) {
fake.downloadProgressMutex.Lock() fake.downloadProgressMutex.Lock()
defer fake.downloadProgressMutex.Unlock() defer fake.downloadProgressMutex.Unlock()
fake.DownloadProgressStub = stub fake.DownloadProgressStub = stub
} }
func (fake *Model) DownloadProgressArgsForCall(i int) (protocol.DeviceID, string, []protocol.FileDownloadProgressUpdate) { func (fake *Model) DownloadProgressArgsForCall(i int) (protocol.Connection, string, []protocol.FileDownloadProgressUpdate) {
fake.downloadProgressMutex.RLock() fake.downloadProgressMutex.RLock()
defer fake.downloadProgressMutex.RUnlock() defer fake.downloadProgressMutex.RUnlock()
argsForCall := fake.downloadProgressArgsForCall[i] argsForCall := fake.downloadProgressArgsForCall[i]
@ -1990,7 +1990,7 @@ func (fake *Model) GlobalDirectoryTreeReturnsOnCall(i int, result1 []*model.Tree
}{result1, result2} }{result1, result2}
} }
func (fake *Model) Index(arg1 protocol.DeviceID, arg2 string, arg3 []protocol.FileInfo) error { func (fake *Model) Index(arg1 protocol.Connection, arg2 string, arg3 []protocol.FileInfo) error {
var arg3Copy []protocol.FileInfo var arg3Copy []protocol.FileInfo
if arg3 != nil { if arg3 != nil {
arg3Copy = make([]protocol.FileInfo, len(arg3)) arg3Copy = make([]protocol.FileInfo, len(arg3))
@ -1999,7 +1999,7 @@ func (fake *Model) Index(arg1 protocol.DeviceID, arg2 string, arg3 []protocol.Fi
fake.indexMutex.Lock() fake.indexMutex.Lock()
ret, specificReturn := fake.indexReturnsOnCall[len(fake.indexArgsForCall)] ret, specificReturn := fake.indexReturnsOnCall[len(fake.indexArgsForCall)]
fake.indexArgsForCall = append(fake.indexArgsForCall, struct { fake.indexArgsForCall = append(fake.indexArgsForCall, struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 string arg2 string
arg3 []protocol.FileInfo arg3 []protocol.FileInfo
}{arg1, arg2, arg3Copy}) }{arg1, arg2, arg3Copy})
@ -2022,13 +2022,13 @@ func (fake *Model) IndexCallCount() int {
return len(fake.indexArgsForCall) return len(fake.indexArgsForCall)
} }
func (fake *Model) IndexCalls(stub func(protocol.DeviceID, string, []protocol.FileInfo) error) { func (fake *Model) IndexCalls(stub func(protocol.Connection, string, []protocol.FileInfo) error) {
fake.indexMutex.Lock() fake.indexMutex.Lock()
defer fake.indexMutex.Unlock() defer fake.indexMutex.Unlock()
fake.IndexStub = stub fake.IndexStub = stub
} }
func (fake *Model) IndexArgsForCall(i int) (protocol.DeviceID, string, []protocol.FileInfo) { func (fake *Model) IndexArgsForCall(i int) (protocol.Connection, string, []protocol.FileInfo) {
fake.indexMutex.RLock() fake.indexMutex.RLock()
defer fake.indexMutex.RUnlock() defer fake.indexMutex.RUnlock()
argsForCall := fake.indexArgsForCall[i] argsForCall := fake.indexArgsForCall[i]
@ -2058,7 +2058,7 @@ func (fake *Model) IndexReturnsOnCall(i int, result1 error) {
}{result1} }{result1}
} }
func (fake *Model) IndexUpdate(arg1 protocol.DeviceID, arg2 string, arg3 []protocol.FileInfo) error { func (fake *Model) IndexUpdate(arg1 protocol.Connection, arg2 string, arg3 []protocol.FileInfo) error {
var arg3Copy []protocol.FileInfo var arg3Copy []protocol.FileInfo
if arg3 != nil { if arg3 != nil {
arg3Copy = make([]protocol.FileInfo, len(arg3)) arg3Copy = make([]protocol.FileInfo, len(arg3))
@ -2067,7 +2067,7 @@ func (fake *Model) IndexUpdate(arg1 protocol.DeviceID, arg2 string, arg3 []proto
fake.indexUpdateMutex.Lock() fake.indexUpdateMutex.Lock()
ret, specificReturn := fake.indexUpdateReturnsOnCall[len(fake.indexUpdateArgsForCall)] ret, specificReturn := fake.indexUpdateReturnsOnCall[len(fake.indexUpdateArgsForCall)]
fake.indexUpdateArgsForCall = append(fake.indexUpdateArgsForCall, struct { fake.indexUpdateArgsForCall = append(fake.indexUpdateArgsForCall, struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 string arg2 string
arg3 []protocol.FileInfo arg3 []protocol.FileInfo
}{arg1, arg2, arg3Copy}) }{arg1, arg2, arg3Copy})
@ -2090,13 +2090,13 @@ func (fake *Model) IndexUpdateCallCount() int {
return len(fake.indexUpdateArgsForCall) return len(fake.indexUpdateArgsForCall)
} }
func (fake *Model) IndexUpdateCalls(stub func(protocol.DeviceID, string, []protocol.FileInfo) error) { func (fake *Model) IndexUpdateCalls(stub func(protocol.Connection, string, []protocol.FileInfo) error) {
fake.indexUpdateMutex.Lock() fake.indexUpdateMutex.Lock()
defer fake.indexUpdateMutex.Unlock() defer fake.indexUpdateMutex.Unlock()
fake.IndexUpdateStub = stub fake.IndexUpdateStub = stub
} }
func (fake *Model) IndexUpdateArgsForCall(i int) (protocol.DeviceID, string, []protocol.FileInfo) { func (fake *Model) IndexUpdateArgsForCall(i int) (protocol.Connection, string, []protocol.FileInfo) {
fake.indexUpdateMutex.RLock() fake.indexUpdateMutex.RLock()
defer fake.indexUpdateMutex.RUnlock() defer fake.indexUpdateMutex.RUnlock()
argsForCall := fake.indexUpdateArgsForCall[i] argsForCall := fake.indexUpdateArgsForCall[i]
@ -2666,7 +2666,7 @@ func (fake *Model) RemoteNeedFolderFilesReturnsOnCall(i int, result1 []db.FileIn
}{result1, result2} }{result1, result2}
} }
func (fake *Model) Request(arg1 protocol.DeviceID, arg2 string, arg3 string, arg4 int32, arg5 int32, arg6 int64, arg7 []byte, arg8 uint32, arg9 bool) (protocol.RequestResponse, error) { func (fake *Model) Request(arg1 protocol.Connection, arg2 string, arg3 string, arg4 int32, arg5 int32, arg6 int64, arg7 []byte, arg8 uint32, arg9 bool) (protocol.RequestResponse, error) {
var arg7Copy []byte var arg7Copy []byte
if arg7 != nil { if arg7 != nil {
arg7Copy = make([]byte, len(arg7)) arg7Copy = make([]byte, len(arg7))
@ -2675,7 +2675,7 @@ func (fake *Model) Request(arg1 protocol.DeviceID, arg2 string, arg3 string, arg
fake.requestMutex.Lock() fake.requestMutex.Lock()
ret, specificReturn := fake.requestReturnsOnCall[len(fake.requestArgsForCall)] ret, specificReturn := fake.requestReturnsOnCall[len(fake.requestArgsForCall)]
fake.requestArgsForCall = append(fake.requestArgsForCall, struct { fake.requestArgsForCall = append(fake.requestArgsForCall, struct {
arg1 protocol.DeviceID arg1 protocol.Connection
arg2 string arg2 string
arg3 string arg3 string
arg4 int32 arg4 int32
@ -2704,13 +2704,13 @@ func (fake *Model) RequestCallCount() int {
return len(fake.requestArgsForCall) return len(fake.requestArgsForCall)
} }
func (fake *Model) RequestCalls(stub func(protocol.DeviceID, string, string, int32, int32, int64, []byte, uint32, bool) (protocol.RequestResponse, error)) { func (fake *Model) RequestCalls(stub func(protocol.Connection, string, string, int32, int32, int64, []byte, uint32, bool) (protocol.RequestResponse, error)) {
fake.requestMutex.Lock() fake.requestMutex.Lock()
defer fake.requestMutex.Unlock() defer fake.requestMutex.Unlock()
fake.RequestStub = stub fake.RequestStub = stub
} }
func (fake *Model) RequestArgsForCall(i int) (protocol.DeviceID, string, string, int32, int32, int64, []byte, uint32, bool) { func (fake *Model) RequestArgsForCall(i int) (protocol.Connection, string, string, int32, int32, int64, []byte, uint32, bool) {
fake.requestMutex.RLock() fake.requestMutex.RLock()
defer fake.requestMutex.RUnlock() defer fake.requestMutex.RUnlock()
argsForCall := fake.requestArgsForCall[i] argsForCall := fake.requestArgsForCall[i]

View File

@ -847,7 +847,7 @@ func (comp *FolderCompletion) setComplectionPct() {
} }
// Map returns the members as a map, e.g. used in api to serialize as JSON. // Map returns the members as a map, e.g. used in api to serialize as JSON.
func (comp FolderCompletion) Map() map[string]interface{} { func (comp *FolderCompletion) Map() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
"completion": comp.CompletionPct, "completion": comp.CompletionPct,
"globalBytes": comp.GlobalBytes, "globalBytes": comp.GlobalBytes,
@ -1110,22 +1110,23 @@ func (p *pager) done() bool {
// Index is called when a new device is connected and we receive their full index. // Index is called when a new device is connected and we receive their full index.
// Implements the protocol.Model interface. // Implements the protocol.Model interface.
func (m *model) Index(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo) error { func (m *model) Index(conn protocol.Connection, folder string, fs []protocol.FileInfo) error {
return m.handleIndex(deviceID, folder, fs, false) return m.handleIndex(conn, folder, fs, false)
} }
// IndexUpdate is called for incremental updates to connected devices' indexes. // IndexUpdate is called for incremental updates to connected devices' indexes.
// Implements the protocol.Model interface. // Implements the protocol.Model interface.
func (m *model) IndexUpdate(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo) error { func (m *model) IndexUpdate(conn protocol.Connection, folder string, fs []protocol.FileInfo) error {
return m.handleIndex(deviceID, folder, fs, true) return m.handleIndex(conn, folder, fs, true)
} }
func (m *model) handleIndex(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo, update bool) error { func (m *model) handleIndex(conn protocol.Connection, folder string, fs []protocol.FileInfo, update bool) error {
op := "Index" op := "Index"
if update { if update {
op += " update" op += " update"
} }
deviceID := conn.DeviceID()
l.Debugf("%v (in): %s / %q: %d files", op, deviceID, folder, len(fs)) l.Debugf("%v (in): %s / %q: %d files", op, deviceID, folder, len(fs))
if cfg, ok := m.cfg.Folder(folder); !ok || !cfg.SharedWith(deviceID) { if cfg, ok := m.cfg.Folder(folder); !ok || !cfg.SharedWith(deviceID) {
@ -1159,12 +1160,13 @@ type ClusterConfigReceivedEventData struct {
Device protocol.DeviceID `json:"device"` Device protocol.DeviceID `json:"device"`
} }
func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterConfig) error { func (m *model) ClusterConfig(conn protocol.Connection, cm protocol.ClusterConfig) error {
// Check the peer device's announced folders against our own. Emits events // Check the peer device's announced folders against our own. Emits events
// for folders that we don't expect (unknown or not shared). // for folders that we don't expect (unknown or not shared).
// Also, collect a list of folders we do share, and if he's interested in // Also, collect a list of folders we do share, and if he's interested in
// temporary indexes, subscribe the connection. // temporary indexes, subscribe the connection.
deviceID := conn.DeviceID()
l.Debugf("Handling ClusterConfig from %v", deviceID.Short()) l.Debugf("Handling ClusterConfig from %v", deviceID.Short())
m.pmut.RLock() m.pmut.RLock()
@ -1544,7 +1546,7 @@ func (m *model) sendClusterConfig(ids []protocol.DeviceID) {
m.pmut.RUnlock() m.pmut.RUnlock()
// Generating cluster-configs acquires fmut -> must happen outside of pmut. // Generating cluster-configs acquires fmut -> must happen outside of pmut.
for _, conn := range ccConns { for _, conn := range ccConns {
cm, passwords := m.generateClusterConfig(conn.ID()) cm, passwords := m.generateClusterConfig(conn.DeviceID())
conn.SetFolderPasswords(passwords) conn.SetFolderPasswords(passwords)
go conn.ClusterConfig(cm) go conn.ClusterConfig(cm)
} }
@ -1774,7 +1776,8 @@ func (m *model) introduceDevice(device protocol.Device, introducerCfg config.Dev
} }
// Closed is called when a connection has been closed // Closed is called when a connection has been closed
func (m *model) Closed(device protocol.DeviceID, err error) { func (m *model) Closed(conn protocol.Connection, err error) {
device := conn.DeviceID()
m.pmut.Lock() m.pmut.Lock()
conn, ok := m.conn[device] conn, ok := m.conn[device]
if !ok { if !ok {
@ -1834,11 +1837,13 @@ func (r *requestResponse) Wait() {
// Request returns the specified data segment by reading it from local disk. // Request returns the specified data segment by reading it from local disk.
// Implements the protocol.Model interface. // Implements the protocol.Model interface.
func (m *model) Request(deviceID protocol.DeviceID, folder, name string, _, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (out protocol.RequestResponse, err error) { func (m *model) Request(conn protocol.Connection, folder, name string, _, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (out protocol.RequestResponse, err error) {
if size < 0 || offset < 0 { if size < 0 || offset < 0 {
return nil, protocol.ErrInvalid return nil, protocol.ErrInvalid
} }
deviceID := conn.DeviceID()
m.fmut.RLock() m.fmut.RLock()
folderCfg, ok := m.folderCfgs[folder] folderCfg, ok := m.folderCfgs[folder]
folderIgnores := m.folderIgnores[folder] folderIgnores := m.folderIgnores[folder]
@ -2214,7 +2219,7 @@ func (m *model) GetHello(id protocol.DeviceID) protocol.HelloIntf {
// be sent to the connected peer, thereafter index updates whenever the local // be sent to the connected peer, thereafter index updates whenever the local
// folder changes. // folder changes.
func (m *model) AddConnection(conn protocol.Connection, hello protocol.Hello) { func (m *model) AddConnection(conn protocol.Connection, hello protocol.Hello) {
deviceID := conn.ID() deviceID := conn.DeviceID()
device, ok := m.cfg.Device(deviceID) device, ok := m.cfg.Device(deviceID)
if !ok { if !ok {
l.Infoln("Trying to add connection to unknown device") l.Infoln("Trying to add connection to unknown device")
@ -2303,11 +2308,12 @@ func (m *model) AddConnection(conn protocol.Connection, hello protocol.Hello) {
m.deviceWasSeen(deviceID) m.deviceWasSeen(deviceID)
} }
func (m *model) DownloadProgress(device protocol.DeviceID, folder string, updates []protocol.FileDownloadProgressUpdate) error { func (m *model) DownloadProgress(conn protocol.Connection, folder string, updates []protocol.FileDownloadProgressUpdate) error {
m.fmut.RLock() m.fmut.RLock()
cfg, ok := m.folderCfgs[folder] cfg, ok := m.folderCfgs[folder]
m.fmut.RUnlock() m.fmut.RUnlock()
device := conn.DeviceID()
if !ok || cfg.DisableTempIndexes || !cfg.SharedWith(device) { if !ok || cfg.DisableTempIndexes || !cfg.SharedWith(device) {
return nil return nil
} }

View File

@ -94,7 +94,7 @@ func TestRequest(t *testing.T) {
m.ScanFolder("default") m.ScanFolder("default")
// Existing, shared file // Existing, shared file
res, err := m.Request(device1, "default", "foo", 0, 6, 0, nil, 0, false) res, err := m.Request(device1Conn, "default", "foo", 0, 6, 0, nil, 0, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -104,35 +104,35 @@ func TestRequest(t *testing.T) {
} }
// Existing, nonshared file // Existing, nonshared file
_, err = m.Request(device2, "default", "foo", 0, 6, 0, nil, 0, false) _, err = m.Request(device2Conn, "default", "foo", 0, 6, 0, nil, 0, false)
if err == nil { if err == nil {
t.Error("Unexpected nil error on insecure file read") t.Error("Unexpected nil error on insecure file read")
} }
// Nonexistent file // Nonexistent file
_, err = m.Request(device1, "default", "nonexistent", 0, 6, 0, nil, 0, false) _, err = m.Request(device1Conn, "default", "nonexistent", 0, 6, 0, nil, 0, false)
if err == nil { if err == nil {
t.Error("Unexpected nil error on insecure file read") t.Error("Unexpected nil error on insecure file read")
} }
// Shared folder, but disallowed file name // Shared folder, but disallowed file name
_, err = m.Request(device1, "default", "../walk.go", 0, 6, 0, nil, 0, false) _, err = m.Request(device1Conn, "default", "../walk.go", 0, 6, 0, nil, 0, false)
if err == nil { if err == nil {
t.Error("Unexpected nil error on insecure file read") t.Error("Unexpected nil error on insecure file read")
} }
// Negative offset // Negative offset
_, err = m.Request(device1, "default", "foo", 0, -4, 0, nil, 0, false) _, err = m.Request(device1Conn, "default", "foo", 0, -4, 0, nil, 0, false)
if err == nil { if err == nil {
t.Error("Unexpected nil error on insecure file read") t.Error("Unexpected nil error on insecure file read")
} }
// Larger block than available // Larger block than available
_, err = m.Request(device1, "default", "foo", 0, 42, 0, []byte("hash necessary but not checked"), 0, false) _, err = m.Request(device1Conn, "default", "foo", 0, 42, 0, []byte("hash necessary but not checked"), 0, false)
if err == nil { if err == nil {
t.Error("Unexpected nil error on read past end of file") t.Error("Unexpected nil error on read past end of file")
} }
_, err = m.Request(device1, "default", "foo", 0, 42, 0, nil, 0, false) _, err = m.Request(device1Conn, "default", "foo", 0, 42, 0, nil, 0, false)
if err != nil { if err != nil {
t.Error("Unexpected error when large read should be permitted") t.Error("Unexpected error when large read should be permitted")
} }
@ -168,11 +168,11 @@ func benchmarkIndex(b *testing.B, nfiles int) {
defer cleanupModelAndRemoveDir(m, fcfg.Filesystem(nil).URI()) defer cleanupModelAndRemoveDir(m, fcfg.Filesystem(nil).URI())
files := genFiles(nfiles) files := genFiles(nfiles)
must(b, m.Index(device1, fcfg.ID, files)) must(b, m.Index(device1Conn, fcfg.ID, files))
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
must(b, m.Index(device1, fcfg.ID, files)) must(b, m.Index(device1Conn, fcfg.ID, files))
} }
b.ReportAllocs() b.ReportAllocs()
} }
@ -197,11 +197,11 @@ func benchmarkIndexUpdate(b *testing.B, nfiles, nufiles int) {
files := genFiles(nfiles) files := genFiles(nfiles)
ufiles := genFiles(nufiles) ufiles := genFiles(nufiles)
must(b, m.Index(device1, fcfg.ID, files)) must(b, m.Index(device1Conn, fcfg.ID, files))
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
must(b, m.IndexUpdate(device1, fcfg.ID, ufiles)) must(b, m.IndexUpdate(device1Conn, fcfg.ID, ufiles))
} }
b.ReportAllocs() b.ReportAllocs()
} }
@ -218,7 +218,7 @@ func BenchmarkRequestOut(b *testing.B) {
fc.addFile(f.Name, 0o644, protocol.FileInfoTypeFile, []byte("some data to return")) fc.addFile(f.Name, 0o644, protocol.FileInfoTypeFile, []byte("some data to return"))
} }
m.AddConnection(fc, protocol.Hello{}) m.AddConnection(fc, protocol.Hello{})
must(b, m.Index(device1, "default", files)) must(b, m.Index(device1Conn, "default", files))
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -247,7 +247,7 @@ func BenchmarkRequestInSingleFile(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if _, err := m.Request(device1, "default", "request/for/a/file/in/a/couple/of/dirs/128k", 0, 128<<10, 0, nil, 0, false); err != nil { if _, err := m.Request(device1Conn, "default", "request/for/a/file/in/a/couple/of/dirs/128k", 0, 128<<10, 0, nil, 0, false); err != nil {
b.Error(err) b.Error(err)
} }
} }
@ -287,7 +287,7 @@ func TestDeviceRename(t *testing.T) {
t.Errorf("Device already has a name") t.Errorf("Device already has a name")
} }
m.Closed(conn.ID(), protocol.ErrTimeout) m.Closed(conn, protocol.ErrTimeout)
hello.DeviceName = "tester" hello.DeviceName = "tester"
m.AddConnection(conn, hello) m.AddConnection(conn, hello)
@ -295,7 +295,7 @@ func TestDeviceRename(t *testing.T) {
t.Errorf("Device did not get a name") t.Errorf("Device did not get a name")
} }
m.Closed(conn.ID(), protocol.ErrTimeout) m.Closed(conn, protocol.ErrTimeout)
hello.DeviceName = "tester2" hello.DeviceName = "tester2"
m.AddConnection(conn, hello) m.AddConnection(conn, hello)
@ -317,7 +317,7 @@ func TestDeviceRename(t *testing.T) {
t.Errorf("Device name not saved in config") t.Errorf("Device name not saved in config")
} }
m.Closed(conn.ID(), protocol.ErrTimeout) m.Closed(conn, protocol.ErrTimeout)
waiter, err := cfg.Modify(func(cfg *config.Configuration) { waiter, err := cfg.Modify(func(cfg *config.Configuration) {
cfg.Options.OverwriteRemoteDevNames = true cfg.Options.OverwriteRemoteDevNames = true
@ -528,7 +528,7 @@ func TestIntroducer(t *testing.T) {
SkipIntroductionRemovals: true, SkipIntroductionRemovals: true,
EncryptionPasswordToken: []byte("faketoken"), EncryptionPasswordToken: []byte("faketoken"),
}) })
m.ClusterConfig(device1, cc) m.ClusterConfig(device1Conn, cc)
if newDev, ok := m.cfg.Device(device2); !ok || !newDev.Introducer || !newDev.SkipIntroductionRemovals { if newDev, ok := m.cfg.Device(device2); !ok || !newDev.Introducer || !newDev.SkipIntroductionRemovals {
t.Error("device 2 missing or wrong flags") t.Error("device 2 missing or wrong flags")
@ -584,7 +584,7 @@ func TestIntroducer(t *testing.T) {
Introducer: true, Introducer: true,
SkipIntroductionRemovals: true, SkipIntroductionRemovals: true,
}) })
m.ClusterConfig(device1, cc) m.ClusterConfig(device1Conn, cc)
// Should not get introducer, as it's already unset, and it's an existing device. // Should not get introducer, as it's already unset, and it's an existing device.
if newDev, ok := m.cfg.Device(device2); !ok || newDev.Introducer || newDev.SkipIntroductionRemovals { if newDev, ok := m.cfg.Device(device2); !ok || newDev.Introducer || newDev.SkipIntroductionRemovals {
@ -634,7 +634,7 @@ func TestIntroducer(t *testing.T) {
}, },
}, },
}) })
m.ClusterConfig(device1, protocol.ClusterConfig{}) m.ClusterConfig(device1Conn, protocol.ClusterConfig{})
if _, ok := m.cfg.Device(device2); ok { if _, ok := m.cfg.Device(device2); ok {
t.Error("device 2 should have been removed") t.Error("device 2 should have been removed")
@ -686,7 +686,7 @@ func TestIntroducer(t *testing.T) {
}, },
}, },
}) })
m.ClusterConfig(device1, protocol.ClusterConfig{}) m.ClusterConfig(device1Conn, protocol.ClusterConfig{})
if _, ok := m.cfg.Device(device2); !ok { if _, ok := m.cfg.Device(device2); !ok {
t.Error("device 2 should not have been removed") t.Error("device 2 should not have been removed")
@ -743,7 +743,7 @@ func TestIntroducer(t *testing.T) {
Introducer: true, Introducer: true,
SkipIntroductionRemovals: true, SkipIntroductionRemovals: true,
}) })
m.ClusterConfig(device1, cc) m.ClusterConfig(device1Conn, cc)
if _, ok := m.cfg.Device(device2); !ok { if _, ok := m.cfg.Device(device2); !ok {
t.Error("device 2 should not have been removed") t.Error("device 2 should not have been removed")
@ -794,7 +794,7 @@ func TestIntroducer(t *testing.T) {
}, },
}, },
}) })
m.ClusterConfig(device1, protocol.ClusterConfig{}) m.ClusterConfig(device1Conn, protocol.ClusterConfig{})
if _, ok := m.cfg.Device(device2); !ok { if _, ok := m.cfg.Device(device2); !ok {
t.Error("device 2 should not have been removed") t.Error("device 2 should not have been removed")
@ -847,7 +847,7 @@ func TestIntroducer(t *testing.T) {
}) })
defer cleanupModel(m) defer cleanupModel(m)
defer cancel() defer cancel()
m.ClusterConfig(device1, protocol.ClusterConfig{}) m.ClusterConfig(device1Conn, protocol.ClusterConfig{})
if _, ok := m.cfg.Device(device2); !ok { if _, ok := m.cfg.Device(device2); !ok {
t.Error("device 2 should not have been removed") t.Error("device 2 should not have been removed")
@ -906,14 +906,14 @@ func TestIssue5063(t *testing.T) {
for _, c := range m.conn { for _, c := range m.conn {
conn := c.(*fakeConnection) conn := c.(*fakeConnection)
conn.CloseCalls(func(_ error) {}) conn.CloseCalls(func(_ error) {})
defer m.Closed(c.ID(), errStopped) // to unblock deferred m.Stop() defer m.Closed(c, errStopped) // to unblock deferred m.Stop()
} }
m.pmut.Unlock() m.pmut.Unlock()
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
addAndVerify := func(id string) { addAndVerify := func(id string) {
m.ClusterConfig(device1, createClusterConfig(device1, id)) m.ClusterConfig(device1Conn, createClusterConfig(device1, id))
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) { if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
t.Error("expected shared", id) t.Error("expected shared", id)
} }
@ -951,7 +951,7 @@ func TestAutoAcceptRejected(t *testing.T) {
// defer cleanupModel(m) // defer cleanupModel(m)
defer cancel() defer cancel()
id := srand.String(8) id := srand.String(8)
m.ClusterConfig(device1, createClusterConfig(device1, id)) m.ClusterConfig(device1Conn, createClusterConfig(device1, id))
if cfg, ok := m.cfg.Folder(id); ok && cfg.SharedWith(device1) { if cfg, ok := m.cfg.Folder(id); ok && cfg.SharedWith(device1) {
t.Error("unexpected shared", id) t.Error("unexpected shared", id)
@ -964,7 +964,7 @@ func TestAutoAcceptNewFolder(t *testing.T) {
defer cleanupModel(m) defer cleanupModel(m)
defer cancel() defer cancel()
id := srand.String(8) id := srand.String(8)
m.ClusterConfig(device1, createClusterConfig(device1, id)) m.ClusterConfig(device1Conn, createClusterConfig(device1, id))
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) { if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
t.Error("expected shared", id) t.Error("expected shared", id)
} }
@ -976,14 +976,14 @@ func TestAutoAcceptNewFolderFromTwoDevices(t *testing.T) {
defer cancel() defer cancel()
id := srand.String(8) id := srand.String(8)
defer os.RemoveAll(id) defer os.RemoveAll(id)
m.ClusterConfig(device1, createClusterConfig(device1, id)) m.ClusterConfig(device1Conn, createClusterConfig(device1, id))
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) { if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
t.Error("expected shared", id) t.Error("expected shared", id)
} }
if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device2) { if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device2) {
t.Error("unexpected expected shared", id) t.Error("unexpected expected shared", id)
} }
m.ClusterConfig(device2, createClusterConfig(device2, id)) m.ClusterConfig(device2Conn, createClusterConfig(device2, id))
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device2) { if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device2) {
t.Error("expected shared", id) t.Error("expected shared", id)
} }
@ -997,14 +997,14 @@ func TestAutoAcceptNewFolderFromOnlyOneDevice(t *testing.T) {
defer os.RemoveAll(id) defer os.RemoveAll(id)
defer cleanupModel(m) defer cleanupModel(m)
defer cancel() defer cancel()
m.ClusterConfig(device1, createClusterConfig(device1, id)) m.ClusterConfig(device1Conn, createClusterConfig(device1, id))
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) { if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
t.Error("expected shared", id) t.Error("expected shared", id)
} }
if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device2) { if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device2) {
t.Error("unexpected expected shared", id) t.Error("unexpected expected shared", id)
} }
m.ClusterConfig(device2, createClusterConfig(device2, id)) m.ClusterConfig(device2Conn, createClusterConfig(device2, id))
if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device2) { if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device2) {
t.Error("unexpected shared", id) t.Error("unexpected shared", id)
} }
@ -1035,10 +1035,10 @@ func TestAutoAcceptNewFolderPremutationsNoPanic(t *testing.T) {
cfg.Folders = append(cfg.Folders, fcfg) cfg.Folders = append(cfg.Folders, fcfg)
} }
m, cancel := newState(t, cfg) m, cancel := newState(t, cfg)
m.ClusterConfig(device1, protocol.ClusterConfig{ m.ClusterConfig(device1Conn, protocol.ClusterConfig{
Folders: []protocol.Folder{dev1folder}, Folders: []protocol.Folder{dev1folder},
}) })
m.ClusterConfig(device2, protocol.ClusterConfig{ m.ClusterConfig(device2Conn, protocol.ClusterConfig{
Folders: []protocol.Folder{dev2folder}, Folders: []protocol.Folder{dev2folder},
}) })
cleanupModel(m) cleanupModel(m)
@ -1058,7 +1058,7 @@ func TestAutoAcceptMultipleFolders(t *testing.T) {
m, cancel := newState(t, defaultAutoAcceptCfg) m, cancel := newState(t, defaultAutoAcceptCfg)
defer cleanupModel(m) defer cleanupModel(m)
defer cancel() defer cancel()
m.ClusterConfig(device1, createClusterConfig(device1, id1, id2)) m.ClusterConfig(device1Conn, createClusterConfig(device1, id1, id2))
if fcfg, ok := m.cfg.Folder(id1); !ok || !fcfg.SharedWith(device1) { if fcfg, ok := m.cfg.Folder(id1); !ok || !fcfg.SharedWith(device1) {
t.Error("expected shared", id1) t.Error("expected shared", id1)
} }
@ -1086,7 +1086,7 @@ func TestAutoAcceptExistingFolder(t *testing.T) {
if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device1) { if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device1) {
t.Error("missing folder, or shared", id) t.Error("missing folder, or shared", id)
} }
m.ClusterConfig(device1, createClusterConfig(device1, id)) m.ClusterConfig(device1Conn, createClusterConfig(device1, id))
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) || fcfg.Path != idOther { if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) || fcfg.Path != idOther {
t.Error("missing folder, or unshared, or path changed", id) t.Error("missing folder, or unshared, or path changed", id)
@ -1112,7 +1112,7 @@ func TestAutoAcceptNewAndExistingFolder(t *testing.T) {
if fcfg, ok := m.cfg.Folder(id1); !ok || fcfg.SharedWith(device1) { if fcfg, ok := m.cfg.Folder(id1); !ok || fcfg.SharedWith(device1) {
t.Error("missing folder, or shared", id1) t.Error("missing folder, or shared", id1)
} }
m.ClusterConfig(device1, createClusterConfig(device1, id1, id2)) m.ClusterConfig(device1Conn, createClusterConfig(device1, id1, id2))
for i, id := range []string{id1, id2} { for i, id := range []string{id1, id2} {
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) { if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
@ -1143,7 +1143,7 @@ func TestAutoAcceptAlreadyShared(t *testing.T) {
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) { if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
t.Error("missing folder, or not shared", id) t.Error("missing folder, or not shared", id)
} }
m.ClusterConfig(device1, createClusterConfig(device1, id)) m.ClusterConfig(device1Conn, createClusterConfig(device1, id))
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) { if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
t.Error("missing folder, or not shared", id) t.Error("missing folder, or not shared", id)
@ -1159,7 +1159,7 @@ func TestAutoAcceptNameConflict(t *testing.T) {
m, cancel := newState(t, defaultAutoAcceptCfg) m, cancel := newState(t, defaultAutoAcceptCfg)
defer cleanupModel(m) defer cleanupModel(m)
defer cancel() defer cancel()
m.ClusterConfig(device1, protocol.ClusterConfig{ m.ClusterConfig(device1Conn, protocol.ClusterConfig{
Folders: []protocol.Folder{ Folders: []protocol.Folder{
{ {
ID: id, ID: id,
@ -1179,7 +1179,7 @@ func TestAutoAcceptPrefersLabel(t *testing.T) {
label := srand.String(8) label := srand.String(8)
defer cleanupModel(m) defer cleanupModel(m)
defer cancel() defer cancel()
m.ClusterConfig(device1, addFolderDevicesToClusterConfig(protocol.ClusterConfig{ m.ClusterConfig(device1Conn, addFolderDevicesToClusterConfig(protocol.ClusterConfig{
Folders: []protocol.Folder{ Folders: []protocol.Folder{
{ {
ID: id, ID: id,
@ -1203,7 +1203,7 @@ func TestAutoAcceptFallsBackToID(t *testing.T) {
} }
defer cleanupModel(m) defer cleanupModel(m)
defer cancel() defer cancel()
m.ClusterConfig(device1, addFolderDevicesToClusterConfig(protocol.ClusterConfig{ m.ClusterConfig(device1Conn, addFolderDevicesToClusterConfig(protocol.ClusterConfig{
Folders: []protocol.Folder{ Folders: []protocol.Folder{
{ {
ID: id, ID: id,
@ -1245,7 +1245,7 @@ func TestAutoAcceptPausedWhenFolderConfigChanged(t *testing.T) {
t.Fatal("folder running?") t.Fatal("folder running?")
} }
m.ClusterConfig(device1, createClusterConfig(device1, id)) m.ClusterConfig(device1Conn, createClusterConfig(device1, id))
m.generateClusterConfig(device1) m.generateClusterConfig(device1)
if fcfg, ok := m.cfg.Folder(id); !ok { if fcfg, ok := m.cfg.Folder(id); !ok {
@ -1294,7 +1294,7 @@ func TestAutoAcceptPausedWhenFolderConfigNotChanged(t *testing.T) {
t.Fatal("folder running?") t.Fatal("folder running?")
} }
m.ClusterConfig(device1, createClusterConfig(device1, id)) m.ClusterConfig(device1Conn, createClusterConfig(device1, id))
m.generateClusterConfig(device1) m.generateClusterConfig(device1)
if fcfg, ok := m.cfg.Folder(id); !ok { if fcfg, ok := m.cfg.Folder(id); !ok {
@ -1338,7 +1338,7 @@ func TestAutoAcceptEnc(t *testing.T) {
// would panic. // would panic.
clusterConfig := func(deviceID protocol.DeviceID, cm protocol.ClusterConfig) { clusterConfig := func(deviceID protocol.DeviceID, cm protocol.ClusterConfig) {
m.AddConnection(newFakeConnection(deviceID, m), protocol.Hello{}) m.AddConnection(newFakeConnection(deviceID, m), protocol.Hello{})
m.ClusterConfig(deviceID, cm) m.ClusterConfig(&protocolmocks.Connection{DeviceIDStub: func() protocol.DeviceID { return deviceID }}, cm)
} }
clusterConfig(device1, basicCC()) clusterConfig(device1, basicCC())
@ -1703,7 +1703,7 @@ func TestRWScanRecovery(t *testing.T) {
} }
func TestGlobalDirectoryTree(t *testing.T) { func TestGlobalDirectoryTree(t *testing.T) {
m, _, fcfg, wCancel := setupModelWithConnection(t) m, conn, fcfg, wCancel := setupModelWithConnection(t)
defer wCancel() defer wCancel()
defer cleanupModelAndRemoveDir(m, fcfg.Filesystem(nil).URI()) defer cleanupModelAndRemoveDir(m, fcfg.Filesystem(nil).URI())
@ -1807,7 +1807,7 @@ func TestGlobalDirectoryTree(t *testing.T) {
return string(bytes) return string(bytes)
} }
must(t, m.Index(device1, "default", testdata)) must(t, m.Index(conn, "default", testdata))
result, _ := m.GlobalDirectoryTree("default", "", -1, false) result, _ := m.GlobalDirectoryTree("default", "", -1, false)
@ -2014,7 +2014,7 @@ func benchmarkTree(b *testing.B, n1, n2 int) {
m.ScanFolder(fcfg.ID) m.ScanFolder(fcfg.ID)
files := genDeepFiles(n1, n2) files := genDeepFiles(n1, n2)
must(b, m.Index(device1, fcfg.ID, files)) must(b, m.Index(device1Conn, fcfg.ID, files))
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -2160,7 +2160,7 @@ func TestSharedWithClearedOnDisconnect(t *testing.T) {
conn2 := newFakeConnection(device2, m) conn2 := newFakeConnection(device2, m)
m.AddConnection(conn2, protocol.Hello{}) m.AddConnection(conn2, protocol.Hello{})
m.ClusterConfig(device1, protocol.ClusterConfig{ m.ClusterConfig(conn1, protocol.ClusterConfig{
Folders: []protocol.Folder{ Folders: []protocol.Folder{
{ {
ID: "default", ID: "default",
@ -2172,7 +2172,7 @@ func TestSharedWithClearedOnDisconnect(t *testing.T) {
}, },
}, },
}) })
m.ClusterConfig(device2, protocol.ClusterConfig{ m.ClusterConfig(conn2, protocol.ClusterConfig{
Folders: []protocol.Folder{ Folders: []protocol.Folder{
{ {
ID: "default", ID: "default",
@ -2398,7 +2398,7 @@ func TestCustomMarkerName(t *testing.T) {
} }
func TestRemoveDirWithContent(t *testing.T) { func TestRemoveDirWithContent(t *testing.T) {
m, _, fcfg, wcfgCancel := setupModelWithConnection(t) m, conn, fcfg, wcfgCancel := setupModelWithConnection(t)
defer wcfgCancel() defer wcfgCancel()
tfs := fcfg.Filesystem(nil) tfs := fcfg.Filesystem(nil)
defer cleanupModelAndRemoveDir(m, tfs.URI()) defer cleanupModelAndRemoveDir(m, tfs.URI())
@ -2425,7 +2425,7 @@ func TestRemoveDirWithContent(t *testing.T) {
file.Deleted = true file.Deleted = true
file.Version = file.Version.Update(device1.Short()).Update(device1.Short()) file.Version = file.Version.Update(device1.Short()).Update(device1.Short())
must(t, m.IndexUpdate(device1, fcfg.ID, []protocol.FileInfo{dir, file})) must(t, m.IndexUpdate(conn, fcfg.ID, []protocol.FileInfo{dir, file}))
// Is there something we could trigger on instead of just waiting? // Is there something we could trigger on instead of just waiting?
timeout := time.NewTimer(5 * time.Second) timeout := time.NewTimer(5 * time.Second)
@ -2919,19 +2919,19 @@ func TestRequestLimit(t *testing.T) {
}) })
must(t, err) must(t, err)
waiter.Wait() waiter.Wait()
m, _ := setupModelWithConnectionFromWrapper(t, wrapper) m, conn := setupModelWithConnectionFromWrapper(t, wrapper)
defer cleanupModel(m) defer cleanupModel(m)
m.ScanFolder("default") m.ScanFolder("default")
befReq := time.Now() befReq := time.Now()
first, err := m.Request(device1, "default", file, 0, 2000, 0, nil, 0, false) first, err := m.Request(conn, "default", file, 0, 2000, 0, nil, 0, false)
if err != nil { if err != nil {
t.Fatalf("First request failed: %v", err) t.Fatalf("First request failed: %v", err)
} }
reqDur := time.Since(befReq) reqDur := time.Since(befReq)
returned := make(chan struct{}) returned := make(chan struct{})
go func() { go func() {
second, err := m.Request(device1, "default", file, 0, 2000, 0, nil, 0, false) second, err := m.Request(conn, "default", file, 0, 2000, 0, nil, 0, false)
if err != nil { if err != nil {
t.Errorf("Second request failed: %v", err) t.Errorf("Second request failed: %v", err)
} }
@ -2969,12 +2969,16 @@ func TestConnCloseOnRestart(t *testing.T) {
br := &testutils.BlockingRW{} br := &testutils.BlockingRW{}
nw := &testutils.NoopRW{} nw := &testutils.NoopRW{}
m.AddConnection(protocol.NewConnection(device1, br, nw, testutils.NoopCloser{}, m, new(protocolmocks.ConnectionInfo), protocol.CompressionNever, nil, m.keyGen), protocol.Hello{}) ci := &protocolmocks.ConnectionInfo{}
m.AddConnection(protocol.NewConnection(device1, br, nw, testutils.NoopCloser{}, m, ci, protocol.CompressionNever, nil, m.keyGen), protocol.Hello{})
m.pmut.RLock() m.pmut.RLock()
if len(m.closed) != 1 { if len(m.closed) != 1 {
t.Fatalf("Expected just one conn (len(m.conn) == %v)", len(m.conn)) t.Fatalf("Expected just one conn (len(m.closed) == %v)", len(m.closed))
}
var closed chan struct{}
for _, c := range m.closed {
closed = c
} }
closed := m.closed[device1]
m.pmut.RUnlock() m.pmut.RUnlock()
waiter, err := w.RemoveDevice(device1) waiter, err := w.RemoveDevice(device1)
@ -3069,7 +3073,10 @@ func TestDevicePause(t *testing.T) {
defer sub.Unsubscribe() defer sub.Unsubscribe()
m.pmut.RLock() m.pmut.RLock()
closed := m.closed[device1] var closed chan struct{}
for _, c := range m.closed {
closed = c
}
m.pmut.RUnlock() m.pmut.RUnlock()
pauseDevice(t, m.cfg, device1, true) pauseDevice(t, m.cfg, device1, true)
@ -3567,7 +3574,7 @@ func TestAddFolderCompletion(t *testing.T) {
} }
func TestScanDeletedROChangedOnSR(t *testing.T) { func TestScanDeletedROChangedOnSR(t *testing.T) {
m, _, fcfg, wCancel := setupModelWithConnection(t) m, conn, fcfg, wCancel := setupModelWithConnection(t)
ffs := fcfg.Filesystem(nil) ffs := fcfg.Filesystem(nil)
defer wCancel() defer wCancel()
defer cleanupModelAndRemoveDir(m, ffs.URI()) defer cleanupModelAndRemoveDir(m, ffs.URI())
@ -3585,7 +3592,7 @@ func TestScanDeletedROChangedOnSR(t *testing.T) {
} }
// A remote must have the file, otherwise the deletion below is // A remote must have the file, otherwise the deletion below is
// automatically resolved as not a ro-changed item. // automatically resolved as not a ro-changed item.
must(t, m.IndexUpdate(device1, fcfg.ID, []protocol.FileInfo{file})) must(t, m.IndexUpdate(conn, fcfg.ID, []protocol.FileInfo{file}))
must(t, ffs.Remove(name)) must(t, ffs.Remove(name))
m.ScanFolders() m.ScanFolders()
@ -3690,17 +3697,17 @@ func TestIssue6961(t *testing.T) {
} }
m.ServeBackground() m.ServeBackground()
defer cleanupModelAndRemoveDir(m, tfs.URI()) defer cleanupModelAndRemoveDir(m, tfs.URI())
addFakeConn(m, device1, fcfg.ID) conn1 := addFakeConn(m, device1, fcfg.ID)
addFakeConn(m, device2, fcfg.ID) conn2 := addFakeConn(m, device2, fcfg.ID)
m.ScanFolders() m.ScanFolders()
name := "foo" name := "foo"
version := protocol.Vector{}.Update(device1.Short()) version := protocol.Vector{}.Update(device1.Short())
// Remote, valid and existing file // Remote, valid and existing file
must(t, m.Index(device1, fcfg.ID, []protocol.FileInfo{{Name: name, Version: version, Sequence: 1}})) must(t, m.Index(conn1, fcfg.ID, []protocol.FileInfo{{Name: name, Version: version, Sequence: 1}}))
// Remote, invalid (receive-only) and existing file // Remote, invalid (receive-only) and existing file
must(t, m.Index(device2, fcfg.ID, []protocol.FileInfo{{Name: name, RawInvalid: true, Sequence: 1}})) must(t, m.Index(conn2, fcfg.ID, []protocol.FileInfo{{Name: name, RawInvalid: true, Sequence: 1}}))
// Create a local file // Create a local file
if fd, err := tfs.OpenFile(name, fs.OptCreate, 0o666); err != nil { if fd, err := tfs.OpenFile(name, fs.OptCreate, 0o666); err != nil {
t.Fatal(err) t.Fatal(err)
@ -3726,7 +3733,7 @@ func TestIssue6961(t *testing.T) {
m.ScanFolders() m.ScanFolders()
// Drop the remote index, add some other file. // Drop the remote index, add some other file.
must(t, m.Index(device2, fcfg.ID, []protocol.FileInfo{{Name: "bar", RawInvalid: true, Sequence: 1}})) must(t, m.Index(conn2, fcfg.ID, []protocol.FileInfo{{Name: "bar", RawInvalid: true, Sequence: 1}}))
// Pause and unpause folder to create new db.FileSet and thus recalculate everything // Pause and unpause folder to create new db.FileSet and thus recalculate everything
pauseFolder(t, wcfg, fcfg.ID, true) pauseFolder(t, wcfg, fcfg.ID, true)
@ -3740,7 +3747,7 @@ func TestIssue6961(t *testing.T) {
} }
func TestCompletionEmptyGlobal(t *testing.T) { func TestCompletionEmptyGlobal(t *testing.T) {
m, _, fcfg, wcfgCancel := setupModelWithConnection(t) m, conn, fcfg, wcfgCancel := setupModelWithConnection(t)
defer wcfgCancel() defer wcfgCancel()
defer cleanupModelAndRemoveDir(m, fcfg.Filesystem(nil).URI()) defer cleanupModelAndRemoveDir(m, fcfg.Filesystem(nil).URI())
files := []protocol.FileInfo{{Name: "foo", Version: protocol.Vector{}.Update(myID.Short()), Sequence: 1}} files := []protocol.FileInfo{{Name: "foo", Version: protocol.Vector{}.Update(myID.Short()), Sequence: 1}}
@ -3749,7 +3756,7 @@ func TestCompletionEmptyGlobal(t *testing.T) {
m.fmut.Unlock() m.fmut.Unlock()
files[0].Deleted = true files[0].Deleted = true
files[0].Version = files[0].Version.Update(device1.Short()) files[0].Version = files[0].Version.Update(device1.Short())
must(t, m.IndexUpdate(device1, fcfg.ID, files)) must(t, m.IndexUpdate(conn, fcfg.ID, files))
comp := m.testCompletion(protocol.LocalDeviceID, fcfg.ID) comp := m.testCompletion(protocol.LocalDeviceID, fcfg.ID)
if comp.CompletionPct != 95 { if comp.CompletionPct != 95 {
t.Error("Expected completion of 95%, got", comp.CompletionPct) t.Error("Expected completion of 95%, got", comp.CompletionPct)
@ -3762,34 +3769,34 @@ func TestNeedMetaAfterIndexReset(t *testing.T) {
addDevice2(t, w, fcfg) addDevice2(t, w, fcfg)
m := setupModel(t, w) m := setupModel(t, w)
defer cleanupModelAndRemoveDir(m, fcfg.Path) defer cleanupModelAndRemoveDir(m, fcfg.Path)
addFakeConn(m, device1, fcfg.ID) conn1 := addFakeConn(m, device1, fcfg.ID)
addFakeConn(m, device2, fcfg.ID) conn2 := addFakeConn(m, device2, fcfg.ID)
var seq int64 = 1 var seq int64 = 1
files := []protocol.FileInfo{{Name: "foo", Size: 10, Version: protocol.Vector{}.Update(device1.Short()), Sequence: seq}} files := []protocol.FileInfo{{Name: "foo", Size: 10, Version: protocol.Vector{}.Update(device1.Short()), Sequence: seq}}
// Start with two remotes having one file, then both deleting it, then // Start with two remotes having one file, then both deleting it, then
// only one adding it again. // only one adding it again.
must(t, m.Index(device1, fcfg.ID, files)) must(t, m.Index(conn1, fcfg.ID, files))
must(t, m.Index(device2, fcfg.ID, files)) must(t, m.Index(conn2, fcfg.ID, files))
seq++ seq++
files[0].SetDeleted(device2.Short()) files[0].SetDeleted(device2.Short())
files[0].Sequence = seq files[0].Sequence = seq
must(t, m.IndexUpdate(device2, fcfg.ID, files)) must(t, m.IndexUpdate(conn1, fcfg.ID, files))
must(t, m.IndexUpdate(device1, fcfg.ID, files)) must(t, m.IndexUpdate(conn2, fcfg.ID, files))
seq++ seq++
files[0].Deleted = false files[0].Deleted = false
files[0].Size = 20 files[0].Size = 20
files[0].Version = files[0].Version.Update(device1.Short()) files[0].Version = files[0].Version.Update(device1.Short())
files[0].Sequence = seq files[0].Sequence = seq
must(t, m.IndexUpdate(device1, fcfg.ID, files)) must(t, m.IndexUpdate(conn1, fcfg.ID, files))
if comp := m.testCompletion(device2, fcfg.ID); comp.NeedItems != 1 { if comp := m.testCompletion(device2, fcfg.ID); comp.NeedItems != 1 {
t.Error("Expected one needed item for device2, got", comp.NeedItems) t.Error("Expected one needed item for device2, got", comp.NeedItems)
} }
// Pretend we had an index reset on device 1 // Pretend we had an index reset on device 1
must(t, m.Index(device1, fcfg.ID, files)) must(t, m.Index(conn1, fcfg.ID, files))
if comp := m.testCompletion(device2, fcfg.ID); comp.NeedItems != 1 { if comp := m.testCompletion(device2, fcfg.ID); comp.NeedItems != 1 {
t.Error("Expected one needed item for device2, got", comp.NeedItems) t.Error("Expected one needed item for device2, got", comp.NeedItems)
} }

View File

@ -315,15 +315,15 @@ func (t *ProgressEmitter) emptyLocked() bool {
func (t *ProgressEmitter) temporaryIndexSubscribe(conn protocol.Connection, folders []string) { func (t *ProgressEmitter) temporaryIndexSubscribe(conn protocol.Connection, folders []string) {
t.mut.Lock() t.mut.Lock()
defer t.mut.Unlock() defer t.mut.Unlock()
t.connections[conn.ID()] = conn t.connections[conn.DeviceID()] = conn
t.foldersByConns[conn.ID()] = folders t.foldersByConns[conn.DeviceID()] = folders
} }
func (t *ProgressEmitter) temporaryIndexUnsubscribe(conn protocol.Connection) { func (t *ProgressEmitter) temporaryIndexUnsubscribe(conn protocol.Connection) {
t.mut.Lock() t.mut.Lock()
defer t.mut.Unlock() defer t.mut.Unlock()
delete(t.connections, conn.ID()) delete(t.connections, conn.DeviceID())
delete(t.foldersByConns, conn.ID()) delete(t.foldersByConns, conn.DeviceID())
} }
func (t *ProgressEmitter) clearLocked() { func (t *ProgressEmitter) clearLocked() {

View File

@ -463,7 +463,7 @@ func TestSendDownloadProgressMessages(t *testing.T) {
p.temporaryIndexUnsubscribe(fc) p.temporaryIndexUnsubscribe(fc)
sendMsgs(p) sendMsgs(p)
_, ok := p.sentDownloadStates[fc.ID()] _, ok := p.sentDownloadStates[fc.DeviceID()]
if ok { if ok {
t.Error("Should not be there") t.Error("Should not be there")
} }

View File

@ -107,7 +107,7 @@ func TestSymlinkTraversalRead(t *testing.T) {
<-done <-done
// Request a file by traversing the symlink // Request a file by traversing the symlink
res, err := m.Request(device1, "default", "symlink/requests_test.go", 0, 10, 0, nil, 0, false) res, err := m.Request(device1Conn, "default", "symlink/requests_test.go", 0, 10, 0, nil, 0, false)
if err == nil || res != nil { if err == nil || res != nil {
t.Error("Managed to traverse symlink") t.Error("Managed to traverse symlink")
} }
@ -439,7 +439,7 @@ func TestRescanIfHaveInvalidContent(t *testing.T) {
t.Fatalf("unexpected weak hash: %d != 103547413", f.Blocks[0].WeakHash) t.Fatalf("unexpected weak hash: %d != 103547413", f.Blocks[0].WeakHash)
} }
res, err := m.Request(device1, "default", "foo", 0, int32(len(payload)), 0, f.Blocks[0].Hash, f.Blocks[0].WeakHash, false) res, err := m.Request(device1Conn, "default", "foo", 0, int32(len(payload)), 0, f.Blocks[0].Hash, f.Blocks[0].WeakHash, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -453,7 +453,7 @@ func TestRescanIfHaveInvalidContent(t *testing.T) {
writeFile(t, tfs, "foo", payload) writeFile(t, tfs, "foo", payload)
_, err = m.Request(device1, "default", "foo", 0, int32(len(payload)), 0, f.Blocks[0].Hash, f.Blocks[0].WeakHash, false) _, err = m.Request(device1Conn, "default", "foo", 0, int32(len(payload)), 0, f.Blocks[0].Hash, f.Blocks[0].WeakHash, false)
if err == nil { if err == nil {
t.Fatalf("expected failure") t.Fatalf("expected failure")
} }
@ -1122,7 +1122,7 @@ func TestRequestIndexSenderPause(t *testing.T) {
cc := basicClusterConfig(device1, myID, fcfg.ID) cc := basicClusterConfig(device1, myID, fcfg.ID)
cc.Folders[0].Paused = true cc.Folders[0].Paused = true
m.ClusterConfig(device1, cc) m.ClusterConfig(fc, cc)
seq++ seq++
files[0].Sequence = seq files[0].Sequence = seq
@ -1143,7 +1143,7 @@ func TestRequestIndexSenderPause(t *testing.T) {
// Remote unpaused // Remote unpaused
cc.Folders[0].Paused = false cc.Folders[0].Paused = false
m.ClusterConfig(device1, cc) m.ClusterConfig(fc, cc)
select { select {
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
t.Fatal("timed out before receiving index") t.Fatal("timed out before receiving index")
@ -1168,12 +1168,12 @@ func TestRequestIndexSenderPause(t *testing.T) {
// Local and remote paused, then first resume remote, then local // Local and remote paused, then first resume remote, then local
cc.Folders[0].Paused = true cc.Folders[0].Paused = true
m.ClusterConfig(device1, cc) m.ClusterConfig(fc, cc)
pauseFolder(t, m.cfg, fcfg.ID, true) pauseFolder(t, m.cfg, fcfg.ID, true)
cc.Folders[0].Paused = false cc.Folders[0].Paused = false
m.ClusterConfig(device1, cc) m.ClusterConfig(fc, cc)
pauseFolder(t, m.cfg, fcfg.ID, false) pauseFolder(t, m.cfg, fcfg.ID, false)
@ -1190,7 +1190,7 @@ func TestRequestIndexSenderPause(t *testing.T) {
// Folder removed on remote // Folder removed on remote
cc = protocol.ClusterConfig{} cc = protocol.ClusterConfig{}
m.ClusterConfig(device1, cc) m.ClusterConfig(fc, cc)
seq++ seq++
files[0].Sequence = seq files[0].Sequence = seq
@ -1304,7 +1304,7 @@ func TestRequestReceiveEncrypted(t *testing.T) {
return nil return nil
}) })
m.AddConnection(fc, protocol.Hello{}) m.AddConnection(fc, protocol.Hello{})
m.ClusterConfig(device1, protocol.ClusterConfig{ m.ClusterConfig(fc, protocol.ClusterConfig{
Folders: []protocol.Folder{ Folders: []protocol.Folder{
{ {
ID: "default", ID: "default",
@ -1354,7 +1354,7 @@ func TestRequestReceiveEncrypted(t *testing.T) {
} }
// Simulate request from device that is untrusted too, i.e. with non-empty, but garbage hash // Simulate request from device that is untrusted too, i.e. with non-empty, but garbage hash
_, err := m.Request(device1, fcfg.ID, name, 0, 1064, 0, []byte("garbage"), 0, false) _, err := m.Request(fc, fcfg.ID, name, 0, 1064, 0, []byte("garbage"), 0, false)
must(t, err) must(t, err)
changed, err := m.LocalChangedFolderFiles(fcfg.ID, 1, 10) changed, err := m.LocalChangedFolderFiles(fcfg.ID, 1, 10)
@ -1380,7 +1380,7 @@ func TestRequestGlobalInvalidToValid(t *testing.T) {
}) })
must(t, err) must(t, err)
waiter.Wait() waiter.Wait()
addFakeConn(m, device2, fcfg.ID) conn := addFakeConn(m, device2, fcfg.ID)
tfs := fcfg.Filesystem(nil) tfs := fcfg.Filesystem(nil)
defer cleanupModelAndRemoveDir(m, tfs.URI()) defer cleanupModelAndRemoveDir(m, tfs.URI())
@ -1405,7 +1405,7 @@ func TestRequestGlobalInvalidToValid(t *testing.T) {
file := fc.files[0] file := fc.files[0]
fc.mut.Unlock() fc.mut.Unlock()
file.SetIgnored() file.SetIgnored()
m.IndexUpdate(device2, fcfg.ID, []protocol.FileInfo{prepareFileInfoForIndex(file)}) m.IndexUpdate(conn, fcfg.ID, []protocol.FileInfo{prepareFileInfoForIndex(file)})
// Wait for the ignored file to be received and possible pulled // Wait for the ignored file to be received and possible pulled
timeout := time.After(10 * time.Second) timeout := time.After(10 * time.Second)

View File

@ -19,6 +19,7 @@ import (
"github.com/syncthing/syncthing/lib/fs" "github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/ignore" "github.com/syncthing/syncthing/lib/ignore"
"github.com/syncthing/syncthing/lib/protocol" "github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/protocol/mocks"
"github.com/syncthing/syncthing/lib/rand" "github.com/syncthing/syncthing/lib/rand"
) )
@ -29,12 +30,16 @@ var (
defaultFolderConfig config.FolderConfiguration defaultFolderConfig config.FolderConfiguration
defaultCfg config.Configuration defaultCfg config.Configuration
defaultAutoAcceptCfg config.Configuration defaultAutoAcceptCfg config.Configuration
device1Conn = &mocks.Connection{}
device2Conn = &mocks.Connection{}
) )
func init() { func init() {
myID, _ = protocol.DeviceIDFromString("ZNWFSWE-RWRV2BD-45BLMCV-LTDE2UR-4LJDW6J-R5BPWEB-TXD27XJ-IZF5RA4") myID, _ = protocol.DeviceIDFromString("ZNWFSWE-RWRV2BD-45BLMCV-LTDE2UR-4LJDW6J-R5BPWEB-TXD27XJ-IZF5RA4")
device1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR") device1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY") device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY")
device1Conn.DeviceIDReturns(device1)
device2Conn.DeviceIDReturns(device2)
cfg := config.New(myID) cfg := config.New(myID)
cfg.Options.MinHomeDiskFree.Value = 0 // avoids unnecessary free space checks cfg.Options.MinHomeDiskFree.Value = 0 // avoids unnecessary free space checks

View File

@ -167,15 +167,15 @@ func negotiateTLS(cert tls.Certificate, conn0, conn1 net.Conn) (net.Conn, net.Co
type fakeModel struct{} type fakeModel struct{}
func (*fakeModel) Index(_ DeviceID, _ string, _ []FileInfo) error { func (*fakeModel) Index(Connection, string, []FileInfo) error {
return nil return nil
} }
func (*fakeModel) IndexUpdate(_ DeviceID, _ string, _ []FileInfo) error { func (*fakeModel) IndexUpdate(Connection, string, []FileInfo) error {
return nil return nil
} }
func (*fakeModel) Request(_ DeviceID, _, _ string, _, size int32, offset int64, _ []byte, _ uint32, _ bool) (RequestResponse, error) { func (*fakeModel) Request(_ Connection, _, _ string, _, size int32, offset int64, _ []byte, _ uint32, _ bool) (RequestResponse, error) {
// We write the offset to the end of the buffer, so the receiver // We write the offset to the end of the buffer, so the receiver
// can verify that it did in fact get some data back over the // can verify that it did in fact get some data back over the
// connection. // connection.
@ -184,13 +184,13 @@ func (*fakeModel) Request(_ DeviceID, _, _ string, _, size int32, offset int64,
return &fakeRequestResponse{buf}, nil return &fakeRequestResponse{buf}, nil
} }
func (*fakeModel) ClusterConfig(_ DeviceID, _ ClusterConfig) error { func (*fakeModel) ClusterConfig(Connection, ClusterConfig) error {
return nil return nil
} }
func (*fakeModel) Closed(DeviceID, error) { func (*fakeModel) Closed(Connection, error) {
} }
func (*fakeModel) DownloadProgress(_ DeviceID, _ string, _ []FileDownloadProgressUpdate) error { func (*fakeModel) DownloadProgress(Connection, string, []FileDownloadProgressUpdate) error {
return nil return nil
} }

View File

@ -13,8 +13,8 @@ type TestModel struct {
hash []byte hash []byte
weakHash uint32 weakHash uint32
fromTemporary bool fromTemporary bool
indexFn func(DeviceID, string, []FileInfo) indexFn func(string, []FileInfo)
ccFn func(DeviceID, ClusterConfig) ccFn func(ClusterConfig)
closedCh chan struct{} closedCh chan struct{}
closedErr error closedErr error
} }
@ -25,18 +25,18 @@ func newTestModel() *TestModel {
} }
} }
func (t *TestModel) Index(deviceID DeviceID, folder string, files []FileInfo) error { func (t *TestModel) Index(_ Connection, folder string, files []FileInfo) error {
if t.indexFn != nil { if t.indexFn != nil {
t.indexFn(deviceID, folder, files) t.indexFn(folder, files)
} }
return nil return nil
} }
func (*TestModel) IndexUpdate(_ DeviceID, _ string, _ []FileInfo) error { func (*TestModel) IndexUpdate(Connection, string, []FileInfo) error {
return nil return nil
} }
func (t *TestModel) Request(_ DeviceID, folder, name string, _, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) { func (t *TestModel) Request(_ Connection, folder, name string, _, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
t.folder = folder t.folder = folder
t.name = name t.name = name
t.offset = offset t.offset = offset
@ -49,19 +49,19 @@ func (t *TestModel) Request(_ DeviceID, folder, name string, _, size int32, offs
return &fakeRequestResponse{buf}, nil return &fakeRequestResponse{buf}, nil
} }
func (t *TestModel) Closed(_ DeviceID, err error) { func (t *TestModel) Closed(_ Connection, err error) {
t.closedErr = err t.closedErr = err
close(t.closedCh) close(t.closedCh)
} }
func (t *TestModel) ClusterConfig(deviceID DeviceID, config ClusterConfig) error { func (t *TestModel) ClusterConfig(_ Connection, config ClusterConfig) error {
if t.ccFn != nil { if t.ccFn != nil {
t.ccFn(deviceID, config) t.ccFn(config)
} }
return nil return nil
} }
func (*TestModel) DownloadProgress(DeviceID, string, []FileDownloadProgressUpdate) error { func (*TestModel) DownloadProgress(Connection, string, []FileDownloadProgressUpdate) error {
return nil return nil
} }

View File

@ -43,12 +43,12 @@ const (
// receives encrypted metadata and requests from the untrusted device, so it // receives encrypted metadata and requests from the untrusted device, so it
// must decrypt those and answer requests by encrypting the data. // must decrypt those and answer requests by encrypting the data.
type encryptedModel struct { type encryptedModel struct {
model Model model contextLessModel
folderKeys *folderKeyRegistry folderKeys *folderKeyRegistry
keyGen *KeyGenerator keyGen *KeyGenerator
} }
func newEncryptedModel(model Model, folderKeys *folderKeyRegistry, keyGen *KeyGenerator) encryptedModel { func newEncryptedModel(model contextLessModel, folderKeys *folderKeyRegistry, keyGen *KeyGenerator) encryptedModel {
return encryptedModel{ return encryptedModel{
model: model, model: model,
folderKeys: folderKeys, folderKeys: folderKeys,
@ -56,30 +56,30 @@ func newEncryptedModel(model Model, folderKeys *folderKeyRegistry, keyGen *KeyGe
} }
} }
func (e encryptedModel) Index(deviceID DeviceID, folder string, files []FileInfo) error { func (e encryptedModel) Index(folder string, files []FileInfo) error {
if folderKey, ok := e.folderKeys.get(folder); ok { if folderKey, ok := e.folderKeys.get(folder); ok {
// incoming index data to be decrypted // incoming index data to be decrypted
if err := decryptFileInfos(e.keyGen, files, folderKey); err != nil { if err := decryptFileInfos(e.keyGen, files, folderKey); err != nil {
return err return err
} }
} }
return e.model.Index(deviceID, folder, files) return e.model.Index(folder, files)
} }
func (e encryptedModel) IndexUpdate(deviceID DeviceID, folder string, files []FileInfo) error { func (e encryptedModel) IndexUpdate(folder string, files []FileInfo) error {
if folderKey, ok := e.folderKeys.get(folder); ok { if folderKey, ok := e.folderKeys.get(folder); ok {
// incoming index data to be decrypted // incoming index data to be decrypted
if err := decryptFileInfos(e.keyGen, files, folderKey); err != nil { if err := decryptFileInfos(e.keyGen, files, folderKey); err != nil {
return err return err
} }
} }
return e.model.IndexUpdate(deviceID, folder, files) return e.model.IndexUpdate(folder, files)
} }
func (e encryptedModel) Request(deviceID DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) { func (e encryptedModel) Request(folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
folderKey, ok := e.folderKeys.get(folder) folderKey, ok := e.folderKeys.get(folder)
if !ok { if !ok {
return e.model.Request(deviceID, folder, name, blockNo, size, offset, hash, weakHash, fromTemporary) return e.model.Request(folder, name, blockNo, size, offset, hash, weakHash, fromTemporary)
} }
// Figure out the real file name, offset and size from the encrypted / // Figure out the real file name, offset and size from the encrypted /
@ -120,7 +120,7 @@ func (e encryptedModel) Request(deviceID DeviceID, folder, name string, blockNo,
// Perform that request and grab the data. // Perform that request and grab the data.
resp, err := e.model.Request(deviceID, folder, realName, blockNo, realSize, realOffset, realHash, 0, false) resp, err := e.model.Request(folder, realName, blockNo, realSize, realOffset, realHash, 0, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -142,21 +142,21 @@ func (e encryptedModel) Request(deviceID DeviceID, folder, name string, blockNo,
return rawResponse{enc}, nil return rawResponse{enc}, nil
} }
func (e encryptedModel) DownloadProgress(deviceID DeviceID, folder string, updates []FileDownloadProgressUpdate) error { func (e encryptedModel) DownloadProgress(folder string, updates []FileDownloadProgressUpdate) error {
if _, ok := e.folderKeys.get(folder); !ok { if _, ok := e.folderKeys.get(folder); !ok {
return e.model.DownloadProgress(deviceID, folder, updates) return e.model.DownloadProgress(folder, updates)
} }
// Encrypted devices shouldn't send these - ignore them. // Encrypted devices shouldn't send these - ignore them.
return nil return nil
} }
func (e encryptedModel) ClusterConfig(deviceID DeviceID, config ClusterConfig) error { func (e encryptedModel) ClusterConfig(config ClusterConfig) error {
return e.model.ClusterConfig(deviceID, config) return e.model.ClusterConfig(config)
} }
func (e encryptedModel) Closed(device DeviceID, err error) { func (e encryptedModel) Closed(err error) {
e.model.Closed(device, err) e.model.Closed(err)
} }
// The encryptedConnection sits between the model and the encrypted device. It // The encryptedConnection sits between the model and the encrypted device. It
@ -185,8 +185,8 @@ func (e encryptedConnection) SetFolderPasswords(passwords map[string]string) {
e.folderKeys.setPasswords(passwords) e.folderKeys.setPasswords(passwords)
} }
func (e encryptedConnection) ID() DeviceID { func (e encryptedConnection) DeviceID() DeviceID {
return e.conn.ID() return e.conn.DeviceID()
} }
func (e encryptedConnection) Index(ctx context.Context, folder string, files []FileInfo) error { func (e encryptedConnection) Index(ctx context.Context, folder string, files []FileInfo) error {

View File

@ -41,6 +41,16 @@ type Connection struct {
cryptoReturnsOnCall map[int]struct { cryptoReturnsOnCall map[int]struct {
result1 string result1 string
} }
DeviceIDStub func() protocol.DeviceID
deviceIDMutex sync.RWMutex
deviceIDArgsForCall []struct {
}
deviceIDReturns struct {
result1 protocol.DeviceID
}
deviceIDReturnsOnCall map[int]struct {
result1 protocol.DeviceID
}
DownloadProgressStub func(context.Context, string, []protocol.FileDownloadProgressUpdate) DownloadProgressStub func(context.Context, string, []protocol.FileDownloadProgressUpdate)
downloadProgressMutex sync.RWMutex downloadProgressMutex sync.RWMutex
downloadProgressArgsForCall []struct { downloadProgressArgsForCall []struct {
@ -58,16 +68,6 @@ type Connection struct {
establishedAtReturnsOnCall map[int]struct { establishedAtReturnsOnCall map[int]struct {
result1 time.Time result1 time.Time
} }
IDStub func() protocol.DeviceID
iDMutex sync.RWMutex
iDArgsForCall []struct {
}
iDReturns struct {
result1 protocol.DeviceID
}
iDReturnsOnCall map[int]struct {
result1 protocol.DeviceID
}
IndexStub func(context.Context, string, []protocol.FileInfo) error IndexStub func(context.Context, string, []protocol.FileInfo) error
indexMutex sync.RWMutex indexMutex sync.RWMutex
indexArgsForCall []struct { indexArgsForCall []struct {
@ -368,6 +368,59 @@ func (fake *Connection) CryptoReturnsOnCall(i int, result1 string) {
}{result1} }{result1}
} }
func (fake *Connection) DeviceID() protocol.DeviceID {
fake.deviceIDMutex.Lock()
ret, specificReturn := fake.deviceIDReturnsOnCall[len(fake.deviceIDArgsForCall)]
fake.deviceIDArgsForCall = append(fake.deviceIDArgsForCall, struct {
}{})
stub := fake.DeviceIDStub
fakeReturns := fake.deviceIDReturns
fake.recordInvocation("DeviceID", []interface{}{})
fake.deviceIDMutex.Unlock()
if stub != nil {
return stub()
}
if specificReturn {
return ret.result1
}
return fakeReturns.result1
}
func (fake *Connection) DeviceIDCallCount() int {
fake.deviceIDMutex.RLock()
defer fake.deviceIDMutex.RUnlock()
return len(fake.deviceIDArgsForCall)
}
func (fake *Connection) DeviceIDCalls(stub func() protocol.DeviceID) {
fake.deviceIDMutex.Lock()
defer fake.deviceIDMutex.Unlock()
fake.DeviceIDStub = stub
}
func (fake *Connection) DeviceIDReturns(result1 protocol.DeviceID) {
fake.deviceIDMutex.Lock()
defer fake.deviceIDMutex.Unlock()
fake.DeviceIDStub = nil
fake.deviceIDReturns = struct {
result1 protocol.DeviceID
}{result1}
}
func (fake *Connection) DeviceIDReturnsOnCall(i int, result1 protocol.DeviceID) {
fake.deviceIDMutex.Lock()
defer fake.deviceIDMutex.Unlock()
fake.DeviceIDStub = nil
if fake.deviceIDReturnsOnCall == nil {
fake.deviceIDReturnsOnCall = make(map[int]struct {
result1 protocol.DeviceID
})
}
fake.deviceIDReturnsOnCall[i] = struct {
result1 protocol.DeviceID
}{result1}
}
func (fake *Connection) DownloadProgress(arg1 context.Context, arg2 string, arg3 []protocol.FileDownloadProgressUpdate) { func (fake *Connection) DownloadProgress(arg1 context.Context, arg2 string, arg3 []protocol.FileDownloadProgressUpdate) {
var arg3Copy []protocol.FileDownloadProgressUpdate var arg3Copy []protocol.FileDownloadProgressUpdate
if arg3 != nil { if arg3 != nil {
@ -460,59 +513,6 @@ func (fake *Connection) EstablishedAtReturnsOnCall(i int, result1 time.Time) {
}{result1} }{result1}
} }
func (fake *Connection) ID() protocol.DeviceID {
fake.iDMutex.Lock()
ret, specificReturn := fake.iDReturnsOnCall[len(fake.iDArgsForCall)]
fake.iDArgsForCall = append(fake.iDArgsForCall, struct {
}{})
stub := fake.IDStub
fakeReturns := fake.iDReturns
fake.recordInvocation("ID", []interface{}{})
fake.iDMutex.Unlock()
if stub != nil {
return stub()
}
if specificReturn {
return ret.result1
}
return fakeReturns.result1
}
func (fake *Connection) IDCallCount() int {
fake.iDMutex.RLock()
defer fake.iDMutex.RUnlock()
return len(fake.iDArgsForCall)
}
func (fake *Connection) IDCalls(stub func() protocol.DeviceID) {
fake.iDMutex.Lock()
defer fake.iDMutex.Unlock()
fake.IDStub = stub
}
func (fake *Connection) IDReturns(result1 protocol.DeviceID) {
fake.iDMutex.Lock()
defer fake.iDMutex.Unlock()
fake.IDStub = nil
fake.iDReturns = struct {
result1 protocol.DeviceID
}{result1}
}
func (fake *Connection) IDReturnsOnCall(i int, result1 protocol.DeviceID) {
fake.iDMutex.Lock()
defer fake.iDMutex.Unlock()
fake.IDStub = nil
if fake.iDReturnsOnCall == nil {
fake.iDReturnsOnCall = make(map[int]struct {
result1 protocol.DeviceID
})
}
fake.iDReturnsOnCall[i] = struct {
result1 protocol.DeviceID
}{result1}
}
func (fake *Connection) Index(arg1 context.Context, arg2 string, arg3 []protocol.FileInfo) error { func (fake *Connection) Index(arg1 context.Context, arg2 string, arg3 []protocol.FileInfo) error {
var arg3Copy []protocol.FileInfo var arg3Copy []protocol.FileInfo
if arg3 != nil { if arg3 != nil {
@ -1164,12 +1164,12 @@ func (fake *Connection) Invocations() map[string][][]interface{} {
defer fake.clusterConfigMutex.RUnlock() defer fake.clusterConfigMutex.RUnlock()
fake.cryptoMutex.RLock() fake.cryptoMutex.RLock()
defer fake.cryptoMutex.RUnlock() defer fake.cryptoMutex.RUnlock()
fake.deviceIDMutex.RLock()
defer fake.deviceIDMutex.RUnlock()
fake.downloadProgressMutex.RLock() fake.downloadProgressMutex.RLock()
defer fake.downloadProgressMutex.RUnlock() defer fake.downloadProgressMutex.RUnlock()
fake.establishedAtMutex.RLock() fake.establishedAtMutex.RLock()
defer fake.establishedAtMutex.RUnlock() defer fake.establishedAtMutex.RUnlock()
fake.iDMutex.RLock()
defer fake.iDMutex.RUnlock()
fake.indexMutex.RLock() fake.indexMutex.RLock()
defer fake.indexMutex.RUnlock() defer fake.indexMutex.RUnlock()
fake.indexUpdateMutex.RLock() fake.indexUpdateMutex.RLock()

View File

@ -9,27 +9,27 @@ package protocol
import "golang.org/x/text/unicode/norm" import "golang.org/x/text/unicode/norm"
func makeNative(m Model) Model { return nativeModel{m} } func makeNative(m contextLessModel) contextLessModel { return nativeModel{m} }
type nativeModel struct { type nativeModel struct {
Model contextLessModel
} }
func (m nativeModel) Index(deviceID DeviceID, folder string, files []FileInfo) error { func (m nativeModel) Index(folder string, files []FileInfo) error {
for i := range files { for i := range files {
files[i].Name = norm.NFD.String(files[i].Name) files[i].Name = norm.NFD.String(files[i].Name)
} }
return m.Model.Index(deviceID, folder, files) return m.contextLessModel.Index(folder, files)
} }
func (m nativeModel) IndexUpdate(deviceID DeviceID, folder string, files []FileInfo) error { func (m nativeModel) IndexUpdate(folder string, files []FileInfo) error {
for i := range files { for i := range files {
files[i].Name = norm.NFD.String(files[i].Name) files[i].Name = norm.NFD.String(files[i].Name)
} }
return m.Model.IndexUpdate(deviceID, folder, files) return m.contextLessModel.IndexUpdate(folder, files)
} }
func (m nativeModel) Request(deviceID DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) { func (m nativeModel) Request(folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
name = norm.NFD.String(name) name = norm.NFD.String(name)
return m.Model.Request(deviceID, folder, name, blockNo, size, offset, hash, weakHash, fromTemporary) return m.contextLessModel.Request(folder, name, blockNo, size, offset, hash, weakHash, fromTemporary)
} }

View File

@ -7,4 +7,4 @@ package protocol
// Normal Unixes uses NFC and slashes, which is the wire format. // Normal Unixes uses NFC and slashes, which is the wire format.
func makeNative(m Model) Model { return m } func makeNative(m contextLessModel) contextLessModel { return m }

View File

@ -13,30 +13,30 @@ import (
"strings" "strings"
) )
func makeNative(m Model) Model { return nativeModel{m} } func makeNative(m contextLessModel) contextLessModel { return nativeModel{m} }
type nativeModel struct { type nativeModel struct {
Model contextLessModel
} }
func (m nativeModel) Index(deviceID DeviceID, folder string, files []FileInfo) error { func (m nativeModel) Index(folder string, files []FileInfo) error {
files = fixupFiles(files) files = fixupFiles(files)
return m.Model.Index(deviceID, folder, files) return m.contextLessModel.Index(folder, files)
} }
func (m nativeModel) IndexUpdate(deviceID DeviceID, folder string, files []FileInfo) error { func (m nativeModel) IndexUpdate(folder string, files []FileInfo) error {
files = fixupFiles(files) files = fixupFiles(files)
return m.Model.IndexUpdate(deviceID, folder, files) return m.contextLessModel.IndexUpdate(folder, files)
} }
func (m nativeModel) Request(deviceID DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) { func (m nativeModel) Request(folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
if strings.Contains(name, `\`) { if strings.Contains(name, `\`) {
l.Warnf("Dropping request for %s, contains invalid path separator", name) l.Warnf("Dropping request for %s, contains invalid path separator", name)
return nil, ErrNoSuchFile return nil, ErrNoSuchFile
} }
name = filepath.FromSlash(name) name = filepath.FromSlash(name)
return m.Model.Request(deviceID, folder, name, blockNo, size, offset, hash, weakHash, fromTemporary) return m.contextLessModel.Request(folder, name, blockNo, size, offset, hash, weakHash, fromTemporary)
} }
func fixupFiles(files []FileInfo) []FileInfo { func fixupFiles(files []FileInfo) []FileInfo {

View File

@ -123,17 +123,28 @@ var (
type Model interface { type Model interface {
// An index was received from the peer device // An index was received from the peer device
Index(deviceID DeviceID, folder string, files []FileInfo) error Index(conn Connection, folder string, files []FileInfo) error
// An index update was received from the peer device // An index update was received from the peer device
IndexUpdate(deviceID DeviceID, folder string, files []FileInfo) error IndexUpdate(conn Connection, folder string, files []FileInfo) error
// A request was made by the peer device // A request was made by the peer device
Request(deviceID DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) Request(conn Connection, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error)
// A cluster configuration message was received // A cluster configuration message was received
ClusterConfig(deviceID DeviceID, config ClusterConfig) error ClusterConfig(conn Connection, config ClusterConfig) error
// The peer device closed the connection or an error occurred // The peer device closed the connection or an error occurred
Closed(device DeviceID, err error) Closed(conn Connection, err error)
// The peer device sent progress updates for the files it is currently downloading // The peer device sent progress updates for the files it is currently downloading
DownloadProgress(deviceID DeviceID, folder string, updates []FileDownloadProgressUpdate) error DownloadProgress(conn Connection, folder string, updates []FileDownloadProgressUpdate) error
}
// contextLessModel is the Model interface, but without the initial
// Connection parameter. Internal use only.
type contextLessModel interface {
Index(folder string, files []FileInfo) error
IndexUpdate(folder string, files []FileInfo) error
Request(folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error)
ClusterConfig(config ClusterConfig) error
Closed(err error)
DownloadProgress(folder string, updates []FileDownloadProgressUpdate) error
} }
type RequestResponse interface { type RequestResponse interface {
@ -146,7 +157,7 @@ type Connection interface {
Start() Start()
SetFolderPasswords(passwords map[string]string) SetFolderPasswords(passwords map[string]string)
Close(err error) Close(err error)
ID() DeviceID DeviceID() DeviceID
Index(ctx context.Context, folder string, files []FileInfo) error Index(ctx context.Context, folder string, files []FileInfo) error
IndexUpdate(ctx context.Context, folder string, files []FileInfo) error IndexUpdate(ctx context.Context, folder string, files []FileInfo) error
Request(ctx context.Context, folder string, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) Request(ctx context.Context, folder string, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error)
@ -171,8 +182,8 @@ type ConnectionInfo interface {
type rawConnection struct { type rawConnection struct {
ConnectionInfo ConnectionInfo
id DeviceID deviceID DeviceID
receiver Model model contextLessModel
startTime time.Time startTime time.Time
cr *countingReader cr *countingReader
@ -229,10 +240,16 @@ const (
// Should not be modified in production code, just for testing. // Should not be modified in production code, just for testing.
var CloseTimeout = 10 * time.Second var CloseTimeout = 10 * time.Second
func NewConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, closer io.Closer, receiver Model, connInfo ConnectionInfo, compress Compression, passwords map[string]string, keyGen *KeyGenerator) Connection { func NewConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, closer io.Closer, model Model, connInfo ConnectionInfo, compress Compression, passwords map[string]string, keyGen *KeyGenerator) Connection {
// We create the wrapper for the model first, as it needs to be passed
// in at the lowest level in the stack. At the end of construction,
// before returning, we add the connection to cwm so that it can be used
// by the model.
cwm := &connectionWrappingModel{model: model}
// Encryption / decryption is first (outermost) before conversion to // Encryption / decryption is first (outermost) before conversion to
// native path formats. // native path formats.
nm := makeNative(receiver) nm := makeNative(cwm)
em := newEncryptedModel(nm, newFolderKeyRegistry(keyGen, passwords), keyGen) em := newEncryptedModel(nm, newFolderKeyRegistry(keyGen, passwords), keyGen)
// We do the wire format conversion first (outermost) so that the // We do the wire format conversion first (outermost) so that the
@ -241,17 +258,18 @@ func NewConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, closer
ec := newEncryptedConnection(rc, rc, em.folderKeys, keyGen) ec := newEncryptedConnection(rc, rc, em.folderKeys, keyGen)
wc := wireFormatConnection{ec} wc := wireFormatConnection{ec}
cwm.conn = wc
return wc return wc
} }
func newRawConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, closer io.Closer, receiver Model, connInfo ConnectionInfo, compress Compression) *rawConnection { func newRawConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, closer io.Closer, receiver contextLessModel, connInfo ConnectionInfo, compress Compression) *rawConnection {
cr := &countingReader{Reader: reader} cr := &countingReader{Reader: reader}
cw := &countingWriter{Writer: writer} cw := &countingWriter{Writer: writer}
return &rawConnection{ return &rawConnection{
ConnectionInfo: connInfo, ConnectionInfo: connInfo,
id: deviceID, deviceID: deviceID,
receiver: receiver, model: receiver,
cr: cr, cr: cr,
cw: cw, cw: cw,
closer: closer, closer: closer,
@ -295,8 +313,8 @@ func (c *rawConnection) Start() {
c.startTime = time.Now().Truncate(time.Second) c.startTime = time.Now().Truncate(time.Second)
} }
func (c *rawConnection) ID() DeviceID { func (c *rawConnection) DeviceID() DeviceID {
return c.id return c.deviceID
} }
// Index writes the list of file information to the connected peer device // Index writes the list of file information to the connected peer device
@ -462,7 +480,7 @@ func (c *rawConnection) dispatcherLoop() (err error) {
switch msg := msg.(type) { switch msg := msg.(type) {
case *ClusterConfig: case *ClusterConfig:
err = c.receiver.ClusterConfig(c.id, *msg) err = c.model.ClusterConfig(*msg)
case *Index: case *Index:
err = c.handleIndex(*msg) err = c.handleIndex(*msg)
@ -477,7 +495,7 @@ func (c *rawConnection) dispatcherLoop() (err error) {
c.handleResponse(*msg) c.handleResponse(*msg)
case *DownloadProgress: case *DownloadProgress:
err = c.receiver.DownloadProgress(c.id, msg.Folder, msg.Updates) err = c.model.DownloadProgress(msg.Folder, msg.Updates)
} }
if err != nil { if err != nil {
return newHandleError(err, msgContext) return newHandleError(err, msgContext)
@ -579,13 +597,13 @@ func (c *rawConnection) readHeader(fourByteBuf []byte) (Header, error) {
} }
func (c *rawConnection) handleIndex(im Index) error { func (c *rawConnection) handleIndex(im Index) error {
l.Debugf("Index(%v, %v, %d file)", c.id, im.Folder, len(im.Files)) l.Debugf("Index(%v, %v, %d file)", c.deviceID, im.Folder, len(im.Files))
return c.receiver.Index(c.id, im.Folder, im.Files) return c.model.Index(im.Folder, im.Files)
} }
func (c *rawConnection) handleIndexUpdate(im IndexUpdate) error { func (c *rawConnection) handleIndexUpdate(im IndexUpdate) error {
l.Debugf("queueing IndexUpdate(%v, %v, %d files)", c.id, im.Folder, len(im.Files)) l.Debugf("queueing IndexUpdate(%v, %v, %d files)", c.deviceID, im.Folder, len(im.Files))
return c.receiver.IndexUpdate(c.id, im.Folder, im.Files) return c.model.IndexUpdate(im.Folder, im.Files)
} }
// checkIndexConsistency verifies a number of invariants on FileInfos received in // checkIndexConsistency verifies a number of invariants on FileInfos received in
@ -651,7 +669,7 @@ func checkFilename(name string) error {
} }
func (c *rawConnection) handleRequest(req Request) { func (c *rawConnection) handleRequest(req Request) {
res, err := c.receiver.Request(c.id, req.Folder, req.Name, int32(req.BlockNo), int32(req.Size), req.Offset, req.Hash, req.WeakHash, req.FromTemporary) res, err := c.model.Request(req.Folder, req.Name, int32(req.BlockNo), int32(req.Size), req.Offset, req.Hash, req.WeakHash, req.FromTemporary)
if err != nil { if err != nil {
c.send(context.Background(), &Response{ c.send(context.Background(), &Response{
ID: req.ID, ID: req.ID,
@ -925,7 +943,7 @@ func (c *rawConnection) internalClose(err error) {
c.closeOnce.Do(func() { c.closeOnce.Do(func() {
l.Debugln("close due to", err) l.Debugln("close due to", err)
if cerr := c.closer.Close(); cerr != nil { if cerr := c.closer.Close(); cerr != nil {
l.Debugln(c.id, "failed to close underlying conn:", cerr) l.Debugln(c.deviceID, "failed to close underlying conn:", cerr)
} }
close(c.closed) close(c.closed)
@ -940,7 +958,7 @@ func (c *rawConnection) internalClose(err error) {
<-c.dispatcherLoopStopped <-c.dispatcherLoopStopped
c.receiver.Closed(c.ID(), err) c.model.Closed(err)
}) })
} }
@ -958,11 +976,11 @@ func (c *rawConnection) pingSender() {
case <-ticker.C: case <-ticker.C:
d := time.Since(c.cw.Last()) d := time.Since(c.cw.Last())
if d < PingSendInterval/2 { if d < PingSendInterval/2 {
l.Debugln(c.id, "ping skipped after wr", d) l.Debugln(c.deviceID, "ping skipped after wr", d)
continue continue
} }
l.Debugln(c.id, "ping -> after", d) l.Debugln(c.deviceID, "ping -> after", d)
c.ping() c.ping()
case <-c.closed: case <-c.closed:
@ -983,11 +1001,11 @@ func (c *rawConnection) pingReceiver() {
case <-ticker.C: case <-ticker.C:
d := time.Since(c.cr.Last()) d := time.Since(c.cr.Last())
if d > ReceiveTimeout { if d > ReceiveTimeout {
l.Debugln(c.id, "ping timeout", d) l.Debugln(c.deviceID, "ping timeout", d)
c.internalClose(ErrTimeout) c.internalClose(ErrTimeout)
} }
l.Debugln(c.id, "last read within", d) l.Debugln(c.deviceID, "last read within", d)
case <-c.closed: case <-c.closed:
return return
@ -1068,3 +1086,35 @@ func messageContext(msg message) (string, error) {
return "", errors.New("unknown or empty message") return "", errors.New("unknown or empty message")
} }
} }
// connectionWrappingModel takes the Model interface from the model package,
// which expects the Connection as the first parameter in all methods, and
// wraps it to conform to the protocol.contextLessModel interface.
type connectionWrappingModel struct {
conn Connection
model Model
}
func (c *connectionWrappingModel) Index(folder string, files []FileInfo) error {
return c.model.Index(c.conn, folder, files)
}
func (c *connectionWrappingModel) IndexUpdate(folder string, files []FileInfo) error {
return c.model.IndexUpdate(c.conn, folder, files)
}
func (c *connectionWrappingModel) Request(folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
return c.model.Request(c.conn, folder, name, blockNo, size, offset, hash, weakHash, fromTemporary)
}
func (c *connectionWrappingModel) ClusterConfig(config ClusterConfig) error {
return c.model.ClusterConfig(c.conn, config)
}
func (c *connectionWrappingModel) Closed(err error) {
c.model.Closed(c.conn, err)
}
func (c *connectionWrappingModel) DownloadProgress(folder string, updates []FileDownloadProgressUpdate) error {
return c.model.DownloadProgress(c.conn, folder, updates)
}

View File

@ -145,7 +145,7 @@ func TestCloseRace(t *testing.T) {
indexReceived := make(chan struct{}) indexReceived := make(chan struct{})
unblockIndex := make(chan struct{}) unblockIndex := make(chan struct{})
m0 := newTestModel() m0 := newTestModel()
m0.indexFn = func(_ DeviceID, _ string, _ []FileInfo) { m0.indexFn = func(string, []FileInfo) {
close(indexReceived) close(indexReceived)
<-unblockIndex <-unblockIndex
} }
@ -924,7 +924,7 @@ func TestDispatcherToCloseDeadlock(t *testing.T) {
m := newTestModel() m := newTestModel()
rw := testutils.NewBlockingRW() rw := testutils.NewBlockingRW()
c := getRawConnection(NewConnection(c0ID, rw, &testutils.NoopRW{}, testutils.NoopCloser{}, m, new(mockedConnectionInfo), CompressionAlways, nil, testKeyGen)) c := getRawConnection(NewConnection(c0ID, rw, &testutils.NoopRW{}, testutils.NoopCloser{}, m, new(mockedConnectionInfo), CompressionAlways, nil, testKeyGen))
m.ccFn = func(devID DeviceID, cc ClusterConfig) { m.ccFn = func(ClusterConfig) {
c.Close(errManual) c.Close(errManual)
} }
c.Start() c.Start()