134 lines
5.7 KiB
Swift
134 lines
5.7 KiB
Swift
import Foundation
|
||
import UserNotifications
|
||
import AppKit
|
||
|
||
public final class UpdaterService: ObservableObject {
|
||
public static let shared = UpdaterService()
|
||
public static let didUpdateStateNotification = Notification.Name("UpdaterServiceDidUpdateStateNotification")
|
||
|
||
@Published public var isUpdating: Bool = false
|
||
@Published public var updateStatusMessage: String = ""
|
||
|
||
private init() {}
|
||
|
||
public func checkForUpdatesAndApply() {
|
||
guard !isUpdating else { return }
|
||
|
||
isUpdating = true
|
||
updateStatusMessage = "Проверка обновлений на GitHub..."
|
||
NotificationCenter.default.post(name: UpdaterService.didUpdateStateNotification, object: self)
|
||
|
||
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
||
let projectDir = "/Users/autli/Documents/blts_tracker"
|
||
let updateScript = """
|
||
cd "\(projectDir)"
|
||
git -c http.timeout=8 fetch origin main 2>&1
|
||
FETCH_STATUS=$?
|
||
|
||
if [ $FETCH_STATUS -ne 0 ]; then
|
||
echo "NETWORK_ERROR"
|
||
exit 0
|
||
fi
|
||
|
||
LOCAL=$(git rev-parse HEAD)
|
||
REMOTE=$(git rev-parse origin/main)
|
||
|
||
if [ "$LOCAL" != "$REMOTE" ] || [ -f "\(projectDir)/force_update" ]; then
|
||
echo "UPDATE_FOUND"
|
||
git pull origin main 2>&1
|
||
./build_app.sh 2>&1
|
||
|
||
USER_APPS="$HOME/Applications"
|
||
mkdir -p "$USER_APPS"
|
||
rm -rf "$USER_APPS/BLTS Tracker.app"
|
||
cp -R "\(projectDir)/BLTS Tracker.app" "$USER_APPS/"
|
||
xattr -cr "$USER_APPS/BLTS Tracker.app" 2>/dev/null || true
|
||
|
||
if [ -w "/Applications" ]; then
|
||
rm -rf "/Applications/BLTS Tracker.app"
|
||
cp -R "\(projectDir)/BLTS Tracker.app" "/Applications/"
|
||
xattr -cr "/Applications/BLTS Tracker.app" 2>/dev/null || true
|
||
fi
|
||
|
||
echo "SUCCESS"
|
||
else
|
||
echo "UP_TO_DATE"
|
||
fi
|
||
"""
|
||
|
||
let process = Process()
|
||
process.executableURL = URL(fileURLWithPath: "/bin/bash")
|
||
process.arguments = ["-c", updateScript]
|
||
|
||
let pipe = Pipe()
|
||
process.standardOutput = pipe
|
||
process.standardError = pipe
|
||
|
||
do {
|
||
try process.run()
|
||
process.waitUntilExit()
|
||
|
||
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||
let output = String(data: data, encoding: .utf8) ?? ""
|
||
|
||
DispatchQueue.main.async {
|
||
self?.isUpdating = false
|
||
NotificationCenter.default.post(name: UpdaterService.didUpdateStateNotification, object: self)
|
||
|
||
if output.contains("SUCCESS") {
|
||
self?.sendNotification(
|
||
title: "🎉 Обновление установлено",
|
||
body: "BLTS Tracker успешно обновлён с GitHub! Перезапуск..."
|
||
)
|
||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
||
let appPath = "\(projectDir)/BLTS Tracker.app"
|
||
let p = Process()
|
||
p.executableURL = URL(fileURLWithPath: "/usr/bin/open")
|
||
p.arguments = [appPath]
|
||
try? p.run()
|
||
exit(0)
|
||
}
|
||
} else if output.contains("NETWORK_ERROR") {
|
||
self?.sendNotification(
|
||
title: "⚠️ Ошибка сети",
|
||
body: "Не удалось связаться с GitHub. Проверьте интернет или отключите VPN."
|
||
)
|
||
} else if output.contains("UP_TO_DATE") {
|
||
self?.sendNotification(
|
||
title: "✅ У вас последняя версия",
|
||
body: "Обновлений на GitHub нет, установлена актуальная версия."
|
||
)
|
||
} else {
|
||
self?.sendNotification(
|
||
title: "ℹ️ Проверка завершена",
|
||
body: "Репозиторий проверен. Код актуален."
|
||
)
|
||
}
|
||
}
|
||
} catch {
|
||
DispatchQueue.main.async {
|
||
self?.isUpdating = false
|
||
NotificationCenter.default.post(name: UpdaterService.didUpdateStateNotification, object: self)
|
||
self?.sendNotification(
|
||
title: "⚠️ Ошибка",
|
||
body: "Не удалось выполнить проверку: \(error.localizedDescription)"
|
||
)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private func sendNotification(title: String, body: String) {
|
||
let content = UNMutableNotificationContent()
|
||
content.title = title
|
||
content.body = body
|
||
content.sound = .default
|
||
|
||
let request = UNNotificationRequest(
|
||
identifier: "updater_\(UUID().uuidString)",
|
||
content: content,
|
||
trigger: nil
|
||
)
|
||
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
|
||
}
|
||
}
|