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_
|