wip: Sicherungs-Commit aller Änderungen seit April + Arbeitsstruktur (CLAUDE.md, ROADMAP.md, PROGRESS.md, Autopilot)
6 Wochen uncommittete Arbeit (Voice-Channels, LiveKit-Manager, Settings-Modal u.v.m.) als ein WIP-Commit gesichert, damit nichts verloren geht und der Pi den aktuellen Stand klonen kann. Thematische Aufarbeitung: siehe ROADMAP M0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CPrAGBxBT6GfPXzeWQ4AXb
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class E2eeDiagEntry {
|
||||
final DateTime timestamp;
|
||||
final String roomId;
|
||||
final String eventId;
|
||||
final String sessionId;
|
||||
final String error;
|
||||
|
||||
const E2eeDiagEntry({
|
||||
required this.timestamp,
|
||||
required this.roomId,
|
||||
required this.eventId,
|
||||
required this.sessionId,
|
||||
required this.error,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'ts': timestamp.toIso8601String(),
|
||||
'room': roomId,
|
||||
'event': eventId,
|
||||
'session': sessionId,
|
||||
'error': error,
|
||||
};
|
||||
}
|
||||
|
||||
class E2eeDiagnosticsNotifier extends Notifier<List<E2eeDiagEntry>> {
|
||||
static const int _maxEntries = 500;
|
||||
|
||||
@override
|
||||
List<E2eeDiagEntry> build() => [];
|
||||
|
||||
void add(E2eeDiagEntry entry) {
|
||||
final next = [...state, entry];
|
||||
state = next.length > _maxEntries ? next.sublist(next.length - _maxEntries) : next;
|
||||
}
|
||||
|
||||
void clear() => state = [];
|
||||
|
||||
Future<String> upload({required String serverUrl, required String token}) async {
|
||||
if (state.isEmpty) return 'Keine Diagnosedaten vorhanden.';
|
||||
|
||||
final payload = utf8.encode(jsonEncode({
|
||||
'client': 'Pyramid',
|
||||
'uploaded_at': DateTime.now().toIso8601String(),
|
||||
'entry_count': state.length,
|
||||
'entries': state.map((e) => e.toJson()).toList(),
|
||||
}));
|
||||
|
||||
final client = HttpClient();
|
||||
try {
|
||||
final uri = Uri.parse('$serverUrl/api/e2ee-diagnostics');
|
||||
final request = await client.postUrl(uri);
|
||||
request.headers.set('Content-Type', 'application/json; charset=utf-8');
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
request.headers.contentLength = payload.length;
|
||||
request.add(payload);
|
||||
final response = await request.close();
|
||||
await response.drain<void>();
|
||||
if (response.statusCode == 200) {
|
||||
final count = state.length;
|
||||
clear();
|
||||
return '$count Einträge hochgeladen und lokal gelöscht.';
|
||||
}
|
||||
return 'Server-Fehler: HTTP ${response.statusCode}';
|
||||
} on SocketException catch (e) {
|
||||
return 'Netzwerkfehler: ${e.message}';
|
||||
} catch (e) {
|
||||
return 'Fehler: $e';
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final e2eeDiagnosticsProvider =
|
||||
NotifierProvider<E2eeDiagnosticsNotifier, List<E2eeDiagEntry>>(
|
||||
E2eeDiagnosticsNotifier.new,
|
||||
);
|
||||
Reference in New Issue
Block a user