mirror of https://github.com/oxen-io/session-ios
Replace PublicChatManager
parent
b8d9334d19
commit
e38dae5a05
@ -0,0 +1,96 @@
|
||||
import PromiseKit
|
||||
|
||||
@objc(SNOpenGroupManager)
|
||||
public final class OpenGroupManager : NSObject, OpenGroupManagerProtocol {
|
||||
private var pollers: [String:OpenGroupPoller] = [:]
|
||||
private var isPolling = false
|
||||
|
||||
// MARK: Error
|
||||
public enum Error : LocalizedError {
|
||||
case invalidURL
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .invalidURL: return "Invalid URL."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Initialization
|
||||
@objc public static let shared = OpenGroupManager()
|
||||
|
||||
private override init() { }
|
||||
|
||||
// MARK: Polling
|
||||
@objc public func startPolling() {
|
||||
guard !isPolling else { return }
|
||||
isPolling = true
|
||||
let openGroups = Storage.shared.getAllUserOpenGroups()
|
||||
for (_, openGroup) in openGroups {
|
||||
if let poller = pollers[openGroup.id] { poller.stop() } // Should never occur
|
||||
let poller = OpenGroupPoller(for: openGroup)
|
||||
poller.startIfNeeded()
|
||||
pollers[openGroup.id] = poller
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func stopPolling() {
|
||||
pollers.forEach { (_, openGroupPoller) in openGroupPoller.stop() }
|
||||
pollers.removeAll()
|
||||
}
|
||||
|
||||
// MARK: Adding & Removing
|
||||
public func add(with url: String, using transaction: Any) -> Promise<Void> {
|
||||
guard let url = URL(string: url), let scheme = url.scheme, scheme == "https", url.host != nil else {
|
||||
return Promise(error: Error.invalidURL)
|
||||
}
|
||||
let channel: UInt64 = 1
|
||||
let server = url.absoluteString
|
||||
let userPublicKey = getUserHexEncodedPublicKey()
|
||||
let profileManager = SSKEnvironment.shared.profileManager
|
||||
let displayName = profileManager.profileNameForRecipient(withID: userPublicKey)
|
||||
let profilePictureURL = profileManager.profilePictureURL()
|
||||
let profileKey = profileManager.localProfileKey().keyData
|
||||
Storage.shared.removeLastMessageServerID(for: channel, on: server, using: transaction)
|
||||
Storage.shared.removeLastDeletionServerID(for: channel, on: server, using: transaction)
|
||||
return OpenGroupAPI.getInfo(for: channel, on: server).done { info in
|
||||
let openGroup = OpenGroup(channel: channel, server: server, displayName: info.displayName, isDeletable: true)!
|
||||
let groupID = LKGroupUtilities.getEncodedOpenGroupIDAsData(openGroup.id)
|
||||
let model = TSGroupModel(title: openGroup.displayName, memberIds: [ userPublicKey ], image: nil, groupId: groupID, groupType: .openGroup, adminIds: [])
|
||||
Storage.shared.write(with: { transaction in
|
||||
let thread = TSGroupThread.getOrCreateThread(with: model, transaction: transaction as! YapDatabaseReadWriteTransaction)
|
||||
Storage.shared.setOpenGroup(openGroup, for: thread.uniqueId!, using: transaction)
|
||||
}, completion: {
|
||||
let _ = OpenGroupAPI.setDisplayName(to: displayName, on: server)
|
||||
let _ = OpenGroupAPI.setProfilePictureURL(to: profilePictureURL, using: profileKey, on: server)
|
||||
let _ = OpenGroupAPI.join(channel, on: server)
|
||||
if let poller = OpenGroupManager.shared.pollers[openGroup.id] {
|
||||
poller.stop()
|
||||
OpenGroupManager.shared.pollers[openGroup.id] = nil
|
||||
}
|
||||
let poller = OpenGroupPoller(for: openGroup)
|
||||
poller.startIfNeeded()
|
||||
OpenGroupManager.shared.pollers[openGroup.id] = poller
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public func delete(_ openGroup: OpenGroup, associatedWith thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) {
|
||||
if let poller = pollers[openGroup.id] {
|
||||
poller.stop()
|
||||
pollers[openGroup.id] = nil
|
||||
}
|
||||
var messageIDs: Set<String> = []
|
||||
thread.enumerateInteractions(with: transaction) { interaction, _ in
|
||||
messageIDs.insert(interaction.uniqueId!)
|
||||
}
|
||||
SNMessagingKitConfiguration.shared.storage.updateMessageIDCollectionByPruningMessagesWithIDs(messageIDs, using: transaction)
|
||||
Storage.shared.removeLastMessageServerID(for: openGroup.channel, on: openGroup.server, using: transaction)
|
||||
Storage.shared.removeLastDeletionServerID(for: openGroup.channel, on: openGroup.server, using: transaction)
|
||||
let _ = OpenGroupAPI.leave(openGroup.channel, on: openGroup.server)
|
||||
Storage.shared.removeOpenGroupPublicKey(for: openGroup.server, using: transaction)
|
||||
thread.removeAllThreadInteractions(with: transaction)
|
||||
thread.remove(with: transaction)
|
||||
Storage.shared.removeOpenGroup(for: thread.uniqueId!, using: transaction)
|
||||
}
|
||||
}
|
@ -1,2 +1,8 @@
|
||||
|
||||
extension Storage : SessionMessagingKitStorageProtocol, SessionProtocolKitStorageProtocol, SessionSnodeKitStorageProtocol { }
|
||||
extension Storage : SessionMessagingKitStorageProtocol, SessionProtocolKitStorageProtocol, SessionSnodeKitStorageProtocol {
|
||||
|
||||
public func updateMessageIDCollectionByPruningMessagesWithIDs(_ messageIDs: Set<String>, using transaction: Any) {
|
||||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
OWSPrimaryStorage.shared().updateMessageIDCollectionByPruningMessagesWithIDs(messageIDs, in: transaction)
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
import PromiseKit
|
||||
|
||||
public final class OpenGroupManager : OpenGroupManagerProtocol {
|
||||
|
||||
public enum Error : LocalizedError {
|
||||
case invalidURL
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .invalidURL: return "Invalid URL."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static let shared = OpenGroupManager()
|
||||
|
||||
private init() { }
|
||||
|
||||
public func addOpenGroup(with url: String, using transaction: Any) -> Promise<Void> {
|
||||
guard let url = URL(string: url), let scheme = url.scheme, scheme == "https", url.host != nil else {
|
||||
return Promise(error: Error.invalidURL)
|
||||
}
|
||||
let channelID: UInt64 = 1
|
||||
let urlAsString = url.absoluteString
|
||||
let userPublicKey = getUserHexEncodedPublicKey()
|
||||
let profileManager = OWSProfileManager.shared()
|
||||
let displayName = profileManager.profileNameForRecipient(withID: userPublicKey)
|
||||
let profilePictureURL = profileManager.profilePictureURL()
|
||||
let profileKey = profileManager.localProfileKey().keyData
|
||||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
transaction.removeObject(forKey: "\(urlAsString).\(channelID)", inCollection: Storage.lastMessageServerIDCollection)
|
||||
transaction.removeObject(forKey: "\(urlAsString).\(channelID)", inCollection: Storage.lastDeletionServerIDCollection)
|
||||
return PublicChatManager.shared.addChat(server: urlAsString, channel: channelID).done(on: DispatchQueue.main) { _ in
|
||||
let _ = OpenGroupAPI.setDisplayName(to: displayName, on: urlAsString)
|
||||
let _ = OpenGroupAPI.setProfilePictureURL(to: profilePictureURL, using: profileKey, on: urlAsString)
|
||||
let _ = OpenGroupAPI.join(channelID, on: urlAsString)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
import PromiseKit
|
||||
|
||||
// TODO: Clean
|
||||
|
||||
@objc(LKPublicChatManager)
|
||||
public final class PublicChatManager : NSObject {
|
||||
private let storage = OWSPrimaryStorage.shared()
|
||||
@objc public var chats: [String:OpenGroup] = [:]
|
||||
private var pollers: [String:OpenGroupPoller] = [:]
|
||||
private var isPolling = false
|
||||
|
||||
private var userHexEncodedPublicKey: String? {
|
||||
return OWSIdentityManager.shared().identityKeyPair()?.hexEncodedPublicKey
|
||||
}
|
||||
|
||||
public enum Error : Swift.Error {
|
||||
case chatCreationFailed
|
||||
case userPublicKeyNotFound
|
||||
}
|
||||
|
||||
@objc public static let shared = PublicChatManager()
|
||||
|
||||
private override init() {
|
||||
super.init()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(onThreadDeleted(_:)), name: .threadDeleted, object: nil)
|
||||
refreshChatsAndPollers()
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
@objc public func startPollersIfNeeded() {
|
||||
for (threadID, publicChat) in chats {
|
||||
if let poller = pollers[threadID] {
|
||||
poller.startIfNeeded()
|
||||
} else {
|
||||
let poller = OpenGroupPoller(for: publicChat)
|
||||
poller.startIfNeeded()
|
||||
pollers[threadID] = poller
|
||||
}
|
||||
}
|
||||
isPolling = true
|
||||
}
|
||||
|
||||
@objc public func stopPollers() {
|
||||
for poller in pollers.values { poller.stop() }
|
||||
isPolling = false
|
||||
}
|
||||
|
||||
public func addChat(server: String, channel: UInt64) -> Promise<OpenGroup> {
|
||||
if let existingChat = getChat(server: server, channel: channel) {
|
||||
if let newChat = self.addChat(server: server, channel: channel, name: existingChat.displayName) {
|
||||
return Promise.value(newChat)
|
||||
} else {
|
||||
return Promise(error: Error.chatCreationFailed)
|
||||
}
|
||||
}
|
||||
return OpenGroupAPI.getInfo(for: channel, on: server).map2 { channelInfo -> OpenGroup in
|
||||
guard let chat = self.addChat(server: server, channel: channel, name: channelInfo.displayName) else { throw Error.chatCreationFailed }
|
||||
return chat
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
@objc(addChatWithServer:channel:name:)
|
||||
public func addChat(server: String, channel: UInt64, name: String) -> OpenGroup? {
|
||||
guard let chat = OpenGroup(channel: channel, server: server, displayName: name, isDeletable: true) else { return nil }
|
||||
let model = TSGroupModel(title: chat.displayName, memberIds: [userHexEncodedPublicKey!, chat.server], image: nil, groupId: LKGroupUtilities.getEncodedOpenGroupIDAsData(chat.id), groupType: .openGroup, adminIds: [])
|
||||
|
||||
// Store the group chat mapping
|
||||
Storage.writeSync { transaction in
|
||||
let thread = TSGroupThread.getOrCreateThread(with: model, transaction: transaction)
|
||||
|
||||
// Save the group chat
|
||||
Storage.shared.setOpenGroup(chat, for: thread.uniqueId!, using: transaction)
|
||||
}
|
||||
|
||||
// Update chats and pollers
|
||||
self.refreshChatsAndPollers()
|
||||
|
||||
return chat
|
||||
}
|
||||
|
||||
@objc(addChatWithServer:channel:)
|
||||
public func objc_addChat(server: String, channel: UInt64) -> AnyPromise {
|
||||
return AnyPromise.from(addChat(server: server, channel: channel))
|
||||
}
|
||||
|
||||
@objc func refreshChatsAndPollers() {
|
||||
let newChats = Storage.shared.getAllUserOpenGroups()
|
||||
|
||||
// Remove any chats that don't exist in the database
|
||||
let removedChatThreadIds = self.chats.keys.filter { !newChats.keys.contains($0) }
|
||||
removedChatThreadIds.forEach { threadID in
|
||||
let poller = self.pollers.removeValue(forKey: threadID)
|
||||
poller?.stop()
|
||||
}
|
||||
|
||||
// Only append to chats if we have a thread for the chat
|
||||
self.chats = newChats.filter { (threadID, group) in
|
||||
return TSGroupThread.fetch(uniqueId: threadID) != nil
|
||||
}
|
||||
|
||||
if (isPolling) { startPollersIfNeeded() }
|
||||
}
|
||||
|
||||
@objc private func onThreadDeleted(_ notification: Notification) {
|
||||
guard let threadId = notification.userInfo?["threadId"] as? String else { return }
|
||||
|
||||
// Reset the last message cache
|
||||
if let chat = self.chats[threadId] {
|
||||
Storage.write { transaction in
|
||||
Storage.shared.clearAllData(for: chat.channel, on: chat.server, using: transaction)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the chat from the db
|
||||
Storage.write { transaction in
|
||||
Storage.shared.removeOpenGroup(for: threadId, using: transaction)
|
||||
}
|
||||
|
||||
refreshChatsAndPollers()
|
||||
}
|
||||
|
||||
public func getChat(server: String, channel: UInt64) -> OpenGroup? {
|
||||
return chats.values.first { chat in
|
||||
return chat.server == server && chat.channel == channel
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue