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
21 changed files with 431 additions and 359 deletions
+6 -6
View File
@@ -167,15 +167,15 @@ func negotiateTLS(cert tls.Certificate, conn0, conn1 net.Conn) (net.Conn, net.Co
type fakeModel struct{}
func (*fakeModel) Index(_ DeviceID, _ string, _ []FileInfo) error {
func (*fakeModel) Index(Connection, string, []FileInfo) error {
return nil
}
func (*fakeModel) IndexUpdate(_ DeviceID, _ string, _ []FileInfo) error {
func (*fakeModel) IndexUpdate(Connection, string, []FileInfo) error {
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
// can verify that it did in fact get some data back over the
// connection.
@@ -184,13 +184,13 @@ func (*fakeModel) Request(_ DeviceID, _, _ string, _, size int32, offset int64,
return &fakeRequestResponse{buf}, nil
}
func (*fakeModel) ClusterConfig(_ DeviceID, _ ClusterConfig) error {
func (*fakeModel) ClusterConfig(Connection, ClusterConfig) error {
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
}
+10 -10
View File
@@ -13,8 +13,8 @@ type TestModel struct {
hash []byte
weakHash uint32
fromTemporary bool
indexFn func(DeviceID, string, []FileInfo)
ccFn func(DeviceID, ClusterConfig)
indexFn func(string, []FileInfo)
ccFn func(ClusterConfig)
closedCh chan struct{}
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 {
t.indexFn(deviceID, folder, files)
t.indexFn(folder, files)
}
return nil
}
func (*TestModel) IndexUpdate(_ DeviceID, _ string, _ []FileInfo) error {
func (*TestModel) IndexUpdate(Connection, string, []FileInfo) error {
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.name = name
t.offset = offset
@@ -49,19 +49,19 @@ func (t *TestModel) Request(_ DeviceID, folder, name string, _, size int32, offs
return &fakeRequestResponse{buf}, nil
}
func (t *TestModel) Closed(_ DeviceID, err error) {
func (t *TestModel) Closed(_ Connection, err error) {
t.closedErr = err
close(t.closedCh)
}
func (t *TestModel) ClusterConfig(deviceID DeviceID, config ClusterConfig) error {
func (t *TestModel) ClusterConfig(_ Connection, config ClusterConfig) error {
if t.ccFn != nil {
t.ccFn(deviceID, config)
t.ccFn(config)
}
return nil
}
func (*TestModel) DownloadProgress(DeviceID, string, []FileDownloadProgressUpdate) error {
func (*TestModel) DownloadProgress(Connection, string, []FileDownloadProgressUpdate) error {
return nil
}
+17 -17
View File
@@ -43,12 +43,12 @@ const (
// receives encrypted metadata and requests from the untrusted device, so it
// must decrypt those and answer requests by encrypting the data.
type encryptedModel struct {
model Model
model contextLessModel
folderKeys *folderKeyRegistry
keyGen *KeyGenerator
}
func newEncryptedModel(model Model, folderKeys *folderKeyRegistry, keyGen *KeyGenerator) encryptedModel {
func newEncryptedModel(model contextLessModel, folderKeys *folderKeyRegistry, keyGen *KeyGenerator) encryptedModel {
return encryptedModel{
model: model,
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 {
// incoming index data to be decrypted
if err := decryptFileInfos(e.keyGen, files, folderKey); err != nil {
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 {
// incoming index data to be decrypted
if err := decryptFileInfos(e.keyGen, files, folderKey); err != nil {
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)
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 /
@@ -120,7 +120,7 @@ func (e encryptedModel) Request(deviceID DeviceID, folder, name string, blockNo,
// 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 {
return nil, err
}
@@ -142,21 +142,21 @@ func (e encryptedModel) Request(deviceID DeviceID, folder, name string, blockNo,
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 {
return e.model.DownloadProgress(deviceID, folder, updates)
return e.model.DownloadProgress(folder, updates)
}
// Encrypted devices shouldn't send these - ignore them.
return nil
}
func (e encryptedModel) ClusterConfig(deviceID DeviceID, config ClusterConfig) error {
return e.model.ClusterConfig(deviceID, config)
func (e encryptedModel) ClusterConfig(config ClusterConfig) error {
return e.model.ClusterConfig(config)
}
func (e encryptedModel) Closed(device DeviceID, err error) {
e.model.Closed(device, err)
func (e encryptedModel) Closed(err error) {
e.model.Closed(err)
}
// 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)
}
func (e encryptedConnection) ID() DeviceID {
return e.conn.ID()
func (e encryptedConnection) DeviceID() DeviceID {
return e.conn.DeviceID()
}
func (e encryptedConnection) Index(ctx context.Context, folder string, files []FileInfo) error {
+65 -65
View File
@@ -41,6 +41,16 @@ type Connection struct {
cryptoReturnsOnCall map[int]struct {
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)
downloadProgressMutex sync.RWMutex
downloadProgressArgsForCall []struct {
@@ -58,16 +68,6 @@ type Connection struct {
establishedAtReturnsOnCall map[int]struct {
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
indexMutex sync.RWMutex
indexArgsForCall []struct {
@@ -368,6 +368,59 @@ func (fake *Connection) CryptoReturnsOnCall(i int, result1 string) {
}{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) {
var arg3Copy []protocol.FileDownloadProgressUpdate
if arg3 != nil {
@@ -460,59 +513,6 @@ func (fake *Connection) EstablishedAtReturnsOnCall(i int, result1 time.Time) {
}{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 {
var arg3Copy []protocol.FileInfo
if arg3 != nil {
@@ -1164,12 +1164,12 @@ func (fake *Connection) Invocations() map[string][][]interface{} {
defer fake.clusterConfigMutex.RUnlock()
fake.cryptoMutex.RLock()
defer fake.cryptoMutex.RUnlock()
fake.deviceIDMutex.RLock()
defer fake.deviceIDMutex.RUnlock()
fake.downloadProgressMutex.RLock()
defer fake.downloadProgressMutex.RUnlock()
fake.establishedAtMutex.RLock()
defer fake.establishedAtMutex.RUnlock()
fake.iDMutex.RLock()
defer fake.iDMutex.RUnlock()
fake.indexMutex.RLock()
defer fake.indexMutex.RUnlock()
fake.indexUpdateMutex.RLock()
+8 -8
View File
@@ -9,27 +9,27 @@ package protocol
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 {
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 {
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 {
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)
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)
}
+1 -1
View File
@@ -7,4 +7,4 @@ package protocol
// 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 }
+8 -8
View File
@@ -13,30 +13,30 @@ import (
"strings"
)
func makeNative(m Model) Model { return nativeModel{m} }
func makeNative(m contextLessModel) contextLessModel { return nativeModel{m} }
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)
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)
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, `\`) {
l.Warnf("Dropping request for %s, contains invalid path separator", name)
return nil, ErrNoSuchFile
}
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 {
+79 -29
View File
@@ -123,17 +123,28 @@ var (
type Model interface {
// 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
IndexUpdate(deviceID DeviceID, folder string, files []FileInfo) error
IndexUpdate(conn Connection, folder string, files []FileInfo) error
// 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
ClusterConfig(deviceID DeviceID, config ClusterConfig) error
ClusterConfig(conn Connection, config ClusterConfig) error
// 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
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 {
@@ -146,7 +157,7 @@ type Connection interface {
Start()
SetFolderPasswords(passwords map[string]string)
Close(err error)
ID() DeviceID
DeviceID() DeviceID
Index(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)
@@ -171,8 +182,8 @@ type ConnectionInfo interface {
type rawConnection struct {
ConnectionInfo
id DeviceID
receiver Model
deviceID DeviceID
model contextLessModel
startTime time.Time
cr *countingReader
@@ -229,10 +240,16 @@ const (
// Should not be modified in production code, just for testing.
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
// native path formats.
nm := makeNative(receiver)
nm := makeNative(cwm)
em := newEncryptedModel(nm, newFolderKeyRegistry(keyGen, passwords), keyGen)
// 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)
wc := wireFormatConnection{ec}
cwm.conn = 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}
cw := &countingWriter{Writer: writer}
return &rawConnection{
ConnectionInfo: connInfo,
id: deviceID,
receiver: receiver,
deviceID: deviceID,
model: receiver,
cr: cr,
cw: cw,
closer: closer,
@@ -295,8 +313,8 @@ func (c *rawConnection) Start() {
c.startTime = time.Now().Truncate(time.Second)
}
func (c *rawConnection) ID() DeviceID {
return c.id
func (c *rawConnection) DeviceID() DeviceID {
return c.deviceID
}
// 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) {
case *ClusterConfig:
err = c.receiver.ClusterConfig(c.id, *msg)
err = c.model.ClusterConfig(*msg)
case *Index:
err = c.handleIndex(*msg)
@@ -477,7 +495,7 @@ func (c *rawConnection) dispatcherLoop() (err error) {
c.handleResponse(*msg)
case *DownloadProgress:
err = c.receiver.DownloadProgress(c.id, msg.Folder, msg.Updates)
err = c.model.DownloadProgress(msg.Folder, msg.Updates)
}
if err != nil {
return newHandleError(err, msgContext)
@@ -579,13 +597,13 @@ func (c *rawConnection) readHeader(fourByteBuf []byte) (Header, error) {
}
func (c *rawConnection) handleIndex(im Index) error {
l.Debugf("Index(%v, %v, %d file)", c.id, im.Folder, len(im.Files))
return c.receiver.Index(c.id, im.Folder, im.Files)
l.Debugf("Index(%v, %v, %d file)", c.deviceID, im.Folder, len(im.Files))
return c.model.Index(im.Folder, im.Files)
}
func (c *rawConnection) handleIndexUpdate(im IndexUpdate) error {
l.Debugf("queueing IndexUpdate(%v, %v, %d files)", c.id, im.Folder, len(im.Files))
return c.receiver.IndexUpdate(c.id, im.Folder, im.Files)
l.Debugf("queueing IndexUpdate(%v, %v, %d files)", c.deviceID, im.Folder, len(im.Files))
return c.model.IndexUpdate(im.Folder, im.Files)
}
// 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) {
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 {
c.send(context.Background(), &Response{
ID: req.ID,
@@ -925,7 +943,7 @@ func (c *rawConnection) internalClose(err error) {
c.closeOnce.Do(func() {
l.Debugln("close due to", err)
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)
@@ -940,7 +958,7 @@ func (c *rawConnection) internalClose(err error) {
<-c.dispatcherLoopStopped
c.receiver.Closed(c.ID(), err)
c.model.Closed(err)
})
}
@@ -958,11 +976,11 @@ func (c *rawConnection) pingSender() {
case <-ticker.C:
d := time.Since(c.cw.Last())
if d < PingSendInterval/2 {
l.Debugln(c.id, "ping skipped after wr", d)
l.Debugln(c.deviceID, "ping skipped after wr", d)
continue
}
l.Debugln(c.id, "ping -> after", d)
l.Debugln(c.deviceID, "ping -> after", d)
c.ping()
case <-c.closed:
@@ -983,11 +1001,11 @@ func (c *rawConnection) pingReceiver() {
case <-ticker.C:
d := time.Since(c.cr.Last())
if d > ReceiveTimeout {
l.Debugln(c.id, "ping timeout", d)
l.Debugln(c.deviceID, "ping timeout", d)
c.internalClose(ErrTimeout)
}
l.Debugln(c.id, "last read within", d)
l.Debugln(c.deviceID, "last read within", d)
case <-c.closed:
return
@@ -1068,3 +1086,35 @@ func messageContext(msg message) (string, error) {
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)
}
+2 -2
View File
@@ -145,7 +145,7 @@ func TestCloseRace(t *testing.T) {
indexReceived := make(chan struct{})
unblockIndex := make(chan struct{})
m0 := newTestModel()
m0.indexFn = func(_ DeviceID, _ string, _ []FileInfo) {
m0.indexFn = func(string, []FileInfo) {
close(indexReceived)
<-unblockIndex
}
@@ -924,7 +924,7 @@ func TestDispatcherToCloseDeadlock(t *testing.T) {
m := newTestModel()
rw := testutils.NewBlockingRW()
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.Start()