261 lines
6.9 KiB
Swift
261 lines
6.9 KiB
Swift
import CoreData
|
|
|
|
protocol Database {
|
|
var viewContext: NSManagedObjectContext { get }
|
|
|
|
func room(id: String) -> Room?
|
|
func message(id: String) -> Message?
|
|
func createTempMessage(msg: String, in room: Room, for loggedUser: LoggedUser) -> String
|
|
func updateMessage(_ id: String, status: String)
|
|
func remove(_ message: Message)
|
|
|
|
func process(subscription: SubscriptionsResponse.Subscription)
|
|
func process(subscription: SubscriptionsResponse.Subscription?, in updatedRoom: RoomsResponse.Room)
|
|
func process(updatedMessage: MessageResponse, in room: Room)
|
|
|
|
func remove()
|
|
}
|
|
|
|
final class RocketChatDatabase: Database {
|
|
private let server: Server
|
|
|
|
init(server: Server) {
|
|
self.server = server
|
|
}
|
|
|
|
var viewContext: NSManagedObjectContext {
|
|
container.viewContext
|
|
}
|
|
|
|
private static let model: NSManagedObjectModel = {
|
|
guard let url = Bundle.main.url(forResource: "RocketChat", withExtension: "momd"),
|
|
let managedObjectModel = NSManagedObjectModel(contentsOf: url) else {
|
|
fatalError("Can't find Core Data Model")
|
|
}
|
|
|
|
return managedObjectModel
|
|
}()
|
|
|
|
private lazy var container: NSPersistentContainer = {
|
|
let name = server.url.host ?? "default"
|
|
|
|
let container = NSPersistentContainer(name: name, managedObjectModel: Self.model)
|
|
|
|
container.loadPersistentStores { _, error in
|
|
if let error { fatalError("Can't load persistent stores: \(error)") }
|
|
}
|
|
|
|
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
|
|
|
return container
|
|
}()
|
|
|
|
private func save() {
|
|
guard container.viewContext.hasChanges else {
|
|
return
|
|
}
|
|
|
|
try? container.viewContext.save()
|
|
}
|
|
|
|
func createUser(id: String) -> User {
|
|
let user = User(context: viewContext)
|
|
user.id = id
|
|
|
|
return user
|
|
}
|
|
|
|
func createRoom(id: String) -> Room {
|
|
let room = Room(context: viewContext)
|
|
room.id = id
|
|
|
|
return room
|
|
}
|
|
|
|
func createMessage(id: String) -> Message {
|
|
let message = Message(context: viewContext)
|
|
message.id = id
|
|
message.ts = Date()
|
|
|
|
return message
|
|
}
|
|
|
|
func createAttachment(identifier: String) -> Attachment {
|
|
let attachment = Attachment(context: viewContext)
|
|
attachment.id = identifier
|
|
|
|
return attachment
|
|
}
|
|
|
|
func createTempMessage(msg: String, in room: Room, for loggedUser: LoggedUser) -> String {
|
|
let id = String.random(17)
|
|
let message = message(id: id) ?? createMessage(id: id)
|
|
|
|
message.id = id
|
|
message.ts = Date()
|
|
message.room = room
|
|
message.status = "temp" // TODO:
|
|
message.msg = msg
|
|
message.groupable = true
|
|
|
|
let user = user(id: loggedUser.id) ?? createUser(id: loggedUser.id)
|
|
user.username = loggedUser.username
|
|
user.name = loggedUser.name
|
|
message.user = user
|
|
|
|
return id
|
|
}
|
|
|
|
func updateMessage(_ id: String, status: String) {
|
|
let message = message(id: id) ?? createMessage(id: id)
|
|
message.status = status
|
|
|
|
save()
|
|
}
|
|
|
|
func remove(_ message: Message) {
|
|
viewContext.delete(message)
|
|
|
|
save()
|
|
}
|
|
|
|
func user(id: String) -> User? {
|
|
let user = User(context: viewContext)
|
|
user.id = id
|
|
|
|
return user
|
|
}
|
|
|
|
func room(id: String) -> Room? {
|
|
let request = Room.fetchRequest()
|
|
request.predicate = NSPredicate(format: "id == %@", id)
|
|
|
|
return try? viewContext.fetch(request).first
|
|
}
|
|
|
|
func message(id: String) -> Message? {
|
|
let request = Message.fetchRequest()
|
|
request.predicate = NSPredicate(format: "id == %@", id)
|
|
|
|
return try? viewContext.fetch(request).first
|
|
}
|
|
|
|
func attachment(identifier: String) -> Attachment? {
|
|
let request = Attachment.fetchRequest()
|
|
request.predicate = NSPredicate(format: "id == %@", identifier)
|
|
|
|
return try? viewContext.fetch(request).first
|
|
}
|
|
|
|
func rooms(ids: [String]) -> [Room] {
|
|
let request = Room.fetchRequest()
|
|
request.predicate = NSPredicate(format: "ANY id IN %@", ids)
|
|
|
|
return (try? viewContext.fetch(request)) ?? []
|
|
}
|
|
|
|
func process(updatedMessage: MessageResponse, in room: Room) {
|
|
let message = message(id: updatedMessage._id) ?? createMessage(id: updatedMessage._id)
|
|
|
|
let user = user(id: updatedMessage.u._id) ?? createUser(id: updatedMessage.u._id)
|
|
user.name = updatedMessage.u.name
|
|
user.username = updatedMessage.u.username
|
|
|
|
message.status = "received" // TODO:
|
|
message.id = updatedMessage._id
|
|
message.msg = updatedMessage.msg
|
|
message.room = room
|
|
message.ts = updatedMessage.ts
|
|
message.user = user
|
|
message.t = updatedMessage.t
|
|
message.groupable = updatedMessage.groupable ?? true
|
|
message.editedAt = updatedMessage.editedAt
|
|
|
|
updatedMessage.attachments?.forEach { attachment in
|
|
process(updatedAttachment: attachment, in: message)
|
|
}
|
|
|
|
save()
|
|
}
|
|
|
|
func process(updatedAttachment: AttachmentResponse, in message: Message) {
|
|
let identifier = updatedAttachment.imageURL ?? updatedAttachment.audioURL
|
|
|
|
guard let identifier = identifier?.absoluteString ?? updatedAttachment.title else {
|
|
return
|
|
}
|
|
|
|
let attachment = attachment(identifier: identifier) ?? createAttachment(identifier: identifier)
|
|
|
|
attachment.msg = updatedAttachment.description
|
|
attachment.message = message
|
|
attachment.width = updatedAttachment.dimensions?.width ?? 0
|
|
attachment.height = updatedAttachment.dimensions?.height ?? 0
|
|
}
|
|
|
|
func process(subscription: SubscriptionsResponse.Subscription?, in updatedRoom: RoomsResponse.Room) {
|
|
let room = room(id: updatedRoom._id) ?? createRoom(id: updatedRoom._id)
|
|
|
|
room.name = updatedRoom.name
|
|
room.fname = updatedRoom.fname
|
|
room.updatedAt = updatedRoom._updatedAt
|
|
room.t = updatedRoom.t
|
|
room.usernames = updatedRoom.usernames
|
|
room.uids = updatedRoom.uids
|
|
room.prid = updatedRoom.prid
|
|
room.isReadOnly = updatedRoom.ro ?? false
|
|
room.encrypted = updatedRoom.encrypted ?? false
|
|
room.teamMain = updatedRoom.teamMain ?? false
|
|
room.archived = updatedRoom.archived ?? false
|
|
room.broadcast = updatedRoom.broadcast ?? false
|
|
|
|
if let subscription {
|
|
room.alert = subscription.alert
|
|
room.name = room.name ?? subscription.name
|
|
room.fname = room.fname ?? subscription.fname
|
|
room.unread = Int32(subscription.unread)
|
|
}
|
|
|
|
if let lastMessage = updatedRoom.lastMessage?.value {
|
|
process(updatedMessage: lastMessage, in: room)
|
|
}
|
|
|
|
let lastRoomUpdate = updatedRoom.lm ?? updatedRoom.ts ?? updatedRoom._updatedAt
|
|
|
|
if let lr = subscription?.lr, let lastRoomUpdate {
|
|
room.ts = max(lr, lastRoomUpdate)
|
|
} else {
|
|
room.ts = lastRoomUpdate
|
|
}
|
|
|
|
save()
|
|
}
|
|
|
|
func process(subscription: SubscriptionsResponse.Subscription) {
|
|
let room = room(id: subscription.rid) ?? createRoom(id: subscription.rid)
|
|
|
|
room.alert = subscription.alert
|
|
room.name = room.name ?? subscription.name
|
|
room.fname = room.fname ?? subscription.fname
|
|
room.unread = Int32(subscription.unread)
|
|
|
|
if let lr = subscription.lr, let lastRoomUpdate = room.ts {
|
|
room.ts = max(lr, lastRoomUpdate)
|
|
}
|
|
|
|
save()
|
|
}
|
|
|
|
func remove() {
|
|
guard let path = container.persistentStoreDescriptions.first?.url?.path else {
|
|
return
|
|
}
|
|
|
|
do {
|
|
try FileManager.default.removeItem(atPath: path)
|
|
} catch {
|
|
print(error)
|
|
}
|
|
}
|
|
}
|