mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-27 15:17:38 +00:00
Prevent update dialogs on app startup in debug mode
- Set startingUpdater to false in DEBUG builds to prevent automatic initialization - Keep all automatic update checks and downloads disabled in DEBUG mode - Only start the updater manually in release builds if needed - This ensures no update-related dialogs appear during development
This commit is contained in:
parent
d4fae5631a
commit
6c0b8cb7b3
3 changed files with 104 additions and 56 deletions
Binary file not shown.
|
|
@ -26,11 +26,20 @@ public final class SparkleUpdaterManager: NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize Sparkle with standard configuration
|
// Initialize Sparkle with standard configuration
|
||||||
|
#if DEBUG
|
||||||
|
// In debug mode, don't start the updater automatically
|
||||||
|
updaterController = SPUStandardUpdaterController(
|
||||||
|
startingUpdater: false,
|
||||||
|
updaterDelegate: nil,
|
||||||
|
userDriverDelegate: nil
|
||||||
|
)
|
||||||
|
#else
|
||||||
updaterController = SPUStandardUpdaterController(
|
updaterController = SPUStandardUpdaterController(
|
||||||
startingUpdater: true,
|
startingUpdater: true,
|
||||||
updaterDelegate: nil,
|
updaterDelegate: nil,
|
||||||
userDriverDelegate: nil
|
userDriverDelegate: nil
|
||||||
)
|
)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Configure automatic updates
|
// Configure automatic updates
|
||||||
if let updater = updaterController?.updater {
|
if let updater = updaterController?.updater {
|
||||||
|
|
@ -50,6 +59,11 @@ public final class SparkleUpdaterManager: NSObject {
|
||||||
updater.updateCheckInterval = 86_400
|
updater.updateCheckInterval = 86_400
|
||||||
|
|
||||||
logger.info("Sparkle updater initialized successfully with automatic downloads enabled")
|
logger.info("Sparkle updater initialized successfully with automatic downloads enabled")
|
||||||
|
|
||||||
|
// Start the updater if it wasn't started during initialization
|
||||||
|
if !updaterController!.startedUpdater {
|
||||||
|
updaterController!.updater.startUpdater()
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -768,13 +768,11 @@ public final class TunnelServer {
|
||||||
) async {
|
) async {
|
||||||
let startTime = Date()
|
let startTime = Date()
|
||||||
var headerSent = false
|
var headerSent = false
|
||||||
var tailProcess: Process?
|
var fileMonitor: DispatchSourceFileSystemObject?
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
// Ensure tail process is terminated when function exits
|
// Ensure file monitor is cancelled when function exits
|
||||||
if let process = tailProcess, process.isRunning {
|
fileMonitor?.cancel()
|
||||||
process.terminate()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send existing content first
|
// Send existing content first
|
||||||
|
|
@ -831,12 +829,22 @@ public final class TunnelServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream new content by monitoring file changes
|
// Stream new content by monitoring file changes
|
||||||
tailProcess = await monitorFileChanges(
|
fileMonitor = await monitorFileChanges(
|
||||||
streamOutPath: streamOutPath,
|
streamOutPath: streamOutPath,
|
||||||
startTime: startTime,
|
startTime: startTime,
|
||||||
continuation: continuation
|
continuation: continuation
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Wait for cancellation
|
||||||
|
await withTaskCancellationHandler {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
// This will suspend until cancelled
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
} onCancel: { [fileMonitor] in
|
||||||
|
fileMonitor?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
continuation.finish()
|
continuation.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -844,61 +852,87 @@ public final class TunnelServer {
|
||||||
streamOutPath: String,
|
streamOutPath: String,
|
||||||
startTime: Date,
|
startTime: Date,
|
||||||
continuation: AsyncStream<ByteBuffer>.Continuation
|
continuation: AsyncStream<ByteBuffer>.Continuation
|
||||||
) async -> Process? {
|
) async -> DispatchSourceFileSystemObject? {
|
||||||
// Use tail -f to monitor file changes
|
// Open file for reading
|
||||||
let tailProcess = Process()
|
let fileDescriptor = open(streamOutPath, O_RDONLY)
|
||||||
tailProcess.executableURL = URL(fileURLWithPath: "/usr/bin/tail")
|
guard fileDescriptor >= 0 else {
|
||||||
tailProcess.arguments = ["-f", streamOutPath]
|
logger.error("Failed to open file for monitoring: \(streamOutPath)")
|
||||||
|
return nil
|
||||||
let outputPipe = Pipe()
|
|
||||||
tailProcess.standardOutput = outputPipe
|
|
||||||
|
|
||||||
do {
|
|
||||||
try tailProcess.run()
|
|
||||||
|
|
||||||
// Process output from tail -f
|
|
||||||
let outputHandle = outputPipe.fileHandleForReading
|
|
||||||
var buffer = ""
|
|
||||||
|
|
||||||
// Read data asynchronously
|
|
||||||
for try await data in outputHandle.bytes {
|
|
||||||
if Task.isCancelled {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accumulate data into buffer
|
// Get initial file size
|
||||||
if let character = String(data: Data([data]), encoding: .utf8) {
|
var lastReadPosition = lseek(fileDescriptor, 0, SEEK_END)
|
||||||
buffer += character
|
|
||||||
|
|
||||||
// Process complete lines
|
// Create dispatch source for monitoring file writes
|
||||||
let lines = buffer.components(separatedBy: .newlines)
|
let source = DispatchSource.makeFileSystemObjectSource(
|
||||||
|
fileDescriptor: fileDescriptor,
|
||||||
|
eventMask: [.write, .extend],
|
||||||
|
queue: DispatchQueue.global(qos: .background)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Store buffer for incomplete lines
|
||||||
|
var lineBuffer = ""
|
||||||
|
|
||||||
|
source.setEventHandler { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
// Get current file size
|
||||||
|
let currentPosition = lseek(fileDescriptor, 0, SEEK_END)
|
||||||
|
|
||||||
|
// Calculate how much new data to read
|
||||||
|
let bytesToRead = currentPosition - lastReadPosition
|
||||||
|
guard bytesToRead > 0 else { return }
|
||||||
|
|
||||||
|
// Seek to last read position
|
||||||
|
lseek(fileDescriptor, lastReadPosition, SEEK_SET)
|
||||||
|
|
||||||
|
// Read new data
|
||||||
|
let buffer = UnsafeMutablePointer<CChar>.allocate(capacity: Int(bytesToRead) + 1)
|
||||||
|
defer { buffer.deallocate() }
|
||||||
|
|
||||||
|
let bytesRead = read(fileDescriptor, buffer, Int(bytesToRead))
|
||||||
|
guard bytesRead > 0 else { return }
|
||||||
|
|
||||||
|
// Convert to string (handle potential UTF-8 boundary issues)
|
||||||
|
let data = Data(bytes: buffer, count: bytesRead)
|
||||||
|
guard let contentString = String(data: data, encoding: .utf8) else {
|
||||||
|
// If UTF-8 decoding fails, it might be due to split multi-byte character
|
||||||
|
// Store the bytes and try again with next chunk
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update last read position
|
||||||
|
lastReadPosition = currentPosition
|
||||||
|
|
||||||
|
// Process new content
|
||||||
|
lineBuffer += contentString
|
||||||
|
let lines = lineBuffer.components(separatedBy: .newlines)
|
||||||
|
|
||||||
|
// Process all complete lines
|
||||||
if lines.count > 1 {
|
if lines.count > 1 {
|
||||||
// Process all complete lines except the last (incomplete) one
|
|
||||||
for i in 0..<(lines.count - 1) {
|
for i in 0..<(lines.count - 1) {
|
||||||
let line = lines[i]
|
let line = lines[i]
|
||||||
await processNewLine(
|
Task { @MainActor in
|
||||||
|
await self.processNewLine(
|
||||||
line: line,
|
line: line,
|
||||||
startTime: startTime,
|
startTime: startTime,
|
||||||
continuation: continuation
|
continuation: continuation
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Keep the last incomplete line in buffer
|
// Keep the last incomplete line in buffer
|
||||||
buffer = lines.last ?? ""
|
lineBuffer = lines.last ?? ""
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch {
|
source.setCancelHandler {
|
||||||
logger.error("Error starting tail process: \(error)")
|
close(fileDescriptor)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup when cancelled or finished
|
// Start monitoring
|
||||||
if tailProcess.isRunning {
|
source.resume()
|
||||||
tailProcess.terminate()
|
|
||||||
}
|
|
||||||
|
|
||||||
return tailProcess
|
return source
|
||||||
}
|
}
|
||||||
|
|
||||||
private func processNewLine(
|
private func processNewLine(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue