- Move fleet polling logic to control orchestrator - Split client state management into separate controller/repository - Add client bootstrap and home page components - Update HTTP fleet handlers and views - Add unit tests for client bootstrap and status controller - Archive completed subtask documents
107 lines
4 KiB
Dart
107 lines
4 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;
|
|
|
|
HttpControlPlaneStatusRepository({required this.baseUrl, this.client});
|
|
|
|
http.Client get _httpClient => client ?? http.Client();
|
|
|
|
@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);
|
|
}
|
|
}
|