| 
							
								 | 
							
							// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
 | 
						
						
						
						
							 | 
							
								 | 
							
							//
 | 
						
						
						
						
							 | 
							
								 | 
							
							// stringlint:disable
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							import Foundation
 | 
						
						
						
						
							 | 
							
								 | 
							
							import GRDB
 | 
						
						
						
						
							 | 
							
								 | 
							
							import SessionUtilitiesKit
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							public struct OpenGroup: Codable, Identifiable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible {
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public static var databaseTableName: String { "openGroup" }
 | 
						
						
						
						
							 | 
							
								 | 
							
							    internal static let threadForeignKey = ForeignKey([Columns.threadId], to: [SessionThread.Columns.id])
 | 
						
						
						
						
							 | 
							
								 | 
							
							    private static let thread = belongsTo(SessionThread.self, using: threadForeignKey)
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public static let members = hasMany(GroupMember.self, using: GroupMember.openGroupForeignKey)
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public typealias Columns = CodingKeys
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public enum CodingKeys: String, CodingKey, ColumnExpression {
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case threadId
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case server
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case roomToken
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case publicKey
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case name
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case isActive
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case roomDescription = "description"
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case imageId
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case imageData
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case userCount
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case infoUpdates
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case sequenceNumber
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case inboxLatestMessageId
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case outboxLatestMessageId
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case pollFailureCount
 | 
						
						
						
						
							 | 
							
								 | 
							
							        case permissions
 | 
						
						
						
						
							 | 
							
								 | 
							
							    }
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public struct Permissions: OptionSet, Codable, DatabaseValueConvertible, Hashable {
 | 
						
						
						
						
							 | 
							
								 | 
							
							        public let rawValue: UInt16
 | 
						
						
						
						
							 | 
							
								 | 
							
							        
 | 
						
						
						
						
							 | 
							
								 | 
							
							        public init(rawValue: UInt16) {
 | 
						
						
						
						
							 | 
							
								 | 
							
							            self.rawValue = rawValue
 | 
						
						
						
						
							 | 
							
								 | 
							
							        }
 | 
						
						
						
						
							 | 
							
								 | 
							
							        
 | 
						
						
						
						
							 | 
							
								 | 
							
							        public init(roomInfo: OpenGroupAPI.RoomPollInfo) {
 | 
						
						
						
						
							 | 
							
								 | 
							
							            var permissions: Permissions = []
 | 
						
						
						
						
							 | 
							
								 | 
							
							            
 | 
						
						
						
						
							 | 
							
								 | 
							
							            if roomInfo.read { permissions.insert(.read) }
 | 
						
						
						
						
							 | 
							
								 | 
							
							            if roomInfo.write { permissions.insert(.write) }
 | 
						
						
						
						
							 | 
							
								 | 
							
							            if roomInfo.upload { permissions.insert(.upload) }
 | 
						
						
						
						
							 | 
							
								 | 
							
							            
 | 
						
						
						
						
							 | 
							
								 | 
							
							            self.init(rawValue: permissions.rawValue)
 | 
						
						
						
						
							 | 
							
								 | 
							
							        }
 | 
						
						
						
						
							 | 
							
								 | 
							
							        
 | 
						
						
						
						
							 | 
							
								 | 
							
							        public func toString() -> String {
 | 
						
						
						
						
							 | 
							
								 | 
							
							            return ""
 | 
						
						
						
						
							 | 
							
								 | 
							
							                .appending(self.contains(.read) ? "r" : "-")
 | 
						
						
						
						
							 | 
							
								 | 
							
							                .appending(self.contains(.write) ? "w" : "-")
 | 
						
						
						
						
							 | 
							
								 | 
							
							                .appending(self.contains(.upload) ? "u" : "-")
 | 
						
						
						
						
							 | 
							
								 | 
							
							        }
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							        static let read: Permissions = Permissions(rawValue: 1 << 0)
 | 
						
						
						
						
							 | 
							
								 | 
							
							        static let write: Permissions = Permissions(rawValue: 1 << 1)
 | 
						
						
						
						
							 | 
							
								 | 
							
							        static let upload: Permissions = Permissions(rawValue: 1 << 2)
 | 
						
						
						
						
							 | 
							
								 | 
							
							        
 | 
						
						
						
						
							 | 
							
								 | 
							
							        static let all: Permissions = [ .read, .write, .upload ]
 | 
						
						
						
						
							 | 
							
								 | 
							
							    }
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The Community public key takes up 32 bytes
 | 
						
						
						
						
							 | 
							
								 | 
							
							    static let pubkeyByteLength: Int = 32
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public var id: String { threadId }  // Identifiable
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The id for the thread this open group belongs to
 | 
						
						
						
						
							 | 
							
								 | 
							
							    ///
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// **Note:** This value will always be `\(server).\(room)` (This needs it’s own column to
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// allow for db joining to the Thread table)
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let threadId: String
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The server for the group
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let server: String
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The specific room on the server for the group
 | 
						
						
						
						
							 | 
							
								 | 
							
							    ///
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// **Note:** In order to support the default open group query we need an OpenGroup entry in
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// the database, for this entry the `roomToken` value will be an empty string so we can ignore
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// it when polling
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let roomToken: String
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The public key for the group
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let publicKey: String
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// Flag indicating whether this is an OpenGroup the user has actively joined (we store inactive
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// open groups so we can display them in the UI but they won't be polled for)
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let isActive: Bool
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The name for the group
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let name: String
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The description for the room
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let roomDescription: String?
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The ID with which the image can be retrieved from the server
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let imageId: String?
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The image for the group
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let imageData: Data?
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The number of users in the group
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let userCount: Int64
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// Monotonic room information counter that increases each time the room's metadata changes
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let infoUpdates: Int64
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// Sequence number for the most recently received message from the open group
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let sequenceNumber: Int64
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The id of the most recently received inbox message
 | 
						
						
						
						
							 | 
							
								 | 
							
							    ///
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// **Note:** This value is unique per server rather than per room (ie. all rooms in the same server will be
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// updated whenever this value changes)
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let inboxLatestMessageId: Int64
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The id of the most recently received outbox message
 | 
						
						
						
						
							 | 
							
								 | 
							
							    ///
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// **Note:** This value is unique per server rather than per room (ie. all rooms in the same server will be
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// updated whenever this value changes)
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let outboxLatestMessageId: Int64
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The number of times this room has failed to poll since the last successful poll
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let pollFailureCount: Int64
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    /// The permissions this room has for current user
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public let permissions: Permissions?
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    // MARK: - Relationships
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public var thread: QueryInterfaceRequest<SessionThread> {
 | 
						
						
						
						
							 | 
							
								 | 
							
							        request(for: OpenGroup.thread)
 | 
						
						
						
						
							 | 
							
								 | 
							
							    }
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public var moderatorIds: QueryInterfaceRequest<GroupMember> {
 | 
						
						
						
						
							 | 
							
								 | 
							
							        request(for: OpenGroup.members)
 | 
						
						
						
						
							 | 
							
								 | 
							
							            .filter(GroupMember.Columns.role == GroupMember.Role.moderator)
 | 
						
						
						
						
							 | 
							
								 | 
							
							    }
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public var adminIds: QueryInterfaceRequest<GroupMember> {
 | 
						
						
						
						
							 | 
							
								 | 
							
							        request(for: OpenGroup.members)
 | 
						
						
						
						
							 | 
							
								 | 
							
							            .filter(GroupMember.Columns.role == GroupMember.Role.admin)
 | 
						
						
						
						
							 | 
							
								 | 
							
							    }
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    // MARK: - Initialization
 | 
						
						
						
						
							 | 
							
								 | 
							
							    
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public init(
 | 
						
						
						
						
							 | 
							
								 | 
							
							        server: String,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        roomToken: String,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        publicKey: String,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        isActive: Bool,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        name: String,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        roomDescription: String? = nil,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        imageId: String? = nil,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        imageData: Data? = nil,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        userCount: Int64,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        infoUpdates: Int64,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        sequenceNumber: Int64 = 0,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        inboxLatestMessageId: Int64 = 0,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        outboxLatestMessageId: Int64 = 0,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        pollFailureCount: Int64 = 0,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        permissions: Permissions? = nil
 | 
						
						
						
						
							 | 
							
								 | 
							
							    ) {
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.threadId = OpenGroup.idFor(roomToken: roomToken, server: server)
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.server = server.lowercased()
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.roomToken = roomToken
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.publicKey = publicKey
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.isActive = isActive
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.name = name
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.roomDescription = roomDescription
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.imageId = imageId
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.imageData = imageData
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.userCount = userCount
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.infoUpdates = infoUpdates
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.sequenceNumber = sequenceNumber
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.inboxLatestMessageId = inboxLatestMessageId
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.outboxLatestMessageId = outboxLatestMessageId
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.pollFailureCount = pollFailureCount
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self.permissions = permissions
 | 
						
						
						
						
							 | 
							
								 | 
							
							    }
 | 
						
						
						
						
							 | 
							
								 | 
							
							}
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							// MARK: - GRDB Interactions
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							public extension OpenGroup {
 | 
						
						
						
						
							 | 
							
								 | 
							
							    static func fetchOrCreate(
 | 
						
						
						
						
							 | 
							
								 | 
							
							        _ db: Database,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        server: String,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        roomToken: String,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        publicKey: String
 | 
						
						
						
						
							 | 
							
								 | 
							
							    ) -> OpenGroup {
 | 
						
						
						
						
							 | 
							
								 | 
							
							        guard let existingGroup: OpenGroup = try? OpenGroup.fetchOne(db, id: OpenGroup.idFor(roomToken: roomToken, server: server)) else {
 | 
						
						
						
						
							 | 
							
								 | 
							
							            return OpenGroup(
 | 
						
						
						
						
							 | 
							
								 | 
							
							                server: server,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                roomToken: roomToken,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                publicKey: publicKey,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                isActive: false,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                name: roomToken,    // Default the name to the `roomToken` until we get retrieve the actual name
 | 
						
						
						
						
							 | 
							
								 | 
							
							                roomDescription: nil,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                imageId: nil,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                imageData: nil,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                userCount: 0,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                infoUpdates: 0,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                sequenceNumber: 0,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                inboxLatestMessageId: 0,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                outboxLatestMessageId: 0,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                pollFailureCount: 0,
 | 
						
						
						
						
							 | 
							
								 | 
							
							                permissions: nil
 | 
						
						
						
						
							 | 
							
								 | 
							
							            )
 | 
						
						
						
						
							 | 
							
								 | 
							
							        }
 | 
						
						
						
						
							 | 
							
								 | 
							
							        
 | 
						
						
						
						
							 | 
							
								 | 
							
							        return existingGroup
 | 
						
						
						
						
							 | 
							
								 | 
							
							    }
 | 
						
						
						
						
							 | 
							
								 | 
							
							}
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							// MARK: - Search Queries
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							public extension OpenGroup {
 | 
						
						
						
						
							 | 
							
								 | 
							
							    struct FullTextSearch: Decodable, ColumnExpressible {
 | 
						
						
						
						
							 | 
							
								 | 
							
							        public typealias Columns = CodingKeys
 | 
						
						
						
						
							 | 
							
								 | 
							
							        public enum CodingKeys: String, CodingKey, ColumnExpression, CaseIterable {
 | 
						
						
						
						
							 | 
							
								 | 
							
							            case name
 | 
						
						
						
						
							 | 
							
								 | 
							
							        }
 | 
						
						
						
						
							 | 
							
								 | 
							
							        
 | 
						
						
						
						
							 | 
							
								 | 
							
							        let name: String
 | 
						
						
						
						
							 | 
							
								 | 
							
							    }
 | 
						
						
						
						
							 | 
							
								 | 
							
							}
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							// MARK: - Convenience
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							public extension OpenGroup {
 | 
						
						
						
						
							 | 
							
								 | 
							
							    static func idFor(roomToken: String, server: String) -> String {
 | 
						
						
						
						
							 | 
							
								 | 
							
							        // Always force the server to lowercase
 | 
						
						
						
						
							 | 
							
								 | 
							
							        return "\(server.lowercased()).\(roomToken)"
 | 
						
						
						
						
							 | 
							
								 | 
							
							    }
 | 
						
						
						
						
							 | 
							
								 | 
							
							}
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							extension OpenGroup: CustomStringConvertible, CustomDebugStringConvertible {
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public var description: String { "\(name) (Server: \(server), Room: \(roomToken))" }
 | 
						
						
						
						
							 | 
							
								 | 
							
							    public var debugDescription: String {
 | 
						
						
						
						
							 | 
							
								 | 
							
							        [
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "OpenGroup(server: \"\(server)\"",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "roomToken: \"\(roomToken)\"",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "id: \"\(id)\"",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "publicKey: \"\(publicKey)\"",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "isActive: \(isActive)",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "name: \"\(name)\"",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "roomDescription: \(roomDescription.map { "\"\($0)\"" } ?? "null")",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "imageId: \(imageId ?? "null")",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "userCount: \(userCount)",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "infoUpdates: \(infoUpdates)",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "sequenceNumber: \(sequenceNumber)",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "inboxLatestMessageId: \(inboxLatestMessageId)",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "outboxLatestMessageId: \(outboxLatestMessageId)",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "pollFailureCount: \(pollFailureCount)",
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "permissions: \(permissions?.toString() ?? "---"))"
 | 
						
						
						
						
							 | 
							
								 | 
							
							        ].joined(separator: ", ")
 | 
						
						
						
						
							 | 
							
								 | 
							
							    }
 | 
						
						
						
						
							 | 
							
								 | 
							
							}
 |