iop/apps/client/lib/control_plane_status_client.dart

487 lines
15 KiB
Dart

import 'dart:convert';
import 'package:http/http.dart' as http;
class EdgeRegistryView {
final String edgeId;
final String edgeName;
final String version;
final List<String> capabilities;
final String protocol;
final bool connected;
final DateTime lastSeen;
EdgeRegistryView({
required this.edgeId,
required this.edgeName,
required this.version,
required this.capabilities,
required this.protocol,
required this.connected,
required this.lastSeen,
});
factory EdgeRegistryView.fromJson(Map<String, dynamic> json) {
return EdgeRegistryView(
edgeId: json['edge_id'] as String? ?? '',
edgeName: json['edge_name'] as String? ?? '',
version: json['version'] as String? ?? '',
capabilities: List<String>.from(json['capabilities'] ?? []),
protocol: json['protocol'] as String? ?? '',
connected: json['connected'] as bool? ?? false,
lastSeen: json['last_seen'] != null
? DateTime.parse(json['last_seen'] as String)
: DateTime.now(),
);
}
}
class AdapterSummaryView {
final String type;
final bool enabled;
AdapterSummaryView({required this.type, required this.enabled});
factory AdapterSummaryView.fromJson(Map<String, dynamic> json) {
return AdapterSummaryView(
type: json['type'] as String? ?? '',
enabled: json['enabled'] as bool? ?? false,
);
}
}
class NodeConfigSummaryView {
final List<AdapterSummaryView> adapters;
final int concurrency;
NodeConfigSummaryView({required this.adapters, required this.concurrency});
factory NodeConfigSummaryView.fromJson(Map<String, dynamic> json) {
return NodeConfigSummaryView(
adapters: (json['adapters'] as List? ?? [])
.map((e) => AdapterSummaryView.fromJson(e as Map<String, dynamic>))
.toList(),
concurrency: json['concurrency'] as int? ?? 0,
);
}
}
class EdgeNodeSnapshotView {
final String nodeId;
final String alias;
final String label;
final bool connected;
final NodeConfigSummaryView? config;
EdgeNodeSnapshotView({
required this.nodeId,
required this.alias,
required this.label,
required this.connected,
this.config,
});
factory EdgeNodeSnapshotView.fromJson(Map<String, dynamic> json) {
return EdgeNodeSnapshotView(
nodeId: json['node_id'] as String? ?? '',
alias: json['alias'] as String? ?? '',
label: json['label'] as String? ?? '',
connected: json['connected'] as bool? ?? false,
config: json['config'] != null
? NodeConfigSummaryView.fromJson(json['config'] as Map<String, dynamic>)
: null,
);
}
}
class EdgeCapabilitySummaryView {
final String kind;
final bool available;
final String status;
final String summary;
EdgeCapabilitySummaryView({
required this.kind,
required this.available,
required this.status,
required this.summary,
});
factory EdgeCapabilitySummaryView.fromJson(Map<String, dynamic> json) {
return EdgeCapabilitySummaryView(
kind: json['kind'] as String? ?? '',
available: json['available'] as bool? ?? false,
status: json['status'] as String? ?? '',
summary: json['summary'] as String? ?? '',
);
}
}
class EdgeDomainAgentSummaryView {
final String agentKind;
final bool available;
final String lifecycleState;
final String activeCommandId;
final String summary;
EdgeDomainAgentSummaryView({
required this.agentKind,
required this.available,
required this.lifecycleState,
required this.activeCommandId,
required this.summary,
});
factory EdgeDomainAgentSummaryView.fromJson(Map<String, dynamic> json) {
return EdgeDomainAgentSummaryView(
agentKind: json['agent_kind'] as String? ?? '',
available: json['available'] as bool? ?? false,
lifecycleState: json['lifecycle_state'] as String? ?? '',
activeCommandId: json['active_command_id'] as String? ?? '',
summary: json['summary'] as String? ?? '',
);
}
}
class EdgeStatusResponseView {
final String requestId;
final String edgeId;
final String edgeName;
final int observedTimeUnixNano;
final List<EdgeNodeSnapshotView> nodes;
final List<EdgeCapabilitySummaryView> capabilities;
final List<EdgeDomainAgentSummaryView> domainAgents;
final Map<String, String> metadata;
final String error;
EdgeStatusResponseView({
required this.requestId,
required this.edgeId,
required this.edgeName,
required this.observedTimeUnixNano,
required this.nodes,
required this.capabilities,
required this.domainAgents,
required this.metadata,
required this.error,
});
factory EdgeStatusResponseView.fromJson(Map<String, dynamic> json) {
return EdgeStatusResponseView(
requestId: json['request_id'] as String? ?? '',
edgeId: json['edge_id'] as String? ?? '',
edgeName: json['edge_name'] as String? ?? '',
observedTimeUnixNano: json['observed_time_unix_nano'] as int? ?? 0,
nodes: (json['nodes'] as List? ?? [])
.map((e) => EdgeNodeSnapshotView.fromJson(e as Map<String, dynamic>))
.toList(),
capabilities: (json['capabilities'] as List? ?? [])
.map((e) => EdgeCapabilitySummaryView.fromJson(e as Map<String, dynamic>))
.toList(),
domainAgents: (json['domain_agents'] as List? ?? [])
.map((e) => EdgeDomainAgentSummaryView.fromJson(e as Map<String, dynamic>))
.toList(),
metadata: Map<String, String>.from(json['metadata'] ?? {}),
error: json['error'] as String? ?? '',
);
}
}
class EdgeNodeEventView {
final String edgeId;
final String eventId;
final String type;
final String source;
final String nodeId;
final String alias;
final String reason;
final DateTime timestamp;
final DateTime receivedAt;
final Map<String, String> metadata;
EdgeNodeEventView({
required this.edgeId,
required this.eventId,
required this.type,
required this.source,
required this.nodeId,
required this.alias,
required this.reason,
required this.timestamp,
required this.receivedAt,
required this.metadata,
});
factory EdgeNodeEventView.fromJson(Map<String, dynamic> json) {
return EdgeNodeEventView(
edgeId: json['edge_id'] as String? ?? '',
eventId: json['event_id'] as String? ?? '',
type: json['type'] as String? ?? '',
source: json['source'] as String? ?? '',
nodeId: json['node_id'] as String? ?? '',
alias: json['alias'] as String? ?? '',
reason: json['reason'] as String? ?? '',
timestamp: json['timestamp'] != null
? DateTime.parse(json['timestamp'] as String)
: DateTime.now(),
receivedAt: json['received_at'] != null
? DateTime.parse(json['received_at'] as String)
: DateTime.now(),
metadata: Map<String, String>.from(json['metadata'] ?? {}),
);
}
}
class FleetEdgeView {
final String edgeId;
final String edgeName;
final String version;
final String protocol;
final bool connected;
final String health;
final DateTime lastSeen;
final int nodeCount;
final List<EdgeCapabilitySummaryView> capabilities;
final List<EdgeDomainAgentSummaryView> domainAgents;
final String error;
FleetEdgeView({
required this.edgeId,
required this.edgeName,
required this.version,
required this.protocol,
required this.connected,
required this.health,
required this.lastSeen,
required this.nodeCount,
required this.capabilities,
required this.domainAgents,
required this.error,
});
factory FleetEdgeView.fromJson(Map<String, dynamic> json) {
return FleetEdgeView(
edgeId: json['edge_id'] as String? ?? '',
edgeName: json['edge_name'] as String? ?? '',
version: json['version'] as String? ?? '',
protocol: json['protocol'] as String? ?? '',
connected: json['connected'] as bool? ?? false,
health: json['health'] as String? ?? '',
lastSeen: json['last_seen'] != null
? DateTime.parse(json['last_seen'] as String)
: DateTime.now(),
nodeCount: json['node_count'] as int? ?? 0,
capabilities: (json['capabilities'] as List? ?? [])
.map((e) => EdgeCapabilitySummaryView.fromJson(e as Map<String, dynamic>))
.toList(),
domainAgents: (json['domain_agents'] as List? ?? [])
.map((e) => EdgeDomainAgentSummaryView.fromJson(e as Map<String, dynamic>))
.toList(),
error: json['error'] as String? ?? '',
);
}
}
class FleetStatusResponseView {
final DateTime generatedAt;
final List<FleetEdgeView> edges;
FleetStatusResponseView({
required this.generatedAt,
required this.edges,
});
factory FleetStatusResponseView.fromJson(Map<String, dynamic> json) {
return FleetStatusResponseView(
generatedAt: json['generated_at'] != null
? DateTime.parse(json['generated_at'] as String)
: DateTime.now(),
edges: (json['edges'] as List? ?? [])
.map((e) => FleetEdgeView.fromJson(e as Map<String, dynamic>))
.toList(),
);
}
}
class EdgeCommandRecordView {
final String edgeId;
final String commandId;
final String operation;
final String targetSelector;
final String status;
final String summary;
final String error;
EdgeCommandRecordView({
required this.edgeId,
required this.commandId,
required this.operation,
required this.targetSelector,
required this.status,
required this.summary,
required this.error,
});
factory EdgeCommandRecordView.fromJson(Map<String, dynamic> json) {
return EdgeCommandRecordView(
edgeId: json['edge_id'] as String? ?? '',
commandId: json['command_id'] as String? ?? '',
operation: json['operation'] as String? ?? '',
targetSelector: json['target_selector'] as String? ?? '',
status: json['status'] as String? ?? '',
summary: json['summary'] as String? ?? '',
error: json['error'] as String? ?? '',
);
}
}
class EdgeOperationsResponseView {
final String edgeId;
final List<EdgeCommandRecordView> operations;
EdgeOperationsResponseView({
required this.edgeId,
required this.operations,
});
factory EdgeOperationsResponseView.fromJson(Map<String, dynamic> json) {
return EdgeOperationsResponseView(
edgeId: json['edge_id'] as String? ?? '',
operations: (json['operations'] as List? ?? [])
.map((e) => EdgeCommandRecordView.fromJson(e as Map<String, dynamic>))
.toList(),
);
}
}
class EdgeCommandResponseView {
final String requestId;
final String commandId;
final String edgeId;
final String status;
final String summary;
final String error;
EdgeCommandResponseView({
required this.requestId,
required this.commandId,
required this.edgeId,
required this.status,
required this.summary,
required this.error,
});
factory EdgeCommandResponseView.fromJson(Map<String, dynamic> json) {
return EdgeCommandResponseView(
requestId: json['request_id'] as String? ?? '',
commandId: json['command_id'] as String? ?? '',
edgeId: json['edge_id'] as String? ?? '',
status: json['status'] as String? ?? '',
summary: json['summary'] as String? ?? '',
error: json['error'] as String? ?? '',
);
}
}
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);
}
}