refactor(apps): 重构数据层目录结构并新增启动预热编排器

This commit is contained in:
zl-q
2026-03-29 20:26:30 +08:00
parent 33340de8f9
commit 4db9a13bfe
108 changed files with 1653 additions and 1320 deletions
@@ -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);
}
}