refactor(apps): 重构数据层目录结构并新增启动预热编排器
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
import '../../../../data/network/i_api_client.dart';
|
||||
import '../../../../data/cache/cache_policy.dart';
|
||||
import '../../../../data/cache/cached_repository.dart';
|
||||
import '../models/friend_request.dart';
|
||||
|
||||
abstract class FriendRepository {
|
||||
Future<List<FriendUser>> getFriends();
|
||||
Future<FriendRequest> getRequestById(String friendshipId);
|
||||
Future<Map<String, FriendRequest>> getRequestsByIds(
|
||||
List<String> friendshipIds,
|
||||
);
|
||||
Future<FriendRequest> acceptRequest(String friendshipId);
|
||||
Future<FriendRequest> declineRequest(String friendshipId);
|
||||
}
|
||||
|
||||
class FriendRepositoryImpl extends CachedRepository<List<FriendUser>>
|
||||
implements FriendRepository {
|
||||
final IApiClient _apiClient;
|
||||
static const _prefix = '/api/v1/friends';
|
||||
|
||||
FriendRepositoryImpl({required IApiClient apiClient, required super.store})
|
||||
: _apiClient = apiClient,
|
||||
super(
|
||||
policy: const CachePolicy(
|
||||
softTtl: Duration(seconds: 30),
|
||||
hardTtl: Duration(minutes: 5),
|
||||
minRefreshInterval: Duration(seconds: 15),
|
||||
),
|
||||
encodeValue: _encodeFriendUsers,
|
||||
decodeValue: _decodeFriendUsers,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<List<FriendUser>> getFriends() async {
|
||||
return getOrLoad(key: _friendsKey, loadFromRemote: _loadFriendsFromRemote);
|
||||
}
|
||||
|
||||
Future<List<FriendUser>> _loadFriendsFromRemote() async {
|
||||
final response = await _apiClient.get<List<dynamic>>(_prefix);
|
||||
final data = response.data;
|
||||
if (data == null) {
|
||||
throw StateError('Invalid getFriends response: empty payload');
|
||||
}
|
||||
return data
|
||||
.map((item) => item as Map<String, dynamic>)
|
||||
.map(
|
||||
(item) => FriendUser.fromJson(item['friend'] as Map<String, dynamic>),
|
||||
)
|
||||
.toList(growable: false);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<FriendRequest> getRequestById(String friendshipId) async {
|
||||
return _loadRequestById(friendshipId);
|
||||
}
|
||||
|
||||
Future<FriendRequest> _loadRequestById(String friendshipId) async {
|
||||
final response = await _apiClient.get<Map<String, dynamic>>(
|
||||
'$_prefix/requests/$friendshipId',
|
||||
);
|
||||
final data = response.data;
|
||||
if (data == null) {
|
||||
throw StateError('Invalid getRequestById response: empty payload');
|
||||
}
|
||||
return FriendRequest.fromJson(data);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, FriendRequest>> getRequestsByIds(
|
||||
List<String> friendshipIds,
|
||||
) async {
|
||||
if (friendshipIds.isEmpty) {
|
||||
return const <String, FriendRequest>{};
|
||||
}
|
||||
|
||||
final pairs = await Future.wait(
|
||||
friendshipIds.map((id) async {
|
||||
final request = await getRequestById(id);
|
||||
return MapEntry(id, request);
|
||||
}),
|
||||
);
|
||||
|
||||
return Map<String, FriendRequest>.fromEntries(pairs);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<FriendRequest> acceptRequest(String friendshipId) async {
|
||||
final response = await _apiClient.post<Map<String, dynamic>>(
|
||||
'$_prefix/requests/$friendshipId/accept',
|
||||
);
|
||||
final data = response.data;
|
||||
if (data == null) {
|
||||
throw StateError('Invalid acceptRequest response: empty payload');
|
||||
}
|
||||
final request = FriendRequest.fromJson(data);
|
||||
await _invalidateFriendCaches(friendshipId);
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<FriendRequest> declineRequest(String friendshipId) async {
|
||||
final response = await _apiClient.post<Map<String, dynamic>>(
|
||||
'$_prefix/requests/$friendshipId/decline',
|
||||
);
|
||||
final data = response.data;
|
||||
if (data == null) {
|
||||
throw StateError('Invalid declineRequest response: empty payload');
|
||||
}
|
||||
final request = FriendRequest.fromJson(data);
|
||||
await _invalidateFriendCaches(friendshipId);
|
||||
return request;
|
||||
}
|
||||
|
||||
Future<void> _invalidateFriendCaches(String friendshipId) {
|
||||
final _ = friendshipId;
|
||||
return removeCacheKey(_friendsKey);
|
||||
}
|
||||
|
||||
static const _friendsKey = 'friends:list';
|
||||
|
||||
static Object? _encodeFriendUsers(List<FriendUser> users) {
|
||||
return users.map(_encodeFriendUser).toList(growable: false);
|
||||
}
|
||||
|
||||
static List<FriendUser> _decodeFriendUsers(Object? raw) {
|
||||
if (raw is! List) {
|
||||
throw const FormatException('Invalid cached friend list payload');
|
||||
}
|
||||
return raw
|
||||
.whereType<Map>()
|
||||
.map((item) => FriendUser.fromJson(Map<String, dynamic>.from(item)))
|
||||
.toList(growable: false);
|
||||
}
|
||||
|
||||
static Map<String, Object?> _encodeFriendUser(FriendUser user) {
|
||||
return <String, Object?>{
|
||||
'id': user.id,
|
||||
'username': user.username,
|
||||
'avatar_url': user.avatarUrl,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import '../../../../data/network/i_api_client.dart';
|
||||
import '../models/user_summary.dart';
|
||||
|
||||
abstract class UserRepository {
|
||||
Future<UserSummary> getById(String userId);
|
||||
Future<UserSummary> getMe();
|
||||
}
|
||||
|
||||
class UserRepositoryImpl implements UserRepository {
|
||||
final IApiClient _apiClient;
|
||||
static const _prefix = '/api/v1/users';
|
||||
|
||||
UserRepositoryImpl(this._apiClient);
|
||||
|
||||
@override
|
||||
Future<UserSummary> getById(String userId) async {
|
||||
final response = await _apiClient.get<Map<String, dynamic>>(
|
||||
'$_prefix/$userId',
|
||||
);
|
||||
final user = response.data;
|
||||
if (user == null) {
|
||||
throw StateError('Invalid getById response: empty payload');
|
||||
}
|
||||
return UserSummary.fromJson(user);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UserSummary> getMe() async {
|
||||
final response = await _apiClient.get<Map<String, dynamic>>('$_prefix/me');
|
||||
final user = response.data;
|
||||
if (user == null) {
|
||||
throw StateError('Invalid getMe response: empty payload');
|
||||
}
|
||||
return UserSummary.fromJson(user);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import '../models/user_profile.dart';
|
||||
|
||||
abstract class UsersRepository {
|
||||
Future<UserProfile> getMe();
|
||||
Future<UserProfile> updateMe(UserUpdateRequest request);
|
||||
Future<List<UserProfile>> searchUsers(String query);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import '../apis/users_api.dart';
|
||||
import 'users_repository.dart';
|
||||
import '../models/user_profile.dart';
|
||||
|
||||
class UsersRepositoryImpl implements UsersRepository {
|
||||
final UsersApi _api;
|
||||
|
||||
UsersRepositoryImpl({required UsersApi api}) : _api = api;
|
||||
|
||||
@override
|
||||
Future<UserProfile> getMe() {
|
||||
return _api.getMe();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UserProfile> updateMe(UserUpdateRequest request) {
|
||||
return _api.updateMe(request);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<UserProfile>> searchUsers(String query) {
|
||||
return _api.searchUsers(query);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user