iop/apps/client/lib/control_plane_status_repository.dart
toki 672b4cdb5d refactor(bridge): 실행 경계 선행 안정화를 반영한다
원격 터미널 브리지 POC 전에 Client HTTP lifecycle과 Edge run result surface 계약을 고정해야 하므로 관련 구현, 테스트, 로드맵 상태를 함께 정리한다.
2026-06-07 08:40:36 +09:00

132 lines
4.3 KiB
Dart

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'control_plane_status_dto.dart';
abstract class ControlPlaneStatusRepository {
Future<List<EdgeRegistryView>> fetchEdges();
Future<EdgeStatusResponseView> fetchEdgeStatus(String edgeId);
Future<List<EdgeNodeEventView>> fetchEdgeEvents(String edgeId);
Future<FleetStatusResponseView> fetchFleetStatus();
Future<EdgeOperationsResponseView> fetchEdgeOperations(String edgeId);
Future<EdgeCommandResponseView> sendEdgeCommand(
String edgeId,
String operation, {
String? targetSelector,
Map<String, String>? parameters,
});
}
class HttpControlPlaneStatusRepository implements ControlPlaneStatusRepository {
final String baseUrl;
final http.Client _client;
final bool _ownsClient;
HttpControlPlaneStatusRepository({required this.baseUrl, http.Client? client})
: _client = client ?? http.Client(),
_ownsClient = client == null;
http.Client get _httpClient => _client;
void close() {
if (_ownsClient) {
_client.close();
}
}
@override
Future<List<EdgeRegistryView>> fetchEdges() async {
final response = await _httpClient.get(Uri.parse('$baseUrl/edges'));
if (response.statusCode != 200) {
throw Exception('Failed to fetch edges: ${response.statusCode}');
}
final body = json.decode(response.body) as Map<String, dynamic>;
final list = body['edges'] as List? ?? [];
return list
.map((e) => EdgeRegistryView.fromJson(e as Map<String, dynamic>))
.toList();
}
@override
Future<EdgeStatusResponseView> fetchEdgeStatus(String edgeId) async {
final response = await _httpClient.get(
Uri.parse('$baseUrl/edges/$edgeId/status'),
);
if (response.statusCode != 200) {
throw Exception(
'Failed to fetch status for $edgeId: ${response.statusCode}',
);
}
final body = json.decode(response.body) as Map<String, dynamic>;
return EdgeStatusResponseView.fromJson(body);
}
@override
Future<List<EdgeNodeEventView>> fetchEdgeEvents(String edgeId) async {
final response = await _httpClient.get(
Uri.parse('$baseUrl/edges/$edgeId/events'),
);
if (response.statusCode != 200) {
throw Exception(
'Failed to fetch events for $edgeId: ${response.statusCode}',
);
}
final body = json.decode(response.body) as Map<String, dynamic>;
final list = body['events'] as List? ?? [];
return list
.map((e) => EdgeNodeEventView.fromJson(e as Map<String, dynamic>))
.toList();
}
@override
Future<FleetStatusResponseView> fetchFleetStatus() async {
final response = await _httpClient.get(Uri.parse('$baseUrl/fleet/status'));
if (response.statusCode != 200) {
throw Exception('Failed to fetch fleet status: ${response.statusCode}');
}
final body = json.decode(response.body) as Map<String, dynamic>;
return FleetStatusResponseView.fromJson(body);
}
@override
Future<EdgeOperationsResponseView> fetchEdgeOperations(String edgeId) async {
final response = await _httpClient.get(
Uri.parse('$baseUrl/edges/$edgeId/operations'),
);
if (response.statusCode != 200) {
throw Exception(
'Failed to fetch operations for $edgeId: ${response.statusCode}',
);
}
final body = json.decode(response.body) as Map<String, dynamic>;
return EdgeOperationsResponseView.fromJson(body);
}
@override
Future<EdgeCommandResponseView> sendEdgeCommand(
String edgeId,
String operation, {
String? targetSelector,
Map<String, String>? parameters,
}) async {
final Map<String, dynamic> requestBody = {'operation': operation};
if (targetSelector != null) {
requestBody['target_selector'] = targetSelector;
}
if (parameters != null) {
requestBody['parameters'] = parameters;
}
final response = await _httpClient.post(
Uri.parse('$baseUrl/edges/$edgeId/commands'),
headers: {'Content-Type': 'application/json'},
body: json.encode(requestBody),
);
if (response.statusCode != 200 && response.statusCode != 202) {
throw Exception(
'Failed to send command to $edgeId: ${response.statusCode}',
);
}
final body = json.decode(response.body) as Map<String, dynamic>;
return EdgeCommandResponseView.fromJson(body);
}
}