487 lines
15 KiB
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);
|
|
}
|
|
}
|