Skip to content

Commit

Permalink
Merge pull request #45 from bostrot/issue_44
Browse files Browse the repository at this point in the history
Issue 44 fix
  • Loading branch information
bostrot authored Jun 13, 2022
2 parents 212af33 + b971962 commit 4e694fd
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 172 deletions.
Binary file modified build/windows/runner/Release/data/app.so
Binary file not shown.
Binary file modified build/windows/runner/Release/desktop_window_plugin.dll
Binary file not shown.
Binary file modified build/windows/runner/Release/flutter_windows.dll
Binary file not shown.
Binary file modified build/windows/runner/Release/system_theme_plugin.dll
Binary file not shown.
Binary file modified build/windows/runner/Release/url_launcher_windows_plugin.dll
Binary file not shown.
Binary file modified build/windows/runner/Release/wsl2distromanager.exe
Binary file not shown.
Binary file modified build/windows/runner/Release/wsl2distromanager.msix
Binary file not shown.
82 changes: 26 additions & 56 deletions lib/components/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,17 @@ class App {
}
}

bool inited = false;

/// WSL API
class WSLApi {
WSLApi() {
if (!inited) {
inited = true;
App().getDistroLinks();
}
}

/// Get distro size
String? getSize(String distroName) {
String? distroLocation = prefs.getString('Path_$distroName');
Expand Down Expand Up @@ -439,7 +448,7 @@ class WSLApi {
/// @param filename: String
/// @return Future<String>
Future<dynamic> create(String distribution, String filename,
String installPath, Function(String) status, Function callback) async {
String installPath, Function(String) status) async {
if (installPath == '') {
installPath = defaultPath + distribution;
}
Expand All @@ -451,72 +460,33 @@ class WSLApi {
bool fileExists = await File(downloadPath).exists();
if (distroRootfsLinks[filename] != null && !fileExists) {
String url = distroRootfsLinks[filename]!;

// Download file
try {
// Download file as a stream
// List<List<int>> chunks = [];
int offset = 0;

var httpClient = http.Client();

// set buffer size to 10MB
var request = http.Request('GET', Uri.parse(url));
var response = httpClient.send(request);

// Open file
File file = File('$downloadPath.tmp');

response.asStream().listen((http.StreamedResponse r) async {
final reader = ChunkedStreamReader(r.stream);
int size = r.contentLength!;
try {
Uint8List buffer;
do {
buffer = await reader.readBytes(chunkSize);
// chunks.add(buffer);
offset += buffer.length;
status('${'downloading-text'.i18n()}: $filename, '
'(${offset ~/ 1024 ~/ 1024}MB'
' - ${(offset / size * 100).toStringAsFixed(0)}%)');
// Write buffer directly to disk and clear chunks
await file.writeAsBytes(buffer, mode: FileMode.append);
} while (buffer.length == chunkSize);

// Rename file
await file.rename(downloadPath);
status('${'downloaded-text'.i18n()}: $filename');

// Create
status('creatinginstance-text'.i18n());
ProcessResult results = await Process.run(
'wsl', ['--import', distribution, installPath, downloadPath],
stdoutEncoding: null);
callback(results);
} catch (e) {
status('${'errordownloading-text'.i18n()}: $filename: $e');
} finally {
reader.cancel();
}
Dio dio = Dio();
await dio.download(url, '$downloadPath.tmp',
onReceiveProgress: (int count, int total) {
status('Step 1: Downloading distro: '
'${(count / total * 100).toStringAsFixed(0)}%');
});
File file = File('$downloadPath.tmp');
file.rename(downloadPath);
status('${'downloaded-text'.i18n()} $filename');
} catch (error) {
status('${'errordownloading-text'.i18n()}: $filename: $error');
status('${'errordownloading-text'.i18n()} $filename');
}
}
// Downloaded or extracted; probably imported

// Downloaded or extracted
if (distroRootfsLinks[filename] == null) {
downloadPath = filename;
}

if (fileExists) {
// Create from local file
ProcessResult results = await Process.run(
'wsl', ['--import', distribution, installPath, downloadPath],
stdoutEncoding: null);
callback(results);
}
// Create from local file
ProcessResult results = await Process.run(
'wsl', ['--import', distribution, installPath, downloadPath],
stdoutEncoding: null);

return null;
return results;
}

/// Returns list of WSL distros
Expand Down
6 changes: 3 additions & 3 deletions lib/components/constants.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const String currentVersion = "1.3.2";
const String currentVersion = "1.3.3";
const String windowsStoreUrl = "https://www.microsoft.com/store/"
"productId/9NWS9K95NMJB";
const String defaultPath = 'C:\\WSL2-Distros\\';
const int chunkSize = 512 * 1024;
const int chunkSize = 16 * 1024;
const String updateUrl =
'https://api.github.com/repos/bostrot/wsl2-distro-manager/releases';

Expand All @@ -13,7 +13,7 @@ const String defaultRepoLink =
'http://ftp.halifax.rwth-aachen.de/turnkeylinux/images/proxmox/';

const String gitRepoLink =
'https://raw.githubusercontent.com/bostrot/wsl2-distro-manager/adjusted_repos/images.json';
'https://raw.githubusercontent.com/bostrot/wsl2-distro-manager/main/images.json';

// https://docs.microsoft.com/en-us/windows/wsl/install-on-server
Map<String, String> distroRootfsLinks = {
Expand Down
65 changes: 16 additions & 49 deletions lib/components/sync.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import 'dart:io';
import 'dart:typed_data';

import 'package:dio/dio.dart';
import 'package:localization/localization.dart';
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_static/shelf_static.dart';
import 'package:wsl2distromanager/components/api.dart';
import 'package:wsl2distromanager/components/constants.dart';
import 'helpers.dart';
import 'package:http/http.dart' as http;
import 'package:async/async.dart';

class Sync {
late Function(String, {bool loading}) statusMsg;
Expand Down Expand Up @@ -72,52 +68,23 @@ class Sync {
// Shutdown WSL
await WSLApi().shutdown();
statusMsg('${'connectingtoip-text'.i18n()}: "$syncIP"...', loading: true);

// Download file
try {
// Download file as a stream
int offset = 0;

var httpClient = http.Client();
// set buffer size to 10MB
var request =
http.Request('GET', Uri.parse('http://$syncIP:59132/ext4.vhdx'));
var response = httpClient.send(request);

// Open file
File file = File('$distroLocation\\ext4.vhdx.tmp');

response.asStream().listen((http.StreamedResponse r) async {
final reader = ChunkedStreamReader(r.stream);
int size = r.contentLength!;
try {
Uint8List buffer;
do {
buffer = await reader.readBytes(chunkSize);
offset += buffer.length;
statusMsg(
'${'downloading-text'.i18n()} $distroName, '
'(${offset ~/ 1024 ~/ 1024}MB'
' - ${(offset / size * 100).toStringAsFixed(0)}%)',
loading: true);
// Write buffer directly to disk and clear chunks
await file.writeAsBytes(buffer, mode: FileMode.append);
} while (buffer.length == chunkSize);

statusMsg('${'downloaded-text'.i18n()} $distroName');

// Rename file
await file.rename('$distroLocation\\ext4.vhdx');
} catch (e) {
statusMsg('${'errordownloading-text'.i18n()} $distroName',
loading: false);
} finally {
reader.cancel();
}
});
} catch (error) {
Dio().download(
'http://$syncIP:59132/ext4.vhdx', '$distroLocation\\ext4.vhdx.tmp',
onReceiveProgress: (received, total) {
String rec = (received / 1024 / 1024).toStringAsFixed(2);
String tot = (total / 1024 / 1024).toStringAsFixed(2);
statusMsg('${'downloading-text'.i18n()} $distroName, $rec MB / $tot MB',
loading: true);
if (received == total) {
statusMsg('${'downloaded-text'.i18n()} $distroName');
File oldFile = File('$distroLocation\\ext4.vhdx');
oldFile.rename('$distroLocation\\ext4.vhdx.old');
File file = File('$distroLocation\\ext4.vhdx.tmp');
file.rename('$distroLocation\\ext4.vhdx');
}
}).catchError((e) {
statusMsg('${'errordownloading-text'.i18n()} $distroName',
loading: false);
}
});
}
}
121 changes: 61 additions & 60 deletions lib/dialogs/create_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:io';

import 'package:localization/localization.dart';
import 'package:wsl2distromanager/components/analytics.dart';
import 'package:wsl2distromanager/components/api.dart';
Expand Down Expand Up @@ -81,76 +83,75 @@ Future<void> createInstance(
location += '/$name';
}
Navigator.of(context, rootNavigator: true).pop();
await api.create(
name, autoSuggestBox.text, location, (String msg) => statusMsg(msg),
(result) async {
if (result.exitCode != 0) {
statusMsg(WSLApi().utf8Convert(result.stdout));
} else {
String user = userController.text;
if (user != '') {
List<int> processes = await api.exec(name, [
'apt-get update',
'apt-get install -y sudo',
'useradd -m -s /bin/bash -G sudo $user',
'passwd $user',
'echo \'$user ALL=(ALL) NOPASSWD:ALL\' >> /etc/sudoers.d/wslsudo',
'echo -e \'[user]\ndefault = $user\' > /etc/wsl.conf',
]);
bool success = true;
for (dynamic process in processes) {
if (process != 0) {
success = false;
break;
}
}
if (success) {
prefs.setString('StartPath_$name', '/home/$user');
prefs.setString('StartUser_$name', user);
bool mounted = mountedFn();
if (!mounted) {
return;
}
ProcessResult result = await api.create(
name, autoSuggestBox.text, location, (String msg) => statusMsg(msg));

statusMsg('createdinstance-text'.i18n());
} else {
bool mounted = mountedFn();
if (!mounted) {
return;
}
statusMsg('createdinstancenouser-text'.i18n());
if (result.exitCode != 0) {
statusMsg(WSLApi().utf8Convert(result.stdout));
} else {
String user = userController.text;
if (user != '') {
List<int> processes = await api.exec(name, [
'apt-get update',
'apt-get install -y sudo',
'useradd -m -s /bin/bash -G sudo $user',
'passwd $user',
'echo \'$user ALL=(ALL) NOPASSWD:ALL\' >> /etc/sudoers.d/wslsudo',
'echo -e \'[user]\ndefault = $user\' > /etc/wsl.conf',
]);
bool success = true;
for (dynamic process in processes) {
if (process != 0) {
success = false;
break;
}
} else {
}
if (success) {
prefs.setString('StartPath_$name', '/home/$user');
prefs.setString('StartUser_$name', user);
bool mounted = mountedFn();
if (!mounted) {
return;
}

// Install fake systemctl
if (autoSuggestBox.text.contains('Turnkey')) {
// Set first start variable
prefs.setBool('TurnkeyFirstStart_$name', true);
statusMsg('installingfakesystemd-text'.i18n(), loading: true);
WSLApi().execCmds(
name,
[
'wget https://raw.githubusercontent.com/bostrot/'
'fake-systemd/master/systemctl -O /usr/bin/systemctl',
'chmod +x /usr/bin/systemctl',
'/usr/bin/systemctl',
],
onMsg: (output) => null,
onDone: () => statusMsg('createdinstance-text'.i18n()));
} else {
statusMsg('createdinstance-text'.i18n());
statusMsg('createdinstance-text'.i18n());
} else {
bool mounted = mountedFn();
if (!mounted) {
return;
}
statusMsg('createdinstancenouser-text'.i18n());
}
} else {
bool mounted = mountedFn();
if (!mounted) {
return;
}

// Install fake systemctl
if (autoSuggestBox.text.contains('Turnkey')) {
// Set first start variable
prefs.setBool('TurnkeyFirstStart_$name', true);
statusMsg('installingfakesystemd-text'.i18n(), loading: true);
WSLApi().execCmds(
name,
[
'wget https://raw.githubusercontent.com/bostrot/'
'fake-systemd/master/systemctl -O /usr/bin/systemctl',
'chmod +x /usr/bin/systemctl',
'/usr/bin/systemctl',
],
onMsg: (output) => null,
onDone: () => statusMsg('createdinstance-text'.i18n()));
} else {
statusMsg('createdinstance-text'.i18n());
}
// Save distro label
prefs.setString('DistroName_$name', label);
// Save distro path
prefs.setString('Path_$name', location);
}
});
// Save distro label
prefs.setString('DistroName_$name', label);
// Save distro path
prefs.setString('Path_$name', location);
}
// Download distro check
} else {
statusMsg('entername-text'.i18n());
Expand Down
8 changes: 5 additions & 3 deletions lib/screens/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,19 @@ class _MyHomePageState extends State<MyHomePage> {
void enableAnalytics() async {
String platform = Platform.operatingSystemVersion;
String exec = Platform.resolvedExecutable.toString();
if (exec.contains("9891PhantomDevs.WSL2Manager")) {
exec = "store";
} else {
exec = "git";
}
try {
List<String> tmpSplitted = exec.split('.');
exec = tmpSplitted[tmpSplitted.length - 1];
if (int.parse(platform.split('Build ')[1].split(')')[0]) >= 22000) {
platform = platform
.replaceAll('Windows 10', 'Windows 11')
.replaceAll('10.0', '11.0');
}
} catch (e) {
// Empty path
exec = '';
}

// Enable analytics
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: wsl2distromanager
description: A GUI to quickly manage your WSL instances.

publish_to: 'none'
version: 1.3.2 # Current version
version: 1.3.3 # Current version

environment:
sdk: ">=2.12.0 <3.0.0"
Expand Down

0 comments on commit 4e694fd

Please sign in to comment.