You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-ios/SessionSnodeKit/Types/SnodeAPINamespace.swift

174 lines
7.5 KiB
Swift

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
//
// stringlint:disable
import Foundation
public extension SnodeAPI {
enum Namespace: Int, Codable, Hashable, CustomStringConvertible {
case `default` = 0
case configUserProfile = 2
case configContacts = 3
case configConvoInfoVolatile = 4
case configUserGroups = 5
case configClosedGroupInfo = 11
case legacyClosedGroup = -10
/// This is used when we somehow receive a message from an unknown namespace (shouldn't really be possible)
case unknown = -9999989
/// This is a convenience namespace used to represent all other namespaces for specific API calls
case all = -9999990
// MARK: Variables
var requiresReadAuthentication: Bool {
switch self {
// Legacy closed groups don't support authenticated retrieval
case .legacyClosedGroup: return false
default: return true
}
}
var requiresWriteAuthentication: Bool {
switch self {
// Legacy closed groups don't support authenticated storage
case .legacyClosedGroup: return false
default: return true
}
}
/// This flag indicates whether we should provide a `lastHash` when retrieving messages from the specified
/// namespace, when `true` we will only receive messages added since the provided `lastHash`, otherwise
/// we will retrieve **all** messages from the namespace
public var shouldFetchSinceLastHash: Bool { true }
/// This flag indicates whether we should dedupe messages from the specified namespace, when `true` we will
/// attempt to `insert` a `SnodeReceivedMessageInfo` record (which will fail if we had already processed this
/// message previously), when `false` we will still `upsert` a record so we don't run into the unique constraint allowing
/// re-processing of a previously processed message
public var shouldDedupeMessages: Bool {
switch self {
case .`default`, .legacyClosedGroup: return true
case .configUserProfile, .configContacts,
.configConvoInfoVolatile, .configUserGroups,
.configClosedGroupInfo, .unknown, .all:
return false
}
}
var verificationString: String {
switch self {
case .`default`: return ""
case .all: return "all"
default: return "\(self.rawValue)"
}
}
public var isConfigNamespace: Bool {
switch self {
case .configUserProfile, .configContacts, .configConvoInfoVolatile, .configUserGroups,
.configClosedGroupInfo:
return true
case .`default`, .legacyClosedGroup, .unknown, .all:
return false
}
}
/// This value defines the order that the SharedConfigMessages should be processed in, while we re-process config
/// messages every time we poll this will prevent an edge-case where data/logic between different config messages
/// could be dependant on each other (eg. there could be `convoInfoVolatile` data related to a new conversation
/// which hasn't been created yet because it's associated `contacts`/`userGroups` message hasn't yet been
/// processed (without this we would have to wait until the next poll for it to be processed correctly)
public var processingOrder: Int {
switch self {
case .configUserProfile, .configContacts: return 0
case .configUserGroups, .configClosedGroupInfo: return 1
case .configConvoInfoVolatile: return 2
case .`default`, .legacyClosedGroup, .unknown, .all:
return 3
}
}
/// Flag which indicates whether messages from this namespace should be handled synchronously as part of the polling process
/// or whether they can be scheduled to be handled asynchronously
public var shouldHandleSynchronously: Bool {
switch self {
case .`default`, .legacyClosedGroup, .configUserProfile, .configContacts,
.configConvoInfoVolatile, .configUserGroups, .configClosedGroupInfo,
.unknown, .all:
return false
}
}
/// When performing a batch request we want to try to use the amount of data available in the response as effectively as possible
/// this priority allows us to split the response effectively between the number of namespaces we are requesting from where
/// namespaces with the same priority will be given the same response size divider, for example:
/// ```
/// default = 1
/// config1, config2 = 2
/// config3, config4 = 3
///
/// Response data split:
/// _____________________________
/// | |
/// | default |
/// |_____________________________|
/// | | | config3 |
/// | config1 | config2 | config4 |
/// |_________|_________|_________|
///
var batchRequestSizePriority: Int64 {
switch self {
case .`default`, .legacyClosedGroup: return 10
case .configUserProfile, .configContacts,
.configConvoInfoVolatile, .configUserGroups,
.configClosedGroupInfo, .unknown, .all:
return 1
}
}
static func maxSizeMap(for namespaces: [Namespace]) -> [Namespace: Int64] {
var lastSplit: Int64 = 1
let namespacePriorityGroups: [Int64: [Namespace]] = namespaces
.grouped { $0.batchRequestSizePriority }
let lowestPriority: Int64 = (namespacePriorityGroups.keys.min() ?? 1)
return namespacePriorityGroups
.map { $0 }
.sorted(by: { lhs, rhs -> Bool in lhs.key > rhs.key })
.flatMap { priority, namespaces -> [(namespace: Namespace, maxSize: Int64)] in
lastSplit *= Int64(namespaces.count + (priority == lowestPriority ? 0 : 1))
return namespaces.map { ($0, lastSplit) }
}
.reduce(into: [:]) { result, next in
result[next.namespace] = -next.maxSize
}
}
// MARK: - CustomStringConvertible
public var description: String {
switch self {
case .`default`: return "default"
case .configUserProfile: return "configUserProfile"
case .configContacts: return "configContacts"
case .configConvoInfoVolatile: return "configConvoInfoVolatile"
case .configUserGroups: return "configUserGroups"
case .configClosedGroupInfo: return "configClosedGroupInfo"
case .legacyClosedGroup: return "legacyClosedGroup"
case .unknown: return "unknown"
case .all: return "all"
}
}
}
}