76 lines
2.2 KiB
Swift
76 lines
2.2 KiB
Swift
import Foundation
|
|
|
|
public struct HookJob: Sendable {
|
|
public let text: String
|
|
public let timestamp: Date
|
|
|
|
public init(text: String, timestamp: Date) {
|
|
self.text = text
|
|
self.timestamp = timestamp
|
|
}
|
|
}
|
|
|
|
public actor HookExecutor {
|
|
private let config: SwabbleConfig
|
|
private var lastRun: Date?
|
|
private let hostname: String
|
|
|
|
public init(config: SwabbleConfig) {
|
|
self.config = config
|
|
hostname = Host.current().localizedName ?? "host"
|
|
}
|
|
|
|
public func shouldRun() -> Bool {
|
|
guard config.hook.cooldownSeconds > 0 else { return true }
|
|
if let lastRun, Date().timeIntervalSince(lastRun) < config.hook.cooldownSeconds {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
public func run(job: HookJob) async throws {
|
|
guard shouldRun() else { return }
|
|
guard !config.hook.command.isEmpty else { throw NSError(
|
|
domain: "Hook",
|
|
code: 1,
|
|
userInfo: [NSLocalizedDescriptionKey: "hook command not set"]) }
|
|
|
|
let prefix = config.hook.prefix.replacingOccurrences(of: "${hostname}", with: hostname)
|
|
let payload = prefix + job.text
|
|
|
|
let process = Process()
|
|
process.executableURL = URL(fileURLWithPath: config.hook.command)
|
|
process.arguments = config.hook.args + [payload]
|
|
|
|
var env = ProcessInfo.processInfo.environment
|
|
env["SWABBLE_TEXT"] = job.text
|
|
env["SWABBLE_PREFIX"] = prefix
|
|
for (k, v) in config.hook.env {
|
|
env[k] = v
|
|
}
|
|
process.environment = env
|
|
|
|
let pipe = Pipe()
|
|
process.standardOutput = pipe
|
|
process.standardError = pipe
|
|
|
|
try process.run()
|
|
|
|
let timeoutNanos = UInt64(max(config.hook.timeoutSeconds, 0.1) * 1_000_000_000)
|
|
try await withThrowingTaskGroup(of: Void.self) { group in
|
|
group.addTask {
|
|
process.waitUntilExit()
|
|
}
|
|
group.addTask {
|
|
try await Task.sleep(nanoseconds: timeoutNanos)
|
|
if process.isRunning {
|
|
process.terminate()
|
|
}
|
|
}
|
|
try await group.next()
|
|
group.cancelAll()
|
|
}
|
|
lastRun = Date()
|
|
}
|
|
}
|