Skip to content

Commit 5b46187

Browse files
minor updates
1 parent df60759 commit 5b46187

2 files changed

Lines changed: 31 additions & 16 deletions

File tree

sdk/runanywhere-flutter/packages/runanywhere/lib/infrastructure/download/download_service.dart

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import 'dart:async';
22
import 'dart:io';
33

4-
import 'package:archive/archive_io.dart';
54
import 'package:http/http.dart' as http;
65
import 'package:path/path.dart' as p;
76
import 'package:runanywhere/core/types/model_types.dart';
@@ -323,39 +322,57 @@ class ModelDownloadService {
323322
return Directory(modelPath);
324323
}
325324

326-
/// Extract an archive to the destination using streaming to avoid OOM on large files
325+
/// Extract an archive using the system `tar`/`unzip` command.
326+
/// This runs in a separate process (non-blocking) and is orders of magnitude
327+
/// faster than the pure-Dart `archive` package for large model files (1GB+).
328+
/// Android has `tar` via toybox since API 23 (min SDK 24).
327329
Future<String> _extractArchive(
328330
String archivePath,
329331
String destDir,
330332
ModelArtifactType artifactType,
331333
) async {
332334
_logger.info('Extracting archive: $archivePath');
333335

334-
final supported = archivePath.endsWith('.tar.gz') ||
335-
archivePath.endsWith('.tgz') ||
336-
archivePath.endsWith('.tar.bz2') ||
337-
archivePath.endsWith('.tbz2') ||
338-
archivePath.endsWith('.zip') ||
339-
archivePath.endsWith('.tar');
340-
341-
if (!supported) {
336+
final List<String> args;
337+
338+
if (archivePath.endsWith('.tar.gz') || archivePath.endsWith('.tgz')) {
339+
args = ['-xzf', archivePath, '-C', destDir];
340+
} else if (archivePath.endsWith('.tar.bz2') ||
341+
archivePath.endsWith('.tbz2')) {
342+
args = ['-xjf', archivePath, '-C', destDir];
343+
} else if (archivePath.endsWith('.tar')) {
344+
args = ['-xf', archivePath, '-C', destDir];
345+
} else if (archivePath.endsWith('.zip')) {
346+
// Use unzip for .zip files
347+
final result = await Process.run('unzip', ['-o', archivePath, '-d', destDir]);
348+
if (result.exitCode != 0) {
349+
throw Exception('unzip failed (exit ${result.exitCode}): ${result.stderr}');
350+
}
351+
_logger.info('Extraction complete: $destDir');
352+
return _resolveExtractedDir(destDir);
353+
} else {
342354
_logger.warning('Unknown archive format: $archivePath');
343355
return archivePath;
344356
}
345357

346-
// Use streaming extraction — reads file in chunks, never loads entire archive into RAM
347-
await extractFileToDisk(archivePath, destDir);
358+
// Run tar extraction — runs as a separate OS process, does not block the Dart event loop
359+
final result = await Process.run('tar', args);
360+
if (result.exitCode != 0) {
361+
throw Exception('tar failed (exit ${result.exitCode}): ${result.stderr}');
362+
}
348363

349364
_logger.info('Extraction complete: $destDir');
365+
return _resolveExtractedDir(destDir);
366+
}
350367

351-
// Return the nested root directory if one exists inside destDir
368+
/// If extraction produced a single subdirectory, return that path instead.
369+
Future<String> _resolveExtractedDir(String destDir) async {
352370
final destDirectory = Directory(destDir);
353371
final entries = await destDirectory.list().toList();
354372
final subdirs = entries.whereType<Directory>().toList();
355373
if (subdirs.length == 1) {
356374
return subdirs.first.path;
357375
}
358-
359376
return destDir;
360377
}
361378

sdk/runanywhere-flutter/packages/runanywhere/pubspec.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ dependencies:
3636
collection: ^1.18.0
3737
json_annotation: ^4.9.0
3838
path: ^1.9.0
39-
# Archive extraction (tar.bz2, zip)
40-
archive: ^3.6.1
4139
# TTS fallback (system TTS)
4240
flutter_tts: ^3.8.0
4341
# Audio recording for voice sessions

0 commit comments

Comments
 (0)