376 lines
11 KiB
Dart
376 lines
11 KiB
Dart
import 'dart:io';
|
|
import 'dart:async';
|
|
|
|
import 'package:path/path.dart' as path;
|
|
import 'package:dart_framework/core/process.dart';
|
|
|
|
class OSStartup {
|
|
static _Startup? _instance;
|
|
static _Startup? get _current {
|
|
if (_instance == null) {
|
|
if (Platform.isMacOS) {
|
|
_instance = _StartupMac();
|
|
} else if (Platform.isLinux) {
|
|
_instance = _StartupLinux();
|
|
} else {
|
|
_instance = _StartupWindows();
|
|
}
|
|
}
|
|
return _instance;
|
|
}
|
|
|
|
static Future<bool> isRegistedStartup(String label) async {
|
|
return _current!.isRegistedStartup(label);
|
|
}
|
|
|
|
//shell file must have '#!/bin/sh'
|
|
static Future<bool> registStartup(String executableFilePath, String label,
|
|
{List<String>? arguments,
|
|
String? logStandardFilePath,
|
|
String? logErrorFilePath}) async {
|
|
return _current!.registStartup(executableFilePath, label,
|
|
arguments: arguments,
|
|
logStandardFilePath: logStandardFilePath,
|
|
logErrorFilePath: logErrorFilePath);
|
|
}
|
|
|
|
static Future<bool> unregistStartup(String label) async {
|
|
return _current!.unregistStartup(label);
|
|
}
|
|
}
|
|
|
|
class _Startup {
|
|
Future<bool> isRegistedStartup(String label) async {
|
|
var c = Completer<bool>();
|
|
return c.future;
|
|
}
|
|
|
|
//shell file must have '#!/bin/sh'
|
|
Future<bool> registStartup(String executableFilePath, String label,
|
|
{List<String>? arguments,
|
|
String? logStandardFilePath,
|
|
String? logErrorFilePath}) async {
|
|
var c = Completer<bool>();
|
|
return c.future;
|
|
}
|
|
|
|
Future<bool> unregistStartup(String label) async {
|
|
var c = Completer<bool>();
|
|
return c.future;
|
|
}
|
|
}
|
|
|
|
class _StartupMac extends _Startup {
|
|
final plistTemplate = """<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>KeepAlive</key>
|
|
<false/>
|
|
<key>Label</key>
|
|
<string>{LABEL}</string>
|
|
<key>ProgramArguments</key>
|
|
<array>
|
|
<string>{FILE_PATH}</string>{PARAMETERS}
|
|
</array>
|
|
<key>RunAtLoad</key>
|
|
<true/>{LOG_STANDARD}{LOG_ERROR}
|
|
</dict>
|
|
</plist>""";
|
|
|
|
final logStandardTemplate = """
|
|
|
|
<key>StandardOutPath</key>
|
|
<string>{LOG_STANDARD}</string>""";
|
|
final logErrorTemplate = """
|
|
|
|
<key>StandardErrorPath</key>
|
|
<string>{LOG_ERROR}</string>""";
|
|
|
|
@override
|
|
Future<bool> isRegistedStartup(String label) async {
|
|
var c = Completer<bool>();
|
|
var plistName = '$label.plist';
|
|
var userPath = Platform.environment['HOME'] as String;
|
|
c.complete(
|
|
await File('$userPath/Library/LaunchAgents/$plistName').exists());
|
|
return c.future;
|
|
}
|
|
|
|
//shell file must have '#!/bin/sh'
|
|
@override
|
|
Future<bool> registStartup(String executableFilePath, String label,
|
|
{List<String>? arguments,
|
|
String? logStandardFilePath,
|
|
String? logErrorFilePath}) async {
|
|
var c = Completer<bool>();
|
|
final tagLabel = '{LABEL}';
|
|
final tagPath = '{FILE_PATH}';
|
|
var success = false;
|
|
|
|
//compose parameters
|
|
var parameters = '';
|
|
if (arguments != null) {
|
|
for (var arg in arguments) {
|
|
parameters += """
|
|
|
|
<string>$arg</string>""";
|
|
}
|
|
}
|
|
|
|
//create plist in LaunchAgents
|
|
final plistName = '$label.plist';
|
|
final userPath = Platform.environment['HOME'];
|
|
final tagLogStandard = '{LOG_STANDARD}';
|
|
final tagLogError = '{LOG_ERROR}';
|
|
final tagParameters = '{PARAMETERS}';
|
|
var plistContent = plistTemplate
|
|
.replaceAll(tagLabel, label)
|
|
.replaceAll(tagPath, executableFilePath)
|
|
.replaceAll(tagParameters, parameters);
|
|
if (logStandardFilePath == null) {
|
|
plistContent = plistContent.replaceAll(tagLogStandard, '');
|
|
} else {
|
|
plistContent = plistContent.replaceAll(tagLogStandard,
|
|
logStandardTemplate.replaceAll(tagLogStandard, logStandardFilePath));
|
|
}
|
|
if (logErrorFilePath == null) {
|
|
plistContent = plistContent.replaceAll(tagLogError, '');
|
|
} else {
|
|
plistContent = plistContent.replaceAll(tagLogError,
|
|
logErrorTemplate.replaceAll(tagLogError, logErrorFilePath));
|
|
}
|
|
var plistFile = File('$userPath/Library/LaunchAgents/$plistName');
|
|
await plistFile.create();
|
|
await plistFile.writeAsString(plistContent);
|
|
|
|
var result = await ProcessExecutor.run(
|
|
StringBuffer('chmod +x "$executableFilePath"'));
|
|
success = result.exitCode == 0;
|
|
|
|
c.complete(success);
|
|
return c.future;
|
|
}
|
|
|
|
@override
|
|
Future<bool> unregistStartup(String label) async {
|
|
var c = Completer<bool>();
|
|
var success = false;
|
|
var plistName = '$label.plist';
|
|
var userPath = Platform.environment['HOME'];
|
|
var file = File('$userPath/Library/LaunchAgents/$plistName');
|
|
if (file.existsSync()) {
|
|
await file.delete();
|
|
success = true;
|
|
}
|
|
c.complete(success);
|
|
return c.future;
|
|
}
|
|
}
|
|
|
|
class _StartupLinux extends _Startup {
|
|
final serviceTemplate = """[Unit]
|
|
Description={LABEL}
|
|
#Documentation=http://toki-labs.com
|
|
|
|
[Service]
|
|
Type=simple
|
|
#User=deck
|
|
#Group=deck
|
|
#TimeoutStartSec=0
|
|
#Restart=on-failure
|
|
#RestartSec=30s
|
|
#ExecStartPre=
|
|
ExecStart={FILE_PATH}
|
|
#SyslogIdentifier=TestService
|
|
#ExecStop=
|
|
|
|
[Install]
|
|
WantedBy=default.target""";
|
|
|
|
@override
|
|
Future<bool> isRegistedStartup(String label) async {
|
|
var c = Completer<bool>();
|
|
var exist = false;
|
|
var userPath = Platform.environment['HOME'] as String;
|
|
exist =
|
|
await File('$userPath/.config/systemd/user/$label.service').exists();
|
|
c.complete(exist);
|
|
return c.future;
|
|
}
|
|
|
|
//shell file must have '#!/bin/sh'
|
|
@override
|
|
Future<bool> registStartup(String executableFilePath, String label,
|
|
{List<String>? arguments,
|
|
String? logStandardFilePath,
|
|
String? logErrorFilePath}) async {
|
|
var c = Completer<bool>();
|
|
final tagLabel = '{LABEL}';
|
|
final tagPath = '{FILE_PATH}';
|
|
ProcessResult? result;
|
|
|
|
var userPath = Platform.environment['HOME'] as String;
|
|
var systemPath = '$userPath/.config/systemd/user';
|
|
if (arguments != null) {
|
|
for (var arg in arguments) {
|
|
executableFilePath += ' $arg';
|
|
}
|
|
}
|
|
var serviceContent = serviceTemplate
|
|
.replaceAll(tagLabel, label)
|
|
.replaceAll(tagPath, executableFilePath);
|
|
|
|
var serviceFile = File('$systemPath/$label.service');
|
|
await serviceFile.create();
|
|
await serviceFile.writeAsString(serviceContent);
|
|
|
|
var shell = StringBuffer();
|
|
shell.write('cd $systemPath && ');
|
|
shell.write('systemctl --user enable $label && ');
|
|
shell.write('systemctl --user daemon-reload');
|
|
result = await ProcessExecutor.run(shell);
|
|
print('exitCode: ${result.exitCode}');
|
|
c.complete(result.exitCode == 0);
|
|
return c.future;
|
|
}
|
|
|
|
@override
|
|
Future<bool> unregistStartup(String label) async {
|
|
var c = Completer<bool>();
|
|
var success = false;
|
|
var userPath = Platform.environment['HOME'] as String;
|
|
var shell = StringBuffer();
|
|
var systemPath = '$userPath/.config/systemd/user';
|
|
shell.write('cd $systemPath && ');
|
|
shell.write('systemctl --user stop $label && ');
|
|
shell.write('systemctl --user disable $label && ');
|
|
shell.write('systemctl --user daemon-reload');
|
|
var result = await ProcessExecutor.run(shell);
|
|
success = result.exitCode == 0;
|
|
|
|
if (success) {
|
|
success = false;
|
|
var file = File('$systemPath/$label.service');
|
|
if (await file.exists()) {
|
|
await file.delete();
|
|
success = true;
|
|
}
|
|
}
|
|
c.complete(success);
|
|
return c.future;
|
|
}
|
|
}
|
|
|
|
class _StartupWindows extends _Startup {
|
|
final windowsStartupPath =
|
|
'\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\';
|
|
|
|
final windowRoamingPath = '\\AppData\\Roaming\\';
|
|
|
|
final vbsTemplate = """Set WshShell = CreateObject("WScript.Shell")
|
|
WshShell.Run chr(34) & "{FILE_PATH}"{PARAMETERS} & Chr(34), 0
|
|
Set WshShell = Nothing
|
|
""";
|
|
|
|
@override
|
|
Future<bool> isRegistedStartup(String label) async {
|
|
var c = Completer<bool>();
|
|
//For Windows 8, 10
|
|
var exist = false;
|
|
var userPath = Platform.environment['UserProfile'];
|
|
var startupDir = Directory('$userPath$windowsStartupPath');
|
|
var files = startupDir.listSync();
|
|
for (var fileEntry in files) {
|
|
var fileName = path.basename(fileEntry.path);
|
|
var extension = path.extension(fileName);
|
|
fileName = fileName.replaceAll(extension, '');
|
|
if (fileName == label) {
|
|
exist = true;
|
|
break;
|
|
}
|
|
}
|
|
c.complete(exist);
|
|
return c.future;
|
|
}
|
|
|
|
//shell file must have '#!/bin/sh'
|
|
@override
|
|
Future<bool> registStartup(String executableFilePath, String label,
|
|
{List<String>? arguments,
|
|
String? logStandardFilePath,
|
|
String? logErrorFilePath}) async {
|
|
var c = Completer<bool>();
|
|
var file = File(executableFilePath);
|
|
ProcessResult? result;
|
|
//For Windows 8, 10
|
|
var userPath = Platform.environment['UserProfile'];
|
|
|
|
//compose vbs content
|
|
var parameters = '';
|
|
if (arguments != null) {
|
|
for (var arg in arguments) {
|
|
parameters += '" $arg"';
|
|
}
|
|
}
|
|
var vbsContent = vbsTemplate
|
|
.replaceAll('{FILE_PATH}', executableFilePath)
|
|
.replaceAll('{PARAMETERS}', parameters);
|
|
|
|
//create vbs file
|
|
var vbsInstallDir = Directory('$userPath$windowRoamingPath$label');
|
|
if (!await vbsInstallDir.exists()) {
|
|
await vbsInstallDir.create(recursive: true);
|
|
}
|
|
var vbsFile = File(path.join(vbsInstallDir.path, '$label.vbs'));
|
|
if (await vbsFile.exists()) {
|
|
await vbsFile.delete();
|
|
}
|
|
await vbsFile.create();
|
|
await vbsFile.writeAsString(vbsContent);
|
|
|
|
//create symbolic
|
|
var symbolicPath = '$userPath$windowsStartupPath$label.vbs';
|
|
result = await ProcessExecutor.run(
|
|
StringBuffer('mklink "$symbolicPath" "${vbsFile.path}"'));
|
|
c.complete(result.exitCode == 0);
|
|
return c.future;
|
|
}
|
|
|
|
@override
|
|
Future<bool> unregistStartup(String label) async {
|
|
var c = Completer<bool>();
|
|
var success = false;
|
|
//For Windows 8, 10
|
|
var userPath = Platform.environment['UserProfile'];
|
|
|
|
//delete vbs file
|
|
var vbsInstallDir = Directory('$userPath$windowRoamingPath$label');
|
|
var vbsFile = File(path.join(vbsInstallDir.path, '$label.vbs'));
|
|
if (await vbsFile.exists()) {
|
|
await vbsFile.delete();
|
|
var list = vbsInstallDir.listSync(recursive: true);
|
|
if (list.isEmpty) {
|
|
if (await vbsInstallDir.exists()) {
|
|
await vbsInstallDir.delete(recursive: true);
|
|
}
|
|
}
|
|
}
|
|
|
|
//delete shorcut file
|
|
var startupDir = Directory('$userPath$windowsStartupPath');
|
|
var files = startupDir.listSync();
|
|
for (var fileEntry in files) {
|
|
var fileName = path.basename(fileEntry.path);
|
|
var extension = path.extension(fileName);
|
|
fileName = fileName.replaceAll(extension, '');
|
|
if (fileName == label) {
|
|
await File(fileEntry.path).delete();
|
|
success = true;
|
|
break;
|
|
}
|
|
}
|
|
c.complete(success);
|
|
return c.future;
|
|
}
|
|
}
|