[READ ONLY MIRROR] Open Source TikTok alternative built on AT Protocol github.com/sprksocial/client
flutter atproto video dart
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: video upload crashes

+56 -7
+56 -7
lib/src/core/network/atproto/data/repositories/feed_repository_impl.dart
··· 1209 1209 } 1210 1210 1211 1211 // Check if the video is in a compatible format 1212 - final videoSizeBytes = await file.length(); 1213 - if (videoSizeBytes == 0) { 1212 + // Use BigInt to avoid overflow for very large files (>2GB) 1213 + final videoSizeBigInt = BigInt.from(await file.length()); 1214 + if (videoSizeBigInt == BigInt.zero) { 1214 1215 throw Exception('Video file is empty'); 1215 1216 } 1216 1217 1218 + // Check for integer overflow (files > 2GB could overflow int on 32-bit) 1219 + if (videoSizeBigInt > BigInt.from(2 * 1024 * 1024 * 1024)) { 1220 + _logger.w( 1221 + 'Video file exceeds 2GB, may cause issues: $videoSizeBigInt bytes', 1222 + ); 1223 + throw VideoUploadException( 1224 + 'Video is too large. Maximum supported size is 2GB.', 1225 + statusCode: 413, 1226 + uploadSizeBytes: videoSizeBigInt.toInt(), 1227 + limitBytes: 2 * 1024 * 1024 * 1024, 1228 + ); 1229 + } 1230 + 1231 + final videoSizeBytes = videoSizeBigInt.toInt(); 1217 1232 _logger.i('Video file size: $videoSizeBytes bytes'); 1218 1233 final maxUploadSizeBytes = (AppConfig.maxUploadSizeMB * 1024 * 1024) 1219 1234 .round(); ··· 1227 1242 statusCode: 413, 1228 1243 uploadSizeBytes: videoSizeBytes, 1229 1244 limitBytes: maxUploadSizeBytes, 1245 + ); 1246 + } 1247 + 1248 + // Validate content length will fit in HTTP header (max ~2GB for int32) 1249 + if (videoSizeBytes > 2147483647) { 1250 + _logger.e('Video file too large for HTTP content-length header'); 1251 + throw VideoUploadException( 1252 + 'Video is too large to upload.', 1253 + statusCode: 413, 1254 + uploadSizeBytes: videoSizeBytes, 1255 + limitBytes: 2147483647, 1230 1256 ); 1231 1257 } 1232 1258 ··· 1293 1319 // Poll job status until it finishes (handles both QUEUED and PROCESSING) 1294 1320 var jobState = responseData['jobStatus']?['state'] as String?; 1295 1321 var attempts = 0; 1322 + var consecutivePollErrors = 0; 1296 1323 const maxAttempts = 120; // ~4 minutes at 2s interval 1324 + const maxConsecutivePollErrors = 3; // Allow 3 consecutive polling errors 1297 1325 while (jobState == 'JOB_STATE_QUEUED' || 1298 1326 jobState == 'JOB_STATE_PROCESSING') { 1299 1327 _logger.d('Video upload in progress, status: $jobState'); ··· 1325 1353 responseData = jsonDecode(response.body); 1326 1354 _logger.d('Video upload status response: $responseData'); 1327 1355 jobState = responseData['jobStatus']?['state'] as String?; 1356 + // Reset consecutive errors on success 1357 + consecutivePollErrors = 0; 1328 1358 } catch (e) { 1329 - // Network or parsing error during polling - log and rethrow 1330 - _logger.e( 1331 - 'Error polling video upload status on attempt $attempts/$maxAttempts', 1332 - error: e, 1359 + // Network or parsing error during polling - log and retry 1360 + consecutivePollErrors++; 1361 + _logger.w( 1362 + 'Error polling video upload status on attempt ' 1363 + '$attempts/$maxAttempts ' 1364 + '(consecutive errors: $consecutivePollErrors/$maxConsecutivePollErrors): ' 1365 + '$e', 1333 1366 ); 1334 - rethrow; 1367 + 1368 + // Only fail if we've had too many consecutive errors 1369 + if (consecutivePollErrors >= maxConsecutivePollErrors) { 1370 + _logger.e( 1371 + 'Too many consecutive polling errors, giving up: $e', 1372 + error: e, 1373 + ); 1374 + throw Exception( 1375 + 'Failed to check video upload status after ' 1376 + '$maxConsecutivePollErrors attempts: $e', 1377 + ); 1378 + } 1379 + 1380 + // Continue polling on transient errors 1381 + _logger.d('Retrying poll after error...'); 1382 + jobState = 1383 + 'JOB_STATE_PROCESSING'; // Assume still processing and retry 1335 1384 } 1336 1385 } 1337 1386