mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2026-03-27 22:40:08 +01:00
- Added shell pipe timeout (w/ new tests) - Reworked ServicesManager to be blocking for startup (10s) - Renamed queues to be more consistent
110 lines
3.7 KiB
Swift
110 lines
3.7 KiB
Swift
//
|
|
// ValetServicesManager.swift
|
|
// PHP Monitor
|
|
//
|
|
// Created by Nico Verbruggen on 23/12/2022.
|
|
// Copyright © 2025 Nico Verbruggen. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import Cocoa
|
|
import NVAlert
|
|
|
|
class ValetServicesManager: ServicesManager {
|
|
private let data: ValetServicesDataManager
|
|
|
|
override init(_ container: Container) {
|
|
self.data = ValetServicesDataManager(container)
|
|
super.init(container)
|
|
}
|
|
|
|
override func reloadServicesStatus() async {
|
|
Log.perf("Reloading Homebrew services status...")
|
|
|
|
// Fetch data on background (actor-isolated, thread-safe)
|
|
let homebrewServices = await data.reloadServicesStatus(isRetry: false)
|
|
|
|
// Update UI on main thread
|
|
await MainActor.run {
|
|
self.services = self.formulae.map { formula in
|
|
Service(
|
|
formula: formula,
|
|
service: homebrewServices.first { $0.name == formula.name }
|
|
)
|
|
}
|
|
|
|
Log.perf("Homebrew service data received and broadcast!")
|
|
}
|
|
}
|
|
|
|
override func toggleService(named: String) async {
|
|
guard let wrapper = self[named] else {
|
|
return Log.err("The wrapper for '\(named)' is missing.")
|
|
}
|
|
|
|
// Normally, we allow starting and stopping
|
|
var action = wrapper.status == .active ? "stop" : "start"
|
|
|
|
// However, if we've encountered an error, attempt to restart
|
|
if wrapper.status == .error {
|
|
action = "restart"
|
|
}
|
|
|
|
// Run the command
|
|
await brew(
|
|
container,
|
|
"services \(action) \(wrapper.formula.name)",
|
|
sudo: wrapper.formula.elevated
|
|
)
|
|
|
|
// Reload the services status to confirm this worked
|
|
await ServicesManager.shared.reloadServicesStatus()
|
|
await presentTroubleshootingForService(named: named)
|
|
}
|
|
|
|
@MainActor func presentTroubleshootingForService(named: String) async {
|
|
// If we cannot get data from Homebrew, we won't be able to troubleshoot
|
|
guard let after = await data.getHomebrewService(named: named) else {
|
|
return
|
|
}
|
|
|
|
// If we don't get an error message from Homebrew, we won't be able to troubleshoot
|
|
guard after.status == "error" else {
|
|
return
|
|
}
|
|
|
|
Log.err("The service '\(named)' is now reporting an error.")
|
|
|
|
// If we don't have a path to a log file, show a simplified alert
|
|
guard let errorLogPath = after.error_log_path else {
|
|
return NVAlert().withInformation(
|
|
title: "alert.service_error.title".localized(named),
|
|
subtitle: "alert.service_error.subtitle.no_error_log".localized(named),
|
|
description: "alert.service_error.extra".localized
|
|
)
|
|
.withPrimary(text: "alert.service_error.button.close".localized)
|
|
.show(urgency: .bringToFront)
|
|
}
|
|
|
|
// If we do have a path to a log file, show a more complex alert w/ Show Log button
|
|
NVAlert().withInformation(
|
|
title: "alert.service_error.title".localized(named),
|
|
subtitle: "alert.service_error.subtitle.error_log".localized(named),
|
|
description: "alert.service_error.extra".localized
|
|
)
|
|
.withPrimary(text: "alert.service_error.button.close".localized)
|
|
.withTertiary(text: "alert.service_error.button.show_log".localized, action: { alert in
|
|
let url = URL(fileURLWithPath: errorLogPath)
|
|
|
|
if errorLogPath.hasSuffix(".log") {
|
|
NSWorkspace.shared.open(url)
|
|
} else {
|
|
NSWorkspace.shared.activateFileViewerSelecting([url])
|
|
}
|
|
|
|
alert.close(with: .OK)
|
|
})
|
|
.show(urgency: .bringToFront)
|
|
}
|
|
}
|