v2.38 — Issue #2: Dauerverbindung Cloud Server (persistenter http.Client)

- CloudService: static final http.Client _client als Instanzvariable
- Alle http.get/post/put/delete/upload nutzen nun _client statt neuem Client
- DownloadService: gleicher Fix für _retryHttpPost und _retryHttpGet
Build: ✓ flutter analyze
This commit is contained in:
Dustin
2026-08-02 15:56:22 +02:00
parent 6ed416c8b1
commit 0fc383daba
2 changed files with 20 additions and 16 deletions
+16 -14
View File
@@ -8,6 +8,8 @@ import '../services/melo_logger.dart';
/// Cloud-Sync Service für Melo Registry (v3 — vollständiges Sync-System) /// Cloud-Sync Service für Melo Registry (v3 — vollständiges Sync-System)
/// Authentifizierung via Baka-Auth JWT-Token /// Authentifizierung via Baka-Auth JWT-Token
class CloudService { class CloudService {
static final http.Client _client = http.Client();
static String get _base => AppConfig.cloudUrl; static String get _base => AppConfig.cloudUrl;
String _user = ''; String _user = '';
@@ -15,7 +17,7 @@ class CloudService {
Future<bool> login(String user) async { Future<bool> login(String user) async {
_user = user; _user = user;
try { try {
final r = await http final r = await _client
.get(Uri.parse('$_base/api/cloud/status'), .get(Uri.parse('$_base/api/cloud/status'),
headers: _authHeader) headers: _authHeader)
.timeout(const Duration(seconds: 5)); .timeout(const Duration(seconds: 5));
@@ -63,7 +65,7 @@ class CloudService {
req.files.add( req.files.add(
await http.MultipartFile.fromPath('file', filepath, await http.MultipartFile.fromPath('file', filepath,
filename: filename)); filename: filename));
final resp = await req.send().timeout(const Duration(seconds: 120)); final resp = await _client.send(req).timeout(const Duration(seconds: 120));
final body = jsonDecode(await resp.stream.bytesToString()); final body = jsonDecode(await resp.stream.bytesToString());
return body['song_id'] as String?; return body['song_id'] as String?;
} catch (e) { } catch (e) {
@@ -74,7 +76,7 @@ class CloudService {
Future<bool> download(String songId, String destPath) async { Future<bool> download(String songId, String destPath) async {
try { try {
final r = await http final r = await _client
.get(Uri.parse('$_base/api/cloud/download/$songId'), .get(Uri.parse('$_base/api/cloud/download/$songId'),
headers: _authHeader) headers: _authHeader)
.timeout(const Duration(seconds: 120)); .timeout(const Duration(seconds: 120));
@@ -91,7 +93,7 @@ class CloudService {
Future<bool> delete(String songId) async { Future<bool> delete(String songId) async {
try { try {
final r = await http final r = await _client
.post(Uri.parse('$_base/api/cloud/delete'), .post(Uri.parse('$_base/api/cloud/delete'),
headers: _jsonHeader, headers: _jsonHeader,
body: jsonEncode({'song_id': songId})) body: jsonEncode({'song_id': songId}))
@@ -105,7 +107,7 @@ class CloudService {
/// Sync-Änderungen seit einem Zeitstempel abrufen /// Sync-Änderungen seit einem Zeitstempel abrufen
Future<List<Map>> syncChanges(String since) async { Future<List<Map>> syncChanges(String since) async {
try { try {
final r = await http final r = await _client
.post(Uri.parse('$_base/api/cloud/sync'), .post(Uri.parse('$_base/api/cloud/sync'),
headers: _jsonHeader, headers: _jsonHeader,
body: jsonEncode({'since': since})) body: jsonEncode({'since': since}))
@@ -153,7 +155,7 @@ class CloudService {
/// Song aus Playlist entfernen /// Song aus Playlist entfernen
Future<bool> removeSongFromPlaylist(int playlistId, String songId) async { Future<bool> removeSongFromPlaylist(int playlistId, String songId) async {
try { try {
final r = await http final r = await _client
.delete( .delete(
Uri.parse( Uri.parse(
'$_base/api/cloud/playlists/$playlistId/songs/$songId'), '$_base/api/cloud/playlists/$playlistId/songs/$songId'),
@@ -169,7 +171,7 @@ class CloudService {
Future<bool> updatePlaylistPositions( Future<bool> updatePlaylistPositions(
int playlistId, List<Map<String, dynamic>> positions) async { int playlistId, List<Map<String, dynamic>> positions) async {
try { try {
final r = await http final r = await _client
.put( .put(
Uri.parse( Uri.parse(
'$_base/api/cloud/playlists/$playlistId/positions'), '$_base/api/cloud/playlists/$playlistId/positions'),
@@ -231,7 +233,7 @@ class CloudService {
Future<List<Map>> globalList() async { Future<List<Map>> globalList() async {
try { try {
final r = await http final r = await _client
.get(Uri.parse('$_base/api/cloud/global'), headers: _authHeader) .get(Uri.parse('$_base/api/cloud/global'), headers: _authHeader)
.timeout(const Duration(seconds: 10)); .timeout(const Duration(seconds: 10));
if (r.statusCode == 200) { if (r.statusCode == 200) {
@@ -243,7 +245,7 @@ class CloudService {
Future<bool> toggleGlobal(String songId) async { Future<bool> toggleGlobal(String songId) async {
try { try {
final r = await http final r = await _client
.post(Uri.parse('$_base/api/cloud/toggle-global'), .post(Uri.parse('$_base/api/cloud/toggle-global'),
headers: _jsonHeader, headers: _jsonHeader,
body: jsonEncode({'song_id': songId})) body: jsonEncode({'song_id': songId}))
@@ -256,7 +258,7 @@ class CloudService {
Future<String?> share(List<String> songIds) async { Future<String?> share(List<String> songIds) async {
try { try {
final r = await http final r = await _client
.post(Uri.parse('$_base/api/cloud/share'), .post(Uri.parse('$_base/api/cloud/share'),
headers: _jsonHeader, headers: _jsonHeader,
body: jsonEncode({'song_ids': songIds})) body: jsonEncode({'song_ids': songIds}))
@@ -271,7 +273,7 @@ class CloudService {
Future<Map?> importCode(String code) async { Future<Map?> importCode(String code) async {
try { try {
final r = await http final r = await _client
.post(Uri.parse('$_base/api/cloud/import'), .post(Uri.parse('$_base/api/cloud/import'),
headers: _jsonHeader, headers: _jsonHeader,
body: jsonEncode({'code': code})) body: jsonEncode({'code': code}))
@@ -283,7 +285,7 @@ class CloudService {
Future<List<Map>> getCorrupted() async { Future<List<Map>> getCorrupted() async {
try { try {
final r = await http final r = await _client
.get(Uri.parse('$_base/api/cloud/corrupted'), headers: _authHeader) .get(Uri.parse('$_base/api/cloud/corrupted'), headers: _authHeader)
.timeout(const Duration(seconds: 15)); .timeout(const Duration(seconds: 15));
if (r.statusCode == 200) { if (r.statusCode == 200) {
@@ -300,7 +302,7 @@ class CloudService {
Future<Map?> _get(String path) async { Future<Map?> _get(String path) async {
try { try {
final r = await http final r = await _client
.get(Uri.parse('$_base$path'), headers: _authHeader) .get(Uri.parse('$_base$path'), headers: _authHeader)
.timeout(const Duration(seconds: 10)); .timeout(const Duration(seconds: 10));
if (r.statusCode == 200) return jsonDecode(r.body); if (r.statusCode == 200) return jsonDecode(r.body);
@@ -313,7 +315,7 @@ class CloudService {
Future<Map?> _post(String path, Map<String, dynamic> body) async { Future<Map?> _post(String path, Map<String, dynamic> body) async {
try { try {
final r = await http final r = await _client
.post(Uri.parse('$_base$path'), .post(Uri.parse('$_base$path'),
headers: _jsonHeader, body: jsonEncode(body)) headers: _jsonHeader, body: jsonEncode(body))
.timeout(const Duration(seconds: 10)); .timeout(const Duration(seconds: 10));
+4 -2
View File
@@ -13,6 +13,8 @@ import '../config/app_config.dart';
/// Download-Service: Lädt YouTube-Audio über den yt-proxy herunter. /// Download-Service: Lädt YouTube-Audio über den yt-proxy herunter.
/// Nutzt ChangeNotifier für UI-Updates via ListenableBuilder. /// Nutzt ChangeNotifier für UI-Updates via ListenableBuilder.
class DownloadService extends ChangeNotifier { class DownloadService extends ChangeNotifier {
static final http.Client _client = http.Client();
static final DownloadService _instanz = DownloadService._(); static final DownloadService _instanz = DownloadService._();
factory DownloadService() => _instanz; factory DownloadService() => _instanz;
DownloadService._(); DownloadService._();
@@ -349,7 +351,7 @@ class DownloadService extends ChangeNotifier {
Object? lastError; Object? lastError;
for (int versuch = 0; versuch < maxVersuche; versuch++) { for (int versuch = 0; versuch < maxVersuche; versuch++) {
try { try {
final response = await http final response = await _client
.post(url, headers: headers, body: body) .post(url, headers: headers, body: body)
.timeout(timeout); .timeout(timeout);
return response; return response;
@@ -386,7 +388,7 @@ class DownloadService extends ChangeNotifier {
Object? lastError; Object? lastError;
for (int versuch = 0; versuch < maxVersuche; versuch++) { for (int versuch = 0; versuch < maxVersuche; versuch++) {
try { try {
final response = await http final response = await _client
.get(url, headers: headers) .get(url, headers: headers)
.timeout(timeout); .timeout(timeout);
return response; return response;