mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-10 07:11:08 +00:00
4d979a1ce9
This truncates times meant for API consumption to second precision, where fractions won't typically matter or add any value. Exception to this is timestamps on logs and events, and of course I'm not touching things like file metadata. I'm not 100% certain this is an exhaustive change, but it's the things I found by grepping and following the breadcrumbs from lib/api... I also considered general-but-ugly solutions, like having the API serializer itself do reflection magic or even regexps on returned objects, but decided against it because aurgh...
210 lines
6.4 KiB
Go
210 lines
6.4 KiB
Go
// 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 (
|
|
"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{
|
|
Time: time.Now().Truncate(time.Second),
|
|
Name: name,
|
|
Address: address,
|
|
}
|
|
bs, err := od.Marshal()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return db.Put(key, bs)
|
|
}
|
|
|
|
func (db *Lowlevel) RemovePendingDevice(device protocol.DeviceID) {
|
|
key := db.keyer.GeneratePendingDeviceKey(nil, device[:])
|
|
if err := db.Delete(key); err != nil {
|
|
l.Warnf("Failed to remove pending device entry: %v", err)
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
func (db *Lowlevel) AddOrUpdatePendingFolder(id, label string, device protocol.DeviceID, receiveEncrypted bool) error {
|
|
key, err := db.keyer.GeneratePendingFolderKey(nil, device[:], []byte(id))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
of := ObservedFolder{
|
|
Time: time.Now().Truncate(time.Second),
|
|
Label: label,
|
|
ReceiveEncrypted: receiveEncrypted,
|
|
}
|
|
bs, err := of.Marshal()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return db.Put(key, bs)
|
|
}
|
|
|
|
// RemovePendingFolderForDevice removes entries for specific folder / device combinations.
|
|
func (db *Lowlevel) RemovePendingFolderForDevice(id string, device protocol.DeviceID) {
|
|
key, err := db.keyer.GeneratePendingFolderKey(nil, device[:], []byte(id))
|
|
if err != nil {
|
|
return
|
|
}
|
|
if err := db.Delete(key); err != nil {
|
|
l.Warnf("Failed to remove pending folder entry: %v", err)
|
|
}
|
|
}
|
|
|
|
// RemovePendingFolder removes all entries matching a specific folder ID.
|
|
func (db *Lowlevel) RemovePendingFolder(id string) {
|
|
iter, err := db.NewPrefixIterator([]byte{KeyTypePendingFolder})
|
|
if err != nil {
|
|
l.Infof("Could not iterate through pending folder entries: %v", err)
|
|
return
|
|
}
|
|
defer iter.Release()
|
|
for iter.Next() {
|
|
if id != string(db.keyer.FolderFromPendingFolderKey(iter.Key())) {
|
|
continue
|
|
}
|
|
if err := db.Delete(iter.Key()); err != nil {
|
|
l.Warnf("Failed to remove pending folder entry: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// RemovePendingFoldersBeforeTime removes entries for a specific device which are older
|
|
// than a given timestamp or invalid. It returns only the valid removed folder IDs.
|
|
func (db *Lowlevel) RemovePendingFoldersBeforeTime(device protocol.DeviceID, oldest time.Time) ([]string, error) {
|
|
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()
|
|
oldest = oldest.Round(time.Second)
|
|
var res []string
|
|
for iter.Next() {
|
|
var of ObservedFolder
|
|
var folderID string
|
|
if err = of.Unmarshal(iter.Value()); err != nil {
|
|
l.Infof("Invalid pending folder entry, deleting from database: %x", iter.Key())
|
|
} else if of.Time.Before(oldest) {
|
|
folderID = string(db.keyer.FolderFromPendingFolderKey(iter.Key()))
|
|
l.Infof("Removing stale pending folder %s (%s) from device %s, last seen %v",
|
|
folderID, of.Label, device.Short(), of.Time)
|
|
} else {
|
|
// Keep entries younger or equal to the given timestamp
|
|
continue
|
|
}
|
|
if err := db.Delete(iter.Key()); err != nil {
|
|
l.Warnf("Failed to remove pending folder entry: %v", err)
|
|
} else if len(folderID) > 0 {
|
|
res = append(res, folderID)
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
// 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
|
|
// is EmptyDeviceID. Invalid ones are dropped from the database after a warning log
|
|
// 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
|
|
}
|