Files
oai-swift/oAI/Services/DraftRecoveryService.swift
T
rune c3abc5a748 Update remaining oai.pm references to confab.no
Covers the per-file license-header comment (~80 Swift files) plus
the contact/website links in README.md, PRIVACY.md, and SECURITY.md.
2026-08-03 08:44:35 +02:00

78 lines
2.7 KiB
Swift

//
// DraftRecoveryService.swift
// Confab
//
// Crash-recovery draft for the in-progress conversation — a lightweight,
// invisible mirror of the current chat, distinct from named saved conversations.
//
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (C) 2026 Rune Olsen
//
// This file is part of Confab.
//
// Confab is licensed under the PolyForm Noncommercial License 1.0.0.
// You may use, study, modify, and share it for any noncommercial
// purpose. Commercial use — including selling Confab or any part of
// it, standalone or bundled into another product or service —
// requires a separate commercial license from the copyright holder.
//
// See the LICENSE file or
// <https://polyformproject.org/licenses/noncommercial/1.0.0> for
// the full license text. For commercial licensing, contact Rune
// Olsen via <https://confab.no>.
import Foundation
struct DraftConversation: Codable, Sendable {
let messages: [Message]
let conversationId: UUID?
let conversationName: String?
let modelId: String?
let savedAt: Date
}
final class DraftRecoveryService: Sendable {
static let shared = DraftRecoveryService()
private let fileURL: URL
/// - Parameter fileURL: injection point for tests; production uses the default
/// Application Support location, matching `DatabaseService`'s pattern.
nonisolated init(fileURL: URL? = nil) {
if let fileURL {
self.fileURL = fileURL
} else {
let appSupport = FileManager.default.urls(for: .applicationSupportDirectory,
in: .userDomainMask).first!
let dir = appSupport.appendingPathComponent("oAI", isDirectory: true)
try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
self.fileURL = dir.appendingPathComponent("draft_conversation.json")
}
}
func save(_ draft: DraftConversation) {
do {
let data = try JSONEncoder().encode(draft)
try data.write(to: fileURL, options: .atomic)
Log.db.info("DraftRecoveryService: wrote draft to \(fileURL.path)")
} catch {
Log.db.error("DraftRecoveryService: save failed: \(error.localizedDescription)")
}
}
func load() -> DraftConversation? {
do {
let data = try Data(contentsOf: fileURL)
return try JSONDecoder().decode(DraftConversation.self, from: data)
} catch {
Log.db.info("DraftRecoveryService: load found nothing (\(error.localizedDescription))")
return nil
}
}
func clear() {
try? FileManager.default.removeItem(at: fileURL)
}
}