lib/protocol: Refactor interface (#9375)
This is a refactor of the protocol/model interface to take the actual
message as the parameter, instead of the broken-out fields:
```diff
type Model interface {
// An index was received from the peer device
- Index(conn Connection, folder string, files []FileInfo) error
+ Index(conn Connection, idx *Index) error
// An index update was received from the peer device
- IndexUpdate(conn Connection, folder string, files []FileInfo) error
+ IndexUpdate(conn Connection, idxUp *IndexUpdate) error
// A request was made by the peer device
- Request(conn Connection, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error)
+ Request(conn Connection, req *Request) (RequestResponse, error)
// A cluster configuration message was received
- ClusterConfig(conn Connection, config ClusterConfig) error
+ ClusterConfig(conn Connection, config *ClusterConfig) error
// The peer device closed the connection or an error occurred
Closed(conn Connection, err error)
// The peer device sent progress updates for the files it is currently downloading
- DownloadProgress(conn Connection, folder string, updates []FileDownloadProgressUpdate) error
+ DownloadProgress(conn Connection, p *DownloadProgress) error
}
```
(and changing the `ClusterConfig` to `*ClusterConfig` for symmetry;
we'll be forced to use all pointers everywhere at some point anyway...)
The reason for this is that I have another thing cooking which is a
small troubleshooting change to check index consistency during transfer.
This required adding a field or two to the index/indexupdate messages,
and plumbing the extra parameters in umpteen changes is almost as big a
diff as this is. I figured let's do it once and avoid having to do that
in the future again...
The rest of the diff falls out of the change above, much of it being in
test code where we run these methods manually...
This commit is contained in:
+47
-47
@@ -52,8 +52,8 @@ func newState(t testing.TB, cfg config.Configuration) (*testModel, context.Cance
|
||||
return m, cancel
|
||||
}
|
||||
|
||||
func createClusterConfig(remote protocol.DeviceID, ids ...string) protocol.ClusterConfig {
|
||||
cc := protocol.ClusterConfig{
|
||||
func createClusterConfig(remote protocol.DeviceID, ids ...string) *protocol.ClusterConfig {
|
||||
cc := &protocol.ClusterConfig{
|
||||
Folders: make([]protocol.Folder, len(ids)),
|
||||
}
|
||||
for i, id := range ids {
|
||||
@@ -65,7 +65,7 @@ func createClusterConfig(remote protocol.DeviceID, ids ...string) protocol.Clust
|
||||
return addFolderDevicesToClusterConfig(cc, remote)
|
||||
}
|
||||
|
||||
func addFolderDevicesToClusterConfig(cc protocol.ClusterConfig, remote protocol.DeviceID) protocol.ClusterConfig {
|
||||
func addFolderDevicesToClusterConfig(cc *protocol.ClusterConfig, remote protocol.DeviceID) *protocol.ClusterConfig {
|
||||
for i := range cc.Folders {
|
||||
cc.Folders[i].Devices = []protocol.Device{
|
||||
{ID: myID},
|
||||
@@ -94,7 +94,7 @@ func TestRequest(t *testing.T) {
|
||||
m.ScanFolder("default")
|
||||
|
||||
// Existing, shared file
|
||||
res, err := m.Request(device1Conn, "default", "foo", 0, 6, 0, nil, 0, false)
|
||||
res, err := m.Request(device1Conn, &protocol.Request{Folder: "default", Name: "foo", Size: 6})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -104,35 +104,35 @@ func TestRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
// Existing, nonshared file
|
||||
_, err = m.Request(device2Conn, "default", "foo", 0, 6, 0, nil, 0, false)
|
||||
_, err = m.Request(device2Conn, &protocol.Request{Folder: "default", Name: "foo", Size: 6})
|
||||
if err == nil {
|
||||
t.Error("Unexpected nil error on insecure file read")
|
||||
}
|
||||
|
||||
// Nonexistent file
|
||||
_, err = m.Request(device1Conn, "default", "nonexistent", 0, 6, 0, nil, 0, false)
|
||||
_, err = m.Request(device1Conn, &protocol.Request{Folder: "default", Name: "nonexistent", Size: 6})
|
||||
if err == nil {
|
||||
t.Error("Unexpected nil error on insecure file read")
|
||||
}
|
||||
|
||||
// Shared folder, but disallowed file name
|
||||
_, err = m.Request(device1Conn, "default", "../walk.go", 0, 6, 0, nil, 0, false)
|
||||
_, err = m.Request(device1Conn, &protocol.Request{Folder: "default", Name: "../walk.go", Size: 6})
|
||||
if err == nil {
|
||||
t.Error("Unexpected nil error on insecure file read")
|
||||
}
|
||||
|
||||
// Negative offset
|
||||
_, err = m.Request(device1Conn, "default", "foo", 0, -4, 0, nil, 0, false)
|
||||
// Negative size
|
||||
_, err = m.Request(device1Conn, &protocol.Request{Folder: "default", Name: "foo", Size: -4})
|
||||
if err == nil {
|
||||
t.Error("Unexpected nil error on insecure file read")
|
||||
}
|
||||
|
||||
// Larger block than available
|
||||
_, err = m.Request(device1Conn, "default", "foo", 0, 42, 0, []byte("hash necessary but not checked"), 0, false)
|
||||
_, err = m.Request(device1Conn, &protocol.Request{Folder: "default", Name: "foo", Size: 42, Hash: []byte("hash necessary but not checked")})
|
||||
if err == nil {
|
||||
t.Error("Unexpected nil error on read past end of file")
|
||||
}
|
||||
_, err = m.Request(device1Conn, "default", "foo", 0, 42, 0, nil, 0, false)
|
||||
_, err = m.Request(device1Conn, &protocol.Request{Folder: "default", Name: "foo", Size: 42})
|
||||
if err != nil {
|
||||
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())
|
||||
|
||||
files := genFiles(nfiles)
|
||||
must(b, m.Index(device1Conn, fcfg.ID, files))
|
||||
must(b, m.Index(device1Conn, &protocol.Index{Folder: fcfg.ID, Files: files}))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
must(b, m.Index(device1Conn, fcfg.ID, files))
|
||||
must(b, m.Index(device1Conn, &protocol.Index{Folder: fcfg.ID, Files: files}))
|
||||
}
|
||||
b.ReportAllocs()
|
||||
}
|
||||
@@ -197,11 +197,11 @@ func benchmarkIndexUpdate(b *testing.B, nfiles, nufiles int) {
|
||||
files := genFiles(nfiles)
|
||||
ufiles := genFiles(nufiles)
|
||||
|
||||
must(b, m.Index(device1Conn, fcfg.ID, files))
|
||||
must(b, m.Index(device1Conn, &protocol.Index{Folder: fcfg.ID, Files: files}))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
must(b, m.IndexUpdate(device1Conn, fcfg.ID, ufiles))
|
||||
must(b, m.IndexUpdate(device1Conn, &protocol.IndexUpdate{Folder: fcfg.ID, Files: ufiles}))
|
||||
}
|
||||
b.ReportAllocs()
|
||||
}
|
||||
@@ -218,7 +218,7 @@ func BenchmarkRequestOut(b *testing.B) {
|
||||
fc.addFile(f.Name, 0o644, protocol.FileInfoTypeFile, []byte("some data to return"))
|
||||
}
|
||||
m.AddConnection(fc, protocol.Hello{})
|
||||
must(b, m.Index(device1Conn, "default", files))
|
||||
must(b, m.Index(device1Conn, &protocol.Index{Folder: "default", Files: files}))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
@@ -247,7 +247,7 @@ func BenchmarkRequestInSingleFile(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
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 {
|
||||
if _, err := m.Request(device1Conn, &protocol.Request{Folder: "default", Name: "request/for/a/file/in/a/couple/of/dirs/128k", Size: 128 << 10}); err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -634,7 +634,7 @@ func TestIntroducer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1Conn, protocol.ClusterConfig{})
|
||||
m.ClusterConfig(device1Conn, &protocol.ClusterConfig{})
|
||||
|
||||
if _, ok := m.cfg.Device(device2); ok {
|
||||
t.Error("device 2 should have been removed")
|
||||
@@ -686,7 +686,7 @@ func TestIntroducer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1Conn, protocol.ClusterConfig{})
|
||||
m.ClusterConfig(device1Conn, &protocol.ClusterConfig{})
|
||||
|
||||
if _, ok := m.cfg.Device(device2); !ok {
|
||||
t.Error("device 2 should not have been removed")
|
||||
@@ -794,7 +794,7 @@ func TestIntroducer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1Conn, protocol.ClusterConfig{})
|
||||
m.ClusterConfig(device1Conn, &protocol.ClusterConfig{})
|
||||
|
||||
if _, ok := m.cfg.Device(device2); !ok {
|
||||
t.Error("device 2 should not have been removed")
|
||||
@@ -847,7 +847,7 @@ func TestIntroducer(t *testing.T) {
|
||||
})
|
||||
defer cleanupModel(m)
|
||||
defer cancel()
|
||||
m.ClusterConfig(device1Conn, protocol.ClusterConfig{})
|
||||
m.ClusterConfig(device1Conn, &protocol.ClusterConfig{})
|
||||
|
||||
if _, ok := m.cfg.Device(device2); !ok {
|
||||
t.Error("device 2 should not have been removed")
|
||||
@@ -1035,10 +1035,10 @@ func TestAutoAcceptNewFolderPremutationsNoPanic(t *testing.T) {
|
||||
cfg.Folders = append(cfg.Folders, fcfg)
|
||||
}
|
||||
m, cancel := newState(t, cfg)
|
||||
m.ClusterConfig(device1Conn, protocol.ClusterConfig{
|
||||
m.ClusterConfig(device1Conn, &protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{dev1folder},
|
||||
})
|
||||
m.ClusterConfig(device2Conn, protocol.ClusterConfig{
|
||||
m.ClusterConfig(device2Conn, &protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{dev2folder},
|
||||
})
|
||||
cleanupModel(m)
|
||||
@@ -1159,7 +1159,7 @@ func TestAutoAcceptNameConflict(t *testing.T) {
|
||||
m, cancel := newState(t, defaultAutoAcceptCfg)
|
||||
defer cleanupModel(m)
|
||||
defer cancel()
|
||||
m.ClusterConfig(device1Conn, protocol.ClusterConfig{
|
||||
m.ClusterConfig(device1Conn, &protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
@@ -1179,7 +1179,7 @@ func TestAutoAcceptPrefersLabel(t *testing.T) {
|
||||
label := srand.String(8)
|
||||
defer cleanupModel(m)
|
||||
defer cancel()
|
||||
m.ClusterConfig(device1Conn, addFolderDevicesToClusterConfig(protocol.ClusterConfig{
|
||||
m.ClusterConfig(device1Conn, addFolderDevicesToClusterConfig(&protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
@@ -1203,7 +1203,7 @@ func TestAutoAcceptFallsBackToID(t *testing.T) {
|
||||
}
|
||||
defer cleanupModel(m)
|
||||
defer cancel()
|
||||
m.ClusterConfig(device1Conn, addFolderDevicesToClusterConfig(protocol.ClusterConfig{
|
||||
m.ClusterConfig(device1Conn, addFolderDevicesToClusterConfig(&protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
@@ -1325,8 +1325,8 @@ func TestAutoAcceptEnc(t *testing.T) {
|
||||
defer os.RemoveAll(id)
|
||||
|
||||
token := []byte("token")
|
||||
basicCC := func() protocol.ClusterConfig {
|
||||
return protocol.ClusterConfig{
|
||||
basicCC := func() *protocol.ClusterConfig {
|
||||
return &protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{{
|
||||
ID: id,
|
||||
Label: id,
|
||||
@@ -1336,7 +1336,7 @@ func TestAutoAcceptEnc(t *testing.T) {
|
||||
|
||||
// Earlier tests might cause the connection to get closed, thus ClusterConfig
|
||||
// would panic.
|
||||
clusterConfig := func(deviceID protocol.DeviceID, cm protocol.ClusterConfig) {
|
||||
clusterConfig := func(deviceID protocol.DeviceID, cm *protocol.ClusterConfig) {
|
||||
conn := newFakeConnection(deviceID, m)
|
||||
m.AddConnection(conn, protocol.Hello{})
|
||||
m.ClusterConfig(conn, cm)
|
||||
@@ -1808,7 +1808,7 @@ func TestGlobalDirectoryTree(t *testing.T) {
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
must(t, m.Index(conn, "default", testdata))
|
||||
must(t, m.Index(conn, &protocol.Index{Folder: "default", Files: testdata}))
|
||||
|
||||
result, _ := m.GlobalDirectoryTree("default", "", -1, false)
|
||||
|
||||
@@ -2015,7 +2015,7 @@ func benchmarkTree(b *testing.B, n1, n2 int) {
|
||||
m.ScanFolder(fcfg.ID)
|
||||
files := genDeepFiles(n1, n2)
|
||||
|
||||
must(b, m.Index(device1Conn, fcfg.ID, files))
|
||||
must(b, m.Index(device1Conn, &protocol.Index{Folder: fcfg.ID, Files: files}))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
@@ -2161,7 +2161,7 @@ func TestSharedWithClearedOnDisconnect(t *testing.T) {
|
||||
conn2 := newFakeConnection(device2, m)
|
||||
m.AddConnection(conn2, protocol.Hello{})
|
||||
|
||||
m.ClusterConfig(conn1, protocol.ClusterConfig{
|
||||
m.ClusterConfig(conn1, &protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: "default",
|
||||
@@ -2173,7 +2173,7 @@ func TestSharedWithClearedOnDisconnect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(conn2, protocol.ClusterConfig{
|
||||
m.ClusterConfig(conn2, &protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: "default",
|
||||
@@ -2426,7 +2426,7 @@ func TestRemoveDirWithContent(t *testing.T) {
|
||||
file.Deleted = true
|
||||
file.Version = file.Version.Update(device1.Short()).Update(device1.Short())
|
||||
|
||||
must(t, m.IndexUpdate(conn, fcfg.ID, []protocol.FileInfo{dir, file}))
|
||||
must(t, m.IndexUpdate(conn, &protocol.IndexUpdate{Folder: fcfg.ID, Files: []protocol.FileInfo{dir, file}}))
|
||||
|
||||
// Is there something we could trigger on instead of just waiting?
|
||||
timeout := time.NewTimer(5 * time.Second)
|
||||
@@ -2925,14 +2925,14 @@ func TestRequestLimit(t *testing.T) {
|
||||
m.ScanFolder("default")
|
||||
|
||||
befReq := time.Now()
|
||||
first, err := m.Request(conn, "default", file, 0, 2000, 0, nil, 0, false)
|
||||
first, err := m.Request(conn, &protocol.Request{Folder: "default", Name: file, Size: 2000})
|
||||
if err != nil {
|
||||
t.Fatalf("First request failed: %v", err)
|
||||
}
|
||||
reqDur := time.Since(befReq)
|
||||
returned := make(chan struct{})
|
||||
go func() {
|
||||
second, err := m.Request(conn, "default", file, 0, 2000, 0, nil, 0, false)
|
||||
second, err := m.Request(conn, &protocol.Request{Folder: "default", Name: file, Size: 2000})
|
||||
if err != nil {
|
||||
t.Errorf("Second request failed: %v", err)
|
||||
}
|
||||
@@ -3594,7 +3594,7 @@ func TestScanDeletedROChangedOnSR(t *testing.T) {
|
||||
}
|
||||
// A remote must have the file, otherwise the deletion below is
|
||||
// automatically resolved as not a ro-changed item.
|
||||
must(t, m.IndexUpdate(conn, fcfg.ID, []protocol.FileInfo{file}))
|
||||
must(t, m.IndexUpdate(conn, &protocol.IndexUpdate{Folder: fcfg.ID, Files: []protocol.FileInfo{file}}))
|
||||
|
||||
must(t, ffs.Remove(name))
|
||||
m.ScanFolders()
|
||||
@@ -3708,9 +3708,9 @@ func TestIssue6961(t *testing.T) {
|
||||
version := protocol.Vector{}.Update(device1.Short())
|
||||
|
||||
// Remote, valid and existing file
|
||||
must(t, m.Index(conn1, fcfg.ID, []protocol.FileInfo{{Name: name, Version: version, Sequence: 1}}))
|
||||
must(t, m.Index(conn1, &protocol.Index{Folder: fcfg.ID, Files: []protocol.FileInfo{{Name: name, Version: version, Sequence: 1}}}))
|
||||
// Remote, invalid (receive-only) and existing file
|
||||
must(t, m.Index(conn2, fcfg.ID, []protocol.FileInfo{{Name: name, RawInvalid: true, Sequence: 1}}))
|
||||
must(t, m.Index(conn2, &protocol.Index{Folder: fcfg.ID, Files: []protocol.FileInfo{{Name: name, RawInvalid: true, Sequence: 1}}}))
|
||||
// Create a local file
|
||||
if fd, err := tfs.OpenFile(name, fs.OptCreate, 0o666); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -3736,7 +3736,7 @@ func TestIssue6961(t *testing.T) {
|
||||
m.ScanFolders()
|
||||
|
||||
// Drop the remote index, add some other file.
|
||||
must(t, m.Index(conn2, fcfg.ID, []protocol.FileInfo{{Name: "bar", RawInvalid: true, Sequence: 1}}))
|
||||
must(t, m.Index(conn2, &protocol.Index{Folder: fcfg.ID, Files: []protocol.FileInfo{{Name: "bar", RawInvalid: true, Sequence: 1}}}))
|
||||
|
||||
// Pause and unpause folder to create new db.FileSet and thus recalculate everything
|
||||
pauseFolder(t, wcfg, fcfg.ID, true)
|
||||
@@ -3759,7 +3759,7 @@ func TestCompletionEmptyGlobal(t *testing.T) {
|
||||
m.mut.Unlock()
|
||||
files[0].Deleted = true
|
||||
files[0].Version = files[0].Version.Update(device1.Short())
|
||||
must(t, m.IndexUpdate(conn, fcfg.ID, files))
|
||||
must(t, m.IndexUpdate(conn, &protocol.IndexUpdate{Folder: fcfg.ID, Files: files}))
|
||||
comp := m.testCompletion(protocol.LocalDeviceID, fcfg.ID)
|
||||
if comp.CompletionPct != 95 {
|
||||
t.Error("Expected completion of 95%, got", comp.CompletionPct)
|
||||
@@ -3780,26 +3780,26 @@ func TestNeedMetaAfterIndexReset(t *testing.T) {
|
||||
|
||||
// Start with two remotes having one file, then both deleting it, then
|
||||
// only one adding it again.
|
||||
must(t, m.Index(conn1, fcfg.ID, files))
|
||||
must(t, m.Index(conn2, fcfg.ID, files))
|
||||
must(t, m.Index(conn1, &protocol.Index{Folder: fcfg.ID, Files: files}))
|
||||
must(t, m.Index(conn2, &protocol.Index{Folder: fcfg.ID, Files: files}))
|
||||
seq++
|
||||
files[0].SetDeleted(device2.Short())
|
||||
files[0].Sequence = seq
|
||||
must(t, m.IndexUpdate(conn1, fcfg.ID, files))
|
||||
must(t, m.IndexUpdate(conn2, fcfg.ID, files))
|
||||
must(t, m.IndexUpdate(conn1, &protocol.IndexUpdate{Folder: fcfg.ID, Files: files}))
|
||||
must(t, m.IndexUpdate(conn2, &protocol.IndexUpdate{Folder: fcfg.ID, Files: files}))
|
||||
seq++
|
||||
files[0].Deleted = false
|
||||
files[0].Size = 20
|
||||
files[0].Version = files[0].Version.Update(device1.Short())
|
||||
files[0].Sequence = seq
|
||||
must(t, m.IndexUpdate(conn1, fcfg.ID, files))
|
||||
must(t, m.IndexUpdate(conn1, &protocol.IndexUpdate{Folder: fcfg.ID, Files: files}))
|
||||
|
||||
if comp := m.testCompletion(device2, fcfg.ID); comp.NeedItems != 1 {
|
||||
t.Error("Expected one needed item for device2, got", comp.NeedItems)
|
||||
}
|
||||
|
||||
// Pretend we had an index reset on device 1
|
||||
must(t, m.Index(conn1, fcfg.ID, files))
|
||||
must(t, m.Index(conn1, &protocol.Index{Folder: fcfg.ID, Files: files}))
|
||||
if comp := m.testCompletion(device2, fcfg.ID); comp.NeedItems != 1 {
|
||||
t.Error("Expected one needed item for device2, got", comp.NeedItems)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user