2020-12-17 18:54:31 +00:00
|
|
|
// Copyright (C) 2020 The Syncthing Authors.
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
package db
|
|
|
|
|
|
|
|
import (
|
2021-06-09 11:35:17 +00:00
|
|
|
"fmt"
|
2020-12-17 18:54:31 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/syncthing/syncthing/lib/protocol"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (db *Lowlevel) AddOrUpdatePendingDevice(device protocol.DeviceID, name, address string) error {
|
|
|
|
key := db.keyer.GeneratePendingDeviceKey(nil, device[:])
|
|
|
|
od := ObservedDevice{
|
2021-03-12 09:35:10 +00:00
|
|
|
Time: time.Now().Truncate(time.Second),
|
2020-12-17 18:54:31 +00:00
|
|
|
Name: name,
|
|
|
|
Address: address,
|
|
|
|
}
|
|
|
|
bs, err := od.Marshal()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return db.Put(key, bs)
|
|
|
|
}
|
|
|
|
|
2021-06-07 08:29:24 +00:00
|
|
|
func (db *Lowlevel) RemovePendingDevice(device protocol.DeviceID) error {
|
2020-12-17 18:54:31 +00:00
|
|
|
key := db.keyer.GeneratePendingDeviceKey(nil, device[:])
|
2021-06-09 11:35:17 +00:00
|
|
|
return db.Delete(key)
|
2020-12-17 18:54:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PendingDevices enumerates all entries. Invalid ones are dropped from the database
|
|
|
|
// after a warning log message, as a side-effect.
|
|
|
|
func (db *Lowlevel) PendingDevices() (map[protocol.DeviceID]ObservedDevice, error) {
|
|
|
|
iter, err := db.NewPrefixIterator([]byte{KeyTypePendingDevice})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer iter.Release()
|
|
|
|
res := make(map[protocol.DeviceID]ObservedDevice)
|
|
|
|
for iter.Next() {
|
|
|
|
keyDev := db.keyer.DeviceFromPendingDeviceKey(iter.Key())
|
|
|
|
deviceID, err := protocol.DeviceIDFromBytes(keyDev)
|
|
|
|
var od ObservedDevice
|
|
|
|
if err != nil {
|
|
|
|
goto deleteKey
|
|
|
|
}
|
|
|
|
if err = od.Unmarshal(iter.Value()); err != nil {
|
|
|
|
goto deleteKey
|
|
|
|
}
|
|
|
|
res[deviceID] = od
|
|
|
|
continue
|
|
|
|
deleteKey:
|
|
|
|
// Deleting invalid entries is the only possible "repair" measure and
|
|
|
|
// appropriate for the importance of pending entries. They will come back
|
|
|
|
// soon if still relevant.
|
|
|
|
l.Infof("Invalid pending device entry, deleting from database: %x", iter.Key())
|
|
|
|
if err := db.Delete(iter.Key()); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res, nil
|
|
|
|
}
|
|
|
|
|
2021-04-11 13:24:08 +00:00
|
|
|
func (db *Lowlevel) AddOrUpdatePendingFolder(id string, of ObservedFolder, device protocol.DeviceID) error {
|
2020-12-17 18:54:31 +00:00
|
|
|
key, err := db.keyer.GeneratePendingFolderKey(nil, device[:], []byte(id))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
bs, err := of.Marshal()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return db.Put(key, bs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemovePendingFolderForDevice removes entries for specific folder / device combinations.
|
2021-06-07 08:29:24 +00:00
|
|
|
func (db *Lowlevel) RemovePendingFolderForDevice(id string, device protocol.DeviceID) error {
|
2020-12-17 18:54:31 +00:00
|
|
|
key, err := db.keyer.GeneratePendingFolderKey(nil, device[:], []byte(id))
|
|
|
|
if err != nil {
|
2021-06-07 08:29:24 +00:00
|
|
|
return err
|
2020-12-17 18:54:31 +00:00
|
|
|
}
|
2021-06-09 11:35:17 +00:00
|
|
|
return db.Delete(key)
|
2020-12-17 18:54:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// RemovePendingFolder removes all entries matching a specific folder ID.
|
2021-06-07 08:29:24 +00:00
|
|
|
func (db *Lowlevel) RemovePendingFolder(id string) error {
|
2020-12-17 18:54:31 +00:00
|
|
|
iter, err := db.NewPrefixIterator([]byte{KeyTypePendingFolder})
|
|
|
|
if err != nil {
|
2021-06-09 11:35:17 +00:00
|
|
|
return fmt.Errorf("creating iterator: %w", err)
|
2020-12-17 18:54:31 +00:00
|
|
|
}
|
|
|
|
defer iter.Release()
|
2021-06-09 11:35:17 +00:00
|
|
|
var iterErr error
|
2020-12-17 18:54:31 +00:00
|
|
|
for iter.Next() {
|
|
|
|
if id != string(db.keyer.FolderFromPendingFolderKey(iter.Key())) {
|
|
|
|
continue
|
|
|
|
}
|
2021-06-07 08:29:24 +00:00
|
|
|
if err = db.Delete(iter.Key()); err != nil {
|
2021-06-09 11:35:17 +00:00
|
|
|
if iterErr != nil {
|
|
|
|
l.Debugf("Repeat error removing pending folder: %v", err)
|
|
|
|
} else {
|
|
|
|
iterErr = err
|
|
|
|
}
|
2020-12-17 18:54:31 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-09 11:35:17 +00:00
|
|
|
return iterErr
|
2020-12-17 18:54:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Consolidated information about a pending folder
|
|
|
|
type PendingFolder struct {
|
|
|
|
OfferedBy map[protocol.DeviceID]ObservedFolder `json:"offeredBy"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *Lowlevel) PendingFolders() (map[string]PendingFolder, error) {
|
|
|
|
return db.PendingFoldersForDevice(protocol.EmptyDeviceID)
|
|
|
|
}
|
|
|
|
|
|
|
|
// PendingFoldersForDevice enumerates only entries matching the given device ID, unless it
|
2021-06-09 11:35:17 +00:00
|
|
|
// is EmptyDeviceID. Invalid ones are dropped from the database after a info log
|
2020-12-17 18:54:31 +00:00
|
|
|
// message, as a side-effect.
|
|
|
|
func (db *Lowlevel) PendingFoldersForDevice(device protocol.DeviceID) (map[string]PendingFolder, error) {
|
|
|
|
var err error
|
|
|
|
prefixKey := []byte{KeyTypePendingFolder}
|
|
|
|
if device != protocol.EmptyDeviceID {
|
|
|
|
prefixKey, err = db.keyer.GeneratePendingFolderKey(nil, device[:], nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
iter, err := db.NewPrefixIterator(prefixKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer iter.Release()
|
|
|
|
res := make(map[string]PendingFolder)
|
|
|
|
for iter.Next() {
|
|
|
|
keyDev, ok := db.keyer.DeviceFromPendingFolderKey(iter.Key())
|
|
|
|
deviceID, err := protocol.DeviceIDFromBytes(keyDev)
|
|
|
|
var of ObservedFolder
|
|
|
|
var folderID string
|
|
|
|
if !ok || err != nil {
|
|
|
|
goto deleteKey
|
|
|
|
}
|
|
|
|
if folderID = string(db.keyer.FolderFromPendingFolderKey(iter.Key())); len(folderID) < 1 {
|
|
|
|
goto deleteKey
|
|
|
|
}
|
|
|
|
if err = of.Unmarshal(iter.Value()); err != nil {
|
|
|
|
goto deleteKey
|
|
|
|
}
|
|
|
|
if _, ok := res[folderID]; !ok {
|
|
|
|
res[folderID] = PendingFolder{
|
|
|
|
OfferedBy: map[protocol.DeviceID]ObservedFolder{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res[folderID].OfferedBy[deviceID] = of
|
|
|
|
continue
|
|
|
|
deleteKey:
|
|
|
|
// Deleting invalid entries is the only possible "repair" measure and
|
|
|
|
// appropriate for the importance of pending entries. They will come back
|
|
|
|
// soon if still relevant.
|
|
|
|
l.Infof("Invalid pending folder entry, deleting from database: %x", iter.Key())
|
|
|
|
if err := db.Delete(iter.Key()); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res, nil
|
|
|
|
}
|