WIP: make group leaving a job

This commit is contained in:
ryanzhao 2023-03-14 17:08:38 +11:00
parent eed8b1dfcb
commit cea2e1522d
8 changed files with 40 additions and 146 deletions

View File

@ -451,11 +451,12 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
Storage.shared
.writeAsync { db in
if !updatedMemberIds.contains(userPublicKey) {
return try MessageSender
.leave(db, groupPublicKey: threadId)
.map { (_, error) in
if let error: Error = error { throw error }
}
try MessageSender.leave(
db,
groupPublicKey: threadId,
deleteThread: false
)
return Promise.value(())
}
return try MessageSender.update(

View File

@ -405,7 +405,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
),
onTap: { [weak self] in
dependencies.storage.writeAsync { db in
try MessageSender.leave(db, groupPublicKey: threadId)
try MessageSender.leave(db, groupPublicKey: threadId, deleteThread: false)
}
}
)

View File

@ -305,28 +305,11 @@ public class HomeViewModel {
Storage.shared.writeAsync { db in
switch threadVariant {
case .closedGroup:
try MessageSender
.leave(db, groupPublicKey: threadId)
.done { (interactionId, error) in
Storage.shared.writeAsync { db in
if let _ = error {
try Interaction
.filter(id: interactionId)
.updateAll(
db,
[
Interaction.Columns.variant.set(to: Interaction.Variant.infoClosedGroupCurrentUserErrorLeaving),
Interaction.Columns.body.set(to: "group_unable_to_leave".localized())
]
)
} else {
_ = try SessionThread
.filter(id: threadId)
.deleteAll(db)
}
}
}
.retainUntilComplete()
try MessageSender.leave(
db,
groupPublicKey: threadId,
deleteThread: true
)
case .openGroup:
OpenGroupManager.shared.delete(db, openGroupId: threadId)

View File

@ -46,5 +46,6 @@ public enum SNMessagingKit { // Just to make the external API nice
JobRunner.add(executor: SendReadReceiptsJob.self, for: .sendReadReceipts)
JobRunner.add(executor: AttachmentDownloadJob.self, for: .attachmentDownload)
JobRunner.add(executor: AttachmentUploadJob.self, for: .attachmentUpload)
JobRunner.add(executor: GroupLeavingJob.self, for: .groupLeaving)
}
}

View File

@ -21,7 +21,8 @@ public enum GroupLeavingJob: JobExecutor {
{
guard
let detailsData: Data = job.details,
let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData)
let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData),
let interactionId: Int64 = job.interactionId
else {
failure(job, JobRunnerError.missingRequiredDetails, false)
return
@ -44,7 +45,7 @@ public enum GroupLeavingJob: JobExecutor {
message: ClosedGroupControlMessage(
kind: .memberLeft
),
interactionId: details.infoMessageInteractionId,
interactionId: interactionId,
in: thread
)
}
@ -66,7 +67,7 @@ public enum GroupLeavingJob: JobExecutor {
)
try Interaction
.filter(id: details.infoMessageInteractionId)
.filter(id: interactionId)
.updateAll(
db,
[
@ -94,7 +95,7 @@ public enum GroupLeavingJob: JobExecutor {
.deleteAll(db)
}
if details.deleteThreadAfterSuccess {
if details.deleteThread {
_ = try SessionThread
.filter(id: thread.id)
.deleteAll(db)
@ -105,7 +106,7 @@ public enum GroupLeavingJob: JobExecutor {
.catch(on: queue) { error in
Storage.shared.write { db in
try Interaction
.filter(id: details.infoMessageInteractionId)
.filter(id: job.interactionId)
.updateAll(
db,
[
@ -125,25 +126,21 @@ public enum GroupLeavingJob: JobExecutor {
extension GroupLeavingJob {
public struct Details: Codable {
private enum CodingKeys: String, CodingKey {
case infoMessageInteractionId
case groupPublicKey
case deleteThreadAfterSuccess
case deleteThread
}
public let infoMessageInteractionId: Int64
public let groupPublicKey: String
public let deleteThreadAfterSuccess: Bool
public let deleteThread: Bool
// MARK: - Initialization
public init(
infoMessageInteractionId: Int64,
groupPublicKey: String,
deleteThreadAfterSuccess: Bool
deleteThread: Bool
) {
self.infoMessageInteractionId = infoMessageInteractionId
self.groupPublicKey = groupPublicKey
self.deleteThreadAfterSuccess = deleteThreadAfterSuccess
self.deleteThread = deleteThread
}
// MARK: - Codable
@ -152,18 +149,16 @@ extension GroupLeavingJob {
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
self = Details(
infoMessageInteractionId: try container.decode(Int64.self, forKey: .infoMessageInteractionId),
groupPublicKey: try container.decode(String.self, forKey: .groupPublicKey),
deleteThreadAfterSuccess: try container.decode(Bool.self, forKey: .deleteThreadAfterSuccess)
deleteThread: try container.decode(Bool.self, forKey: .deleteThread)
)
}
public func encode(to encoder: Encoder) throws {
var container: KeyedEncodingContainer<CodingKeys> = encoder.container(keyedBy: CodingKeys.self)
try container.encode(infoMessageInteractionId, forKey: .infoMessageInteractionId)
try container.encode(groupPublicKey, forKey: .groupPublicKey)
try container.encode(deleteThreadAfterSuccess, forKey: .deleteThreadAfterSuccess)
try container.encode(deleteThread, forKey: .deleteThread)
}
}
}

View File

@ -478,13 +478,9 @@ extension MessageSender {
/// unregisters from push notifications.
///
/// The returned promise is fulfilled when the `MEMBER_LEFT` message has been sent to the group.
public static func leave(_ db: Database, groupPublicKey: String) throws -> Promise<(Int64, Error?)> {
public static func leave(_ db: Database, groupPublicKey: String, deleteThread: Bool) throws {
guard let thread: SessionThread = try? SessionThread.fetchOne(db, id: groupPublicKey) else {
SNLog("Can't leave nonexistent closed group.")
return Promise(error: MessageSenderError.noThread)
}
guard let closedGroup: ClosedGroup = try? thread.closedGroup.fetchOne(db) else {
return Promise(error: MessageSenderError.invalidClosedGroupUpdate)
return
}
let userPublicKey: String = getUserHexEncodedPublicKey(db)
@ -498,78 +494,18 @@ extension MessageSender {
timestampMs: SnodeAPI.currentOffsetTimestampMs()
).inserted(db)
guard let interactionId: Int64 = interaction.id else {
throw StorageError.objectNotSaved
}
// Send the update to the group
let (promise, seal) = Promise<(Int64, Error?)>.pending()
do {
try MessageSender
.sendNonDurably(
db,
message: ClosedGroupControlMessage(
kind: .memberLeft
),
interactionId: interactionId,
in: thread
JobRunner.add(
db,
job: Job(
variant: .groupLeaving,
threadId: thread.id,
interactionId: interaction.id,
details: GroupLeavingJob.Details(
groupPublicKey: groupPublicKey,
deleteThread: deleteThread
)
.done {
// Remove the group from the database and unsubscribe from PNs
ClosedGroupPoller.shared.stopPolling(for: groupPublicKey)
Storage.shared.write { db in
try closedGroup
.keyPairs
.deleteAll(db)
let _ = PushNotificationAPI.performOperation(
.unsubscribe,
for: groupPublicKey,
publicKey: userPublicKey
)
try Interaction
.filter(id: interactionId)
.updateAll(
db,
[
Interaction.Columns.variant.set(to: Interaction.Variant.infoClosedGroupCurrentUserLeft),
Interaction.Columns.body.set(to: "GROUP_YOU_LEFT".localized())
]
)
// Update the group (if the admin leaves the group is disbanded)
let wasAdminUser: Bool = try GroupMember
.filter(GroupMember.Columns.groupId == thread.id)
.filter(GroupMember.Columns.profileId == userPublicKey)
.filter(GroupMember.Columns.role == GroupMember.Role.admin)
.isNotEmpty(db)
if wasAdminUser {
try GroupMember
.filter(GroupMember.Columns.groupId == thread.id)
.deleteAll(db)
}
else {
try GroupMember
.filter(GroupMember.Columns.groupId == thread.id)
.filter(GroupMember.Columns.profileId == userPublicKey)
.deleteAll(db)
}
}
seal.fulfill((interactionId, nil))
}
.catch { error in
seal.fulfill((interactionId, error))
}
}
catch {
seal.fulfill((interactionId, error))
}
// Return
return promise
)
)
}
/*

View File

@ -763,26 +763,3 @@ public final class MessageSender {
}
}
}
// MARK: - Objective-C Support
// FIXME: Remove when possible
@objc(SMKMessageSender)
public class SMKMessageSender: NSObject {
@objc(leaveClosedGroupWithPublicKey:)
public static func objc_leave(_ groupPublicKey: String) -> AnyPromise {
let promise = Storage.shared.writeAsync { db in
try MessageSender.leave(db, groupPublicKey: groupPublicKey)
}
return AnyPromise.from(promise)
}
@objc(forceSyncConfigurationNow)
public static func objc_forceSyncConfigurationNow() {
Storage.shared.write { db in
try MessageSender.syncConfiguration(db, forceSyncNow: true).retainUntilComplete()
}
}
}

View File

@ -66,7 +66,8 @@ public final class JobRunner {
jobVariants.remove(.attachmentUpload),
jobVariants.remove(.messageSend),
jobVariants.remove(.notifyPushServer),
jobVariants.remove(.sendReadReceipts)
jobVariants.remove(.sendReadReceipts),
jobVariants.remove(.groupLeaving)
].compactMap { $0 }
)
let messageReceiveQueue: JobQueue = JobQueue(