BluetoothTracker/Sources/blts_tracker/Services/UpdaterService.swift

134 lines
5.7 KiB
Swift
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}
}