observed.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // Copyright (C) 2020 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package db
  7. import (
  8. "fmt"
  9. "time"
  10. "google.golang.org/protobuf/proto"
  11. "google.golang.org/protobuf/types/known/timestamppb"
  12. "github.com/syncthing/syncthing/internal/gen/dbproto"
  13. "github.com/syncthing/syncthing/lib/protocol"
  14. )
  15. type ObservedFolder struct {
  16. Time time.Time `json:"time"`
  17. Label string `json:"label"`
  18. ReceiveEncrypted bool `json:"receiveEncrypted"`
  19. RemoteEncrypted bool `json:"remoteEncrypted"`
  20. }
  21. func (o *ObservedFolder) toWire() *dbproto.ObservedFolder {
  22. return &dbproto.ObservedFolder{
  23. Time: timestamppb.New(o.Time),
  24. Label: o.Label,
  25. ReceiveEncrypted: o.ReceiveEncrypted,
  26. RemoteEncrypted: o.RemoteEncrypted,
  27. }
  28. }
  29. func (o *ObservedFolder) fromWire(w *dbproto.ObservedFolder) {
  30. o.Time = w.GetTime().AsTime()
  31. o.Label = w.GetLabel()
  32. o.ReceiveEncrypted = w.GetReceiveEncrypted()
  33. o.RemoteEncrypted = w.GetRemoteEncrypted()
  34. }
  35. type ObservedDevice struct {
  36. Time time.Time `json:"time"`
  37. Name string `json:"name"`
  38. Address string `json:"address"`
  39. }
  40. func (o *ObservedDevice) fromWire(w *dbproto.ObservedDevice) {
  41. o.Time = w.GetTime().AsTime()
  42. o.Name = w.GetName()
  43. o.Address = w.GetAddress()
  44. }
  45. func (db *Lowlevel) AddOrUpdatePendingDevice(device protocol.DeviceID, name, address string) error {
  46. key := db.keyer.GeneratePendingDeviceKey(nil, device[:])
  47. od := &dbproto.ObservedDevice{
  48. Time: timestamppb.New(time.Now().Truncate(time.Second)),
  49. Name: name,
  50. Address: address,
  51. }
  52. return db.Put(key, mustMarshal(od))
  53. }
  54. func (db *Lowlevel) RemovePendingDevice(device protocol.DeviceID) error {
  55. key := db.keyer.GeneratePendingDeviceKey(nil, device[:])
  56. return db.Delete(key)
  57. }
  58. // PendingDevices enumerates all entries. Invalid ones are dropped from the database
  59. // after a warning log message, as a side-effect.
  60. func (db *Lowlevel) PendingDevices() (map[protocol.DeviceID]ObservedDevice, error) {
  61. iter, err := db.NewPrefixIterator([]byte{KeyTypePendingDevice})
  62. if err != nil {
  63. return nil, err
  64. }
  65. defer iter.Release()
  66. res := make(map[protocol.DeviceID]ObservedDevice)
  67. for iter.Next() {
  68. keyDev := db.keyer.DeviceFromPendingDeviceKey(iter.Key())
  69. deviceID, err := protocol.DeviceIDFromBytes(keyDev)
  70. var protoD dbproto.ObservedDevice
  71. var od ObservedDevice
  72. if err != nil {
  73. goto deleteKey
  74. }
  75. if err = proto.Unmarshal(iter.Value(), &protoD); err != nil {
  76. goto deleteKey
  77. }
  78. od.fromWire(&protoD)
  79. res[deviceID] = od
  80. continue
  81. deleteKey:
  82. // Deleting invalid entries is the only possible "repair" measure and
  83. // appropriate for the importance of pending entries. They will come back
  84. // soon if still relevant.
  85. l.Infof("Invalid pending device entry, deleting from database: %x", iter.Key())
  86. if err := db.Delete(iter.Key()); err != nil {
  87. return nil, err
  88. }
  89. }
  90. return res, nil
  91. }
  92. func (db *Lowlevel) AddOrUpdatePendingFolder(id string, of ObservedFolder, device protocol.DeviceID) error {
  93. key, err := db.keyer.GeneratePendingFolderKey(nil, device[:], []byte(id))
  94. if err != nil {
  95. return err
  96. }
  97. return db.Put(key, mustMarshal(of.toWire()))
  98. }
  99. // RemovePendingFolderForDevice removes entries for specific folder / device combinations.
  100. func (db *Lowlevel) RemovePendingFolderForDevice(id string, device protocol.DeviceID) error {
  101. key, err := db.keyer.GeneratePendingFolderKey(nil, device[:], []byte(id))
  102. if err != nil {
  103. return err
  104. }
  105. return db.Delete(key)
  106. }
  107. // RemovePendingFolder removes all entries matching a specific folder ID.
  108. func (db *Lowlevel) RemovePendingFolder(id string) error {
  109. iter, err := db.NewPrefixIterator([]byte{KeyTypePendingFolder})
  110. if err != nil {
  111. return fmt.Errorf("creating iterator: %w", err)
  112. }
  113. defer iter.Release()
  114. var iterErr error
  115. for iter.Next() {
  116. if id != string(db.keyer.FolderFromPendingFolderKey(iter.Key())) {
  117. continue
  118. }
  119. if err = db.Delete(iter.Key()); err != nil {
  120. if iterErr != nil {
  121. l.Debugf("Repeat error removing pending folder: %v", err)
  122. } else {
  123. iterErr = err
  124. }
  125. }
  126. }
  127. return iterErr
  128. }
  129. // Consolidated information about a pending folder
  130. type PendingFolder struct {
  131. OfferedBy map[protocol.DeviceID]ObservedFolder `json:"offeredBy"`
  132. }
  133. func (db *Lowlevel) PendingFolders() (map[string]PendingFolder, error) {
  134. return db.PendingFoldersForDevice(protocol.EmptyDeviceID)
  135. }
  136. // PendingFoldersForDevice enumerates only entries matching the given device ID, unless it
  137. // is EmptyDeviceID. Invalid ones are dropped from the database after a info log
  138. // message, as a side-effect.
  139. func (db *Lowlevel) PendingFoldersForDevice(device protocol.DeviceID) (map[string]PendingFolder, error) {
  140. var err error
  141. prefixKey := []byte{KeyTypePendingFolder}
  142. if device != protocol.EmptyDeviceID {
  143. prefixKey, err = db.keyer.GeneratePendingFolderKey(nil, device[:], nil)
  144. if err != nil {
  145. return nil, err
  146. }
  147. }
  148. iter, err := db.NewPrefixIterator(prefixKey)
  149. if err != nil {
  150. return nil, err
  151. }
  152. defer iter.Release()
  153. res := make(map[string]PendingFolder)
  154. for iter.Next() {
  155. keyDev, ok := db.keyer.DeviceFromPendingFolderKey(iter.Key())
  156. deviceID, err := protocol.DeviceIDFromBytes(keyDev)
  157. var protoF dbproto.ObservedFolder
  158. var of ObservedFolder
  159. var folderID string
  160. if !ok || err != nil {
  161. goto deleteKey
  162. }
  163. if folderID = string(db.keyer.FolderFromPendingFolderKey(iter.Key())); len(folderID) < 1 {
  164. goto deleteKey
  165. }
  166. if err = proto.Unmarshal(iter.Value(), &protoF); err != nil {
  167. goto deleteKey
  168. }
  169. if _, ok := res[folderID]; !ok {
  170. res[folderID] = PendingFolder{
  171. OfferedBy: map[protocol.DeviceID]ObservedFolder{},
  172. }
  173. }
  174. of.fromWire(&protoF)
  175. res[folderID].OfferedBy[deviceID] = of
  176. continue
  177. deleteKey:
  178. // Deleting invalid entries is the only possible "repair" measure and
  179. // appropriate for the importance of pending entries. They will come back
  180. // soon if still relevant.
  181. l.Infof("Invalid pending folder entry, deleting from database: %x", iter.Key())
  182. if err := db.Delete(iter.Key()); err != nil {
  183. return nil, err
  184. }
  185. }
  186. return res, nil
  187. }