File: group_data_model.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (161 lines) | stat: -rw-r--r-- 6,746 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_DATA_SHARING_INTERNAL_GROUP_DATA_MODEL_H_
#define COMPONENTS_DATA_SHARING_INTERNAL_GROUP_DATA_MODEL_H_

#include <vector>

#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/time/time.h"
#include "components/data_sharing/internal/collaboration_group_sync_bridge.h"
#include "components/data_sharing/internal/group_data_store.h"
#include "components/data_sharing/public/data_sharing_sdk_delegate.h"
#include "components/data_sharing/public/group_data.h"
#include "components/data_sharing/public/protocol/data_sharing_sdk.pb.h"

class GaiaId;

namespace data_sharing {

// This class manages GroupData and ensures it is synchronized:
// * Provides in-memory and persistent storage for GroupData by incapsulating
// database that stores known GroupData.
// * Observes changes in CollaborationGroupSyncBridge and reflects them in
// cache/DB, retrieving data from SDK when needed.
class GroupDataModel : public CollaborationGroupSyncBridge::Observer {
 public:
  class Observer : public base::CheckedObserver {
   public:
    Observer() = default;
    ~Observer() override = default;

    // Indicates that data is loaded from the disk, it can still be stale
    // though. GetGroup() / GetAllGroups() returns no data prior to this call.
    virtual void OnModelLoaded() = 0;

    virtual void OnGroupAdded(const GroupId& group_id,
                              const base::Time& event_time) = 0;
    virtual void OnGroupUpdated(const GroupId& group_id,
                                const base::Time& event_time) = 0;
    virtual void OnGroupDeleted(const GroupId& group_id,
                                const std::optional<GroupData>& group_data,
                                const base::Time& event_time) = 0;

    virtual void OnMemberAdded(const GroupId& group_id,
                               const GaiaId& member_gaia_id,
                               const base::Time& event_time) = 0;
    virtual void OnMemberRemoved(const GroupId& group_id,
                                 const GaiaId& member_gaia_id,
                                 const base::Time& event_time) = 0;
    virtual void OnSyncBridgeUpdateTypeChanged(
        SyncBridgeUpdateType sync_bridge_update_type) = 0;
  };

  // `collaboration_group_sync_bridge` and `sdk_delegate` must not be null and
  // must outlive `this`.
  GroupDataModel(const base::FilePath& data_sharing_dir,
                 CollaborationGroupSyncBridge* collaboration_group_sync_bridge,
                 DataSharingSDKDelegate* sdk_delegate);
  ~GroupDataModel() override;

  GroupDataModel(const GroupDataModel&) = delete;
  GroupDataModel& operator=(const GroupDataModel&) = delete;
  GroupDataModel(GroupDataModel&&) = delete;
  GroupDataModel& operator=(GroupDataModel&&) = delete;

  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  // Indicates whether data is loaded from the disk, it can still be stale
  // though. GetGroup() / GetAllGroups() returns no data prior as long as it is
  // set to false.
  bool IsModelLoaded() const;

  // Returns nullopt if the group is not (yet) stored locally or doesn't exist.
  std::optional<GroupData> GetGroup(const GroupId& group_id) const;
  // Groups are ordered by id.
  std::set<GroupData> GetAllGroups() const;
  // Returns nullopt if no data about the member is found.
  std::optional<GroupMemberPartialData> GetPossiblyRemovedGroupMember(
      const GroupId& group_id,
      const GaiaId& member_gaia_id) const;
  std::vector<GroupEvent> GetGroupEventsSinceStartup() const;

  // CollaborationGroupSyncBridge::Observer implementation.
  void OnGroupsUpdated(const std::vector<GroupId>& added_group_ids,
                       const std::vector<GroupId>& updated_group_ids,
                       const std::vector<GroupId>& deleted_group_ids) override;
  void OnCollaborationGroupSyncDataLoaded() override;
  void OnSyncBridgeUpdateTypeChanged(
      SyncBridgeUpdateType sync_bridge_update_type) override;

  GroupDataStore& GetGroupDataStoreForTesting();
  void SetGroupDataStoreLoadedCallbackForTesting(
      base::OnceClosure db_loaded_callback);

 private:
  void OnGroupDataStoreLoaded(GroupDataStore::DBInitStatus status);

  // Handles all known group changes, i.e. when data stored in
  // `group_data_store_` is different from data in
  // `collaboration_group_sync_bridge_`.
  void ProcessGroupChanges(bool is_initial_load);

  void DoPeriodicPollingAndScheduleNext();
  void ScheduleNextPeriodicPolling();

  // Asynchronously fetches data from the SDK.
  void FetchGroupsFromSDK(const std::vector<GroupId>& added_or_updated_groups);
  void OnBatchOfGroupsFetchedFromSDK(
      const std::map<GroupId, VersionToken>& requested_groups_and_versions,
      const base::Time& requested_at_timestamp,
      const base::expected<data_sharing_pb::ReadGroupsResult, absl::Status>&
          read_groups_result);
  void FetchBatchOfGroupsFromSDK(const std::vector<GroupId>& batch);
  void HandleBatchCompletion();

  void NotifyObserversAboutChangedMembers(const GroupData& old_group_data,
                                          const GroupData& new_group_data);
  void MaybeRecordGroupEvent(
      const GroupId& group_id,
      GroupEvent::EventType event_type,
      base::Time event_time,
      std::optional<GaiaId> affected_member_gaia_id = std::nullopt);

  GroupDataStore group_data_store_;
  bool is_group_data_store_loaded_ = false;
  bool is_collaboration_group_bridge_loaded_ = false;
  // TODO(crbug.com/370897286): Add test coverage for the scenarios addressed
  // by the following two fields: when there is a race condition between two
  // consecutive fetches (see crrev.com/c/5965993).
  bool has_ongoing_group_fetch_ = false;
  bool has_pending_changes_ = false;

  // Keeps track of the number of ReadGroups requests are currently in-flight.
  int outstanding_batches_ = 0;

  std::vector<GroupEvent> group_events_since_startup_;

  raw_ptr<CollaborationGroupSyncBridge> collaboration_group_sync_bridge_;
  raw_ptr<DataSharingSDKDelegate> sdk_delegate_;

  // Used only for tests to notify that GroupDataStore has been loaded (either
  // successfully or unsuccessfully).
  base::OnceClosure db_loaded_callback_;

  base::OneShotTimer next_periodic_polling_timer_;

  base::ObserverList<Observer> observers_;

  base::WeakPtrFactory<GroupDataModel> weak_ptr_factory_{this};
};

}  // namespace data_sharing

#endif  // COMPONENTS_DATA_SHARING_INTERNAL_GROUP_DATA_MODEL_H_