sdk/communication/AzureCommunicationChat/Source/Signaling/Events/ChatEvent.swift (589 lines of code) (raw):
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import AzureCommunicationCommon
import AzureCore
import Foundation
import Trouter
/// Chat Participant for real-time notification events.
public struct SignalingChatParticipant {
// MARK: Properties
/// The identifier of the participant.
public let id: CommunicationIdentifier?
/// Display name for the participant.
public let displayName: String?
/// Time from which the chat history is shared with the participant. The timestamp is in RFC3339 format:
/// `yyyy-MM-ddTHH:mm:ssZ`.
public let shareHistoryTime: Iso8601Date?
// MARK: Initializers
/// Initialize a SignalingChatParticipant
/// - Parameters:
/// - id: The identifier of the participant.
/// - displayName: Display name for the participant.
/// - shareHistoryTime: Time from which the chat history is shared with the participant. The timestamp is in
/// RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.
init(id: CommunicationIdentifier?, displayName: String? = nil, shareHistoryTime: Iso8601Date? = nil) {
self.id = id
self.displayName = displayName
self.shareHistoryTime = shareHistoryTime
}
}
/// ChatThreadProperties for real-time notification events.
public struct SignalingChatThreadProperties {
// MARK: Properties
/// Thread topic.
public let topic: String
// MARK: Initializers
/// Initialize a SignalingChatThreadProperties
/// - Parameter topic: Thread topic.
init(topic: String) {
self.topic = topic
}
}
/// BaseChatEvent for real-time notifications.
public class BaseChatEvent {
// MARK: Properties
/// Chat thread id.
public var threadId: String
/// Sender identifier.
public var sender: CommunicationIdentifier?
/// Recipient identifier.
public var recipient: CommunicationIdentifier?
// MARK: Initializers
/// Initialize a BaseChatEvent
/// - Parameters:
/// - threadId: ChatThread id.
/// - sender: Sender identifier.
/// - recipient: Recipient identifier.
init(
threadId: String,
sender: CommunicationIdentifier?,
recipient: CommunicationIdentifier?
) {
self.threadId = threadId
self.sender = sender
self.recipient = recipient
}
}
/// BaseChatThreadEvent for real-time notifications.
public class BaseChatThreadEvent {
// MARK: Properties
/// Chat thread id.
public var threadId: String
/// Version of the thread.
public var version: String
// MARK: Initializers
/// Initialize a BaseChatThreadEvent
/// - Parameters:
/// - threadId: ChatThread id.
/// - version: Version of the thread.
init(threadId: String, version: String) {
self.threadId = threadId
self.version = version
}
}
/// BaseChatMessageEvent for real-time notifications.
public class BaseChatMessageEvent: BaseChatEvent {
// MARK: Properties
/// The id of the message. This id is server generated.
public var id: String
/// The timestamp when the message arrived at the server. The timestamp is in RFC3339 format:
/// `yyyy-MM-ddTHH:mm:ssZ`.
public var createdOn: Iso8601Date?
/// Version of the message.
public var version: String
/// The message type.
public var type: ChatMessageType
/// Sender display name.
public var senderDisplayName: String?
// MARK: Initializers
/// Initialize a BaseChatMessageEvent.
/// - Parameters:
/// - threadId: Chat thread id.
/// - sender: Sender identifier.
/// - recipient: Recipient identifier.
/// - id: Message id.
/// - senderDisplayName: Sender display name.
/// - createdOn: Time that the message was created.
/// - version: Message version.
/// - type: Message type.
init(
threadId: String,
sender: CommunicationIdentifier?,
recipient: CommunicationIdentifier?,
id: String,
senderDisplayName: String? = nil,
createdOn: Iso8601Date? = nil,
version: String,
type: ChatMessageType
) {
self.id = id
self.createdOn = createdOn
self.version = version
self.type = type
self.senderDisplayName = senderDisplayName
super.init(threadId: threadId, sender: sender, recipient: recipient)
}
}
/// ChatMessageReceivedEvent for real-time notifications.
public class ChatMessageReceivedEvent: BaseChatMessageEvent {
// MARK: Properties
/// The content of the message.
public var message: String
/// The message metadata.
public var metadata: [String: String?]?
// MARK: Initializers
/// Initialize a ChatMessageReceivedEvent.
/// - Parameters:
/// - threadId: Chat thread id.
/// - sender: Sender identifier.
/// - recipient: Recipient identifier.
/// - id: Message id.
/// - senderDisplayName: Sender display name.
/// - createdOn: Time that the message was created.
/// - version: Message version.
/// - type: Message type.
/// - message: Message content.
init(
threadId: String,
sender: CommunicationIdentifier?,
recipient: CommunicationIdentifier?,
id: String,
senderDisplayName: String? = nil,
createdOn: Iso8601Date?,
version: String,
type: ChatMessageType,
message: String,
metadata: [String: String?]? = nil
) {
self.message = message
self.metadata = metadata
super.init(
threadId: threadId,
sender: sender,
recipient: recipient,
id: id,
senderDisplayName: senderDisplayName,
createdOn: createdOn,
version: version,
type: type
)
}
/// Initialize a ChatMessageReceivedEvent from a TrouterRequest
/// - Parameter request: The TrouterRequest.
init(from request: TrouterRequest) throws {
guard let requestJsonData = request.body.data(using: .utf8) else {
throw AzureError.client("Unable to convert request body to Data.")
}
let messageReceivedPayload: MessageReceivedPayload = try JSONDecoder()
.decode(MessageReceivedPayload.self, from: requestJsonData)
self.message = messageReceivedPayload.messageBody
if messageReceivedPayload.acsChatMessageMetadata != "null" {
if let acsChatMetadata = messageReceivedPayload.acsChatMessageMetadata.data(using: .utf8) {
self.metadata = try JSONDecoder().decode([String: String?].self, from: acsChatMetadata)
}
}
super.init(
threadId: messageReceivedPayload.groupId,
sender: createCommunicationIdentifier(fromRawId: messageReceivedPayload.senderId),
recipient: createCommunicationIdentifier(fromRawId: messageReceivedPayload.recipientMri),
id: messageReceivedPayload.messageId,
senderDisplayName: messageReceivedPayload.senderDisplayName,
createdOn: Iso8601Date(string: messageReceivedPayload.originalArrivalTime),
version: messageReceivedPayload.version,
type: ChatMessageType(messageReceivedPayload.messageType)
)
}
}
/// ChatMessageEditedEvent for real-time notifications.
public class ChatMessageEditedEvent: BaseChatMessageEvent {
// MARK: Properties
/// The message content.
public var message: String
/// The timestamp when the message was edited. The timestamp is in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.
public var editedOn: Iso8601Date?
/// The message metadata
public var metadata: [String: String?]?
// MARK: Initializers
/// Initialize a ChatMessageEditedEvent.
/// - Parameters:
/// - threadId: Chat thread id.
/// - sender: Sender identifier.
/// - recipient: Recipient identifier.
/// - id: Message id.
/// - senderDisplayName: Sender display name.
/// - createdOn: Created on timestamp.
/// - version: Message version.
/// - type: Message type.
/// - message: Message content.
/// - editedOn: Time that the message was edited.
init(
threadId: String,
sender: CommunicationIdentifier?,
recipient: CommunicationIdentifier?,
id: String,
senderDisplayName: String? = nil,
createdOn: Iso8601Date?,
version: String,
type: ChatMessageType,
message: String,
editedOn: Iso8601Date?,
metadata: [String: String?]? = nil
) {
self.message = message
self.editedOn = editedOn
self.metadata = metadata
super.init(
threadId: threadId,
sender: sender,
recipient: recipient,
id: id,
senderDisplayName: senderDisplayName,
createdOn: createdOn,
version: version,
type: type
)
}
/// Initialize a ChatMessageEditedEvent from a TrouterRequest.
/// - Parameter request: The TrouterRequest.
init(from request: TrouterRequest) throws {
guard let requestJsonData = request.body.data(using: .utf8) else {
throw AzureError.client("Unable to convert request body to Data.")
}
let chatMessageEditedPayload: MessageEditedPayload = try JSONDecoder()
.decode(MessageEditedPayload.self, from: requestJsonData)
self.message = chatMessageEditedPayload.messageBody
self.editedOn = Iso8601Date(string: chatMessageEditedPayload.edittime)
if chatMessageEditedPayload.acsChatMessageMetadata != "null" {
if let acsChatMetadata = chatMessageEditedPayload.acsChatMessageMetadata.data(using: .utf8) {
self.metadata = try JSONDecoder().decode([String: String?].self, from: acsChatMetadata)
}
}
super.init(
threadId: chatMessageEditedPayload.groupId,
sender: createCommunicationIdentifier(fromRawId: chatMessageEditedPayload.senderId),
recipient: createCommunicationIdentifier(fromRawId: chatMessageEditedPayload.recipientMri),
id: chatMessageEditedPayload.messageId,
senderDisplayName: chatMessageEditedPayload.senderDisplayName,
createdOn: Iso8601Date(string: chatMessageEditedPayload.originalArrivalTime),
version: chatMessageEditedPayload.version,
type: ChatMessageType(chatMessageEditedPayload.messageType)
)
}
}
/// ChatMessageDeletedEvent for real-time notifications.
public class ChatMessageDeletedEvent: BaseChatMessageEvent {
// MARK: Properties
/// The timestamp when the message was deleted. The timestamp is in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.
public var deletedOn: Iso8601Date?
// MARK: Initializers
/// Initialize a ChatMessageDeletedEvent.
/// - Parameters:
/// - threadId: Chat thread id.
/// - sender: Sender identifier.
/// - recipient: Recipient identifier.
/// - id: Message id.
/// - senderDisplayName: Sender display name.
/// - createdOn: Time that the message was created.
/// - version: Message version.
/// - type: Message type.
/// - deletedOn: Time that the message was deleted on.
init(
threadId: String,
sender: CommunicationIdentifier?,
recipient: CommunicationIdentifier?,
id: String,
senderDisplayName: String? = nil,
createdOn: Iso8601Date?,
version: String,
type: ChatMessageType,
deletedOn: Iso8601Date?
) {
self.deletedOn = deletedOn
super.init(
threadId: threadId,
sender: sender,
recipient: recipient,
id: id,
senderDisplayName: senderDisplayName,
createdOn: createdOn,
version: version,
type: type
)
}
/// Initialize a ChatMessageDeletedEvent from a TrouterRequest.
/// - Parameter request: The TrouterRequest.
init(from request: TrouterRequest) throws {
guard let requestJsonData = request.body.data(using: .utf8) else {
throw AzureError.client("Unable to convert request body to Data.")
}
let chatMessageDeletedPayload: MessageDeletedPayload = try JSONDecoder()
.decode(MessageDeletedPayload.self, from: requestJsonData)
self.deletedOn = Iso8601Date(string: chatMessageDeletedPayload.deletetime)
super.init(
threadId: chatMessageDeletedPayload.groupId,
sender: createCommunicationIdentifier(fromRawId: chatMessageDeletedPayload.senderId),
recipient: createCommunicationIdentifier(fromRawId: chatMessageDeletedPayload.recipientMri),
id: chatMessageDeletedPayload.messageId,
senderDisplayName: chatMessageDeletedPayload.senderDisplayName,
createdOn: Iso8601Date(string: chatMessageDeletedPayload.originalArrivalTime),
version: chatMessageDeletedPayload.version,
type: ChatMessageType(chatMessageDeletedPayload.messageType)
)
}
}
/// TypingIndicatorReceivedEvent for real-time notifications.
public class TypingIndicatorReceivedEvent: BaseChatEvent {
// MARK: Properties
// TODO:
public var version: String
/// The timestamp when the indicator was received. The timestamp is in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.
public var receivedOn: Iso8601Date?
/// The sender displayName.
public var senderDisplayName: String?
// MARK: Initializers
/// Initialize a TypingIndicatorReceivedEvent.
/// - Parameters:
/// - threadId: Chat thread id.
/// - sender: Sender identifier.
/// - recipient: Recipient identifier.
/// - version: Version.
/// - receivedOn: Time that the indicator was received.
init(
threadId: String,
sender: CommunicationIdentifier?,
recipient: CommunicationIdentifier?,
version: String,
receivedOn: Iso8601Date?,
senderDisplayName: String? = nil
) {
self.version = version
self.receivedOn = receivedOn
self.senderDisplayName = senderDisplayName
super.init(threadId: threadId, sender: sender, recipient: recipient)
}
/// Initialize a TypingIndicatorReceivedEvent from a TrouterRequest.
/// - Parameter request: The TrouterRequest.
init(from request: TrouterRequest) throws {
guard let requestJsonData = request.body.data(using: .utf8) else {
throw AzureError.client("Unable to convert request body to Data.")
}
let typingIndicatorReceivedPayload: TypingIndicatorReceivedPayload = try JSONDecoder()
.decode(TypingIndicatorReceivedPayload.self, from: requestJsonData)
self.version = typingIndicatorReceivedPayload.version
self.receivedOn = Iso8601Date(string: typingIndicatorReceivedPayload.originalArrivalTime)
self.senderDisplayName = typingIndicatorReceivedPayload.senderDisplayName
super.init(
threadId: typingIndicatorReceivedPayload.groupId,
sender: createCommunicationIdentifier(fromRawId: typingIndicatorReceivedPayload.senderId),
recipient: createCommunicationIdentifier(fromRawId: typingIndicatorReceivedPayload.recipientMri)
)
}
}
/// ReadReceiptReceivedEvent for real-time notifications.
public class ReadReceiptReceivedEvent: BaseChatEvent {
// MARK: Properties
/// Id of the chat message that has been read. This id is generated by the server.
public var chatMessageId: String
/// The time at which the message was read. The timestamp is in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.
public var readOn: Iso8601Date?
// MARK: Initializers
/// Initialize a ReadReceiptReceivedEvent.
/// - Parameters:
/// - threadId: Chat thread id,
/// - sender: Sender identifier.
/// - recipient: Recipient identifier.
/// - chatMessageId: Id of the message that was read.
/// - readOn: Time that the message was read.
init(
threadId: String,
sender: CommunicationIdentifier?,
recipient: CommunicationIdentifier?,
chatMessageId: String,
readOn: Iso8601Date?
) {
self.chatMessageId = chatMessageId
self.readOn = readOn
super.init(threadId: threadId, sender: sender, recipient: recipient)
}
/// Initialize a ReadReceiptReceivedEvent from a TrouterRequest.
/// - Parameter request: The TrouterRequest.
init(from request: TrouterRequest) throws {
guard let requestJsonData = request.body.data(using: .utf8) else {
throw AzureError.client("Unable to convert request body to Data.")
}
let readReceiptReceivedPayload: ReadReceiptReceivedPayload = try JSONDecoder()
.decode(ReadReceiptReceivedPayload.self, from: requestJsonData)
guard let readReceiptMessageBodyJsonData = readReceiptReceivedPayload.messageBody.data(using: .utf8) else {
throw AzureError.client("Unable to convert payload messageBody to Data.")
}
let readReceiptMessageBody: ReadReceiptMessageBody = try JSONDecoder()
.decode(ReadReceiptMessageBody.self, from: readReceiptMessageBodyJsonData)
// Extract readOn value from consumptionHorizon
let consumptionHorizon = readReceiptMessageBody.consumptionhorizon.split(separator: ";")
guard let readOnMs = Double(consumptionHorizon[1]) else {
throw AzureError.client("Failed to construct Int from consumptionHorizon for readOn property.")
}
// In the payload readOn is represented as epoch time in milliseconds
let readOnSeconds = readOnMs / 1000
let readOnDate = Date(timeIntervalSince1970: TimeInterval(readOnSeconds))
self.chatMessageId = readReceiptReceivedPayload.messageId
self.readOn = Iso8601Date(readOnDate)
super.init(
threadId: readReceiptReceivedPayload.groupId,
sender: createCommunicationIdentifier(fromRawId: readReceiptReceivedPayload.senderId),
recipient: createCommunicationIdentifier(fromRawId: readReceiptReceivedPayload.recipientMri)
)
}
}
/// ChatThreadCreatedEvent for real-time notifications.
public class ChatThreadCreatedEvent: BaseChatThreadEvent {
// MARK: Properties
/// The timestamp when the thread was created. The timestamp is in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.
public var createdOn: Iso8601Date?
/// ChatThread properties, contains the thread topic.
public var properties: SignalingChatThreadProperties?
/// List of participants currently in the thread.
public var participants: [SignalingChatParticipant]?
/// The participant that created the thread.
public var createdBy: SignalingChatParticipant?
// MARK: Initializers
/// Initialize a ChatThreadCreatedEvent.
/// - Parameters:
/// - threadId: Chat thread id,
/// - version: Chat thread version.
/// - createdOn: Time that the chat thread was created.
/// - properties: Properties of the chat thread.
/// - participants: Participants in the thread.
/// - createdBy: Participant that created the thread.
init(
threadId: String,
version: String,
createdOn: Iso8601Date?,
properties: SignalingChatThreadProperties?,
participants: [SignalingChatParticipant]?,
createdBy: SignalingChatParticipant?
) {
self.createdOn = createdOn
self.properties = properties
self.participants = participants
self.createdBy = createdBy
super.init(threadId: threadId, version: version)
}
/// Initialize a ChatThreadCreatedEvent from a TrouterRequest.
/// - Parameter request: The TrouterRequest.
init(from request: TrouterRequest) throws {
guard let requestJsonData = request.body.data(using: .utf8) else {
throw AzureError.client("Unable to convert request body to Data.")
}
let chatThreadCreatedPayload: ChatThreadCreatedPayload = try JSONDecoder()
.decode(ChatThreadCreatedPayload.self, from: requestJsonData)
guard let createdByJsonData = chatThreadCreatedPayload.createdBy.data(using: .utf8) else {
throw AzureError.client("Unable to convert payload createdBy to Data.")
}
let createdByPayload: ChatParticipantPayload = try JSONDecoder()
.decode(ChatParticipantPayload.self, from: createdByJsonData)
let createdBy =
SignalingChatParticipant(
id: createCommunicationIdentifier(fromRawId: createdByPayload.participantId),
displayName: createdByPayload.displayName
)
guard let membersJsonData = chatThreadCreatedPayload.members.data(using: .utf8) else {
throw AzureError.client("Unable to convert payload members to Data.")
}
let membersPayload: [ChatParticipantPayload] = try JSONDecoder()
.decode([ChatParticipantPayload].self, from: membersJsonData)
let participants: [SignalingChatParticipant] = membersPayload
.map { (memberPayload: ChatParticipantPayload) -> SignalingChatParticipant in
SignalingChatParticipant(
id: createCommunicationIdentifier(fromRawId: memberPayload.participantId),
displayName: memberPayload.displayName
)
}
guard let propertiesJsonData = chatThreadCreatedPayload.properties.data(using: .utf8) else {
throw AzureError.client("Unable to convert payload properties to Data.")
}
let propertiesPayload: ChatThreadPropertiesPayload = try JSONDecoder()
.decode(ChatThreadPropertiesPayload.self, from: propertiesJsonData)
let properties = SignalingChatThreadProperties(topic: propertiesPayload.topic)
self.createdOn = Iso8601Date(string: chatThreadCreatedPayload.createTime)
self.properties = properties
self.participants = participants
self.createdBy = createdBy
super.init(
threadId: chatThreadCreatedPayload.threadId,
version: chatThreadCreatedPayload.version
)
}
}
/// ChatThreadPropertiesUpdatedEvent for real-time notifications.
public class ChatThreadPropertiesUpdatedEvent: BaseChatThreadEvent {
// MARK: Properties
/// The chat thread properties, includes the thread topic.
public var properties: SignalingChatThreadProperties?
/// The timestamp when the thread was updated. The timestamp is in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.
public var updatedOn: Iso8601Date?
/// The participant that updated the thread.
public var updatedBy: SignalingChatParticipant?
// MARK: Initializers
/// Initialize a ChatThreadPropertiesUpdatedEvent.
/// - Parameters:
/// - threadId: Chat thread id.
/// - version: Chat thread version.
/// - properties: Chat thread properties, contains the thread topic.
/// - updatedOn: Time that the thread was updated.
/// - updatedBy: Participant that updated the thread.
init(
threadId: String,
version: String,
properties: SignalingChatThreadProperties?,
updatedOn: Iso8601Date?,
updatedBy: SignalingChatParticipant?
) {
self.properties = properties
self.updatedOn = updatedOn
self.updatedBy = updatedBy
super.init(threadId: threadId, version: version)
}
/// Initialize a ChatThreadPropertiesUpdatedEvent from a TrouterRequest.
/// - Parameter request: The TrouterRequest.
init(from request: TrouterRequest) throws {
guard let requestJsonData = request.body.data(using: .utf8) else {
throw AzureError.client("Unable to convert request body to Data.")
}
let chatThreadPropertiesUpdatedPayload: ChatThreadPropertiesUpdatedPayload = try JSONDecoder()
.decode(ChatThreadPropertiesUpdatedPayload.self, from: requestJsonData)
guard let updatedByJsonData = chatThreadPropertiesUpdatedPayload.editedBy.data(using: .utf8) else {
throw AzureError.client("Unable to convert payload editedBy to Data.")
}
let updatedByPayload: ChatParticipantPayload = try JSONDecoder()
.decode(ChatParticipantPayload.self, from: updatedByJsonData)
let updatedBy =
SignalingChatParticipant(
id: createCommunicationIdentifier(fromRawId: updatedByPayload.participantId),
displayName: updatedByPayload.displayName
)
guard let propertiesJsonData = chatThreadPropertiesUpdatedPayload.properties.data(using: .utf8) else {
throw AzureError.client("Unable to convert payload properties Data.")
}
let propertiesPayload: ChatThreadPropertiesPayload = try JSONDecoder()
.decode(ChatThreadPropertiesPayload.self, from: propertiesJsonData)
let properties = SignalingChatThreadProperties(topic: propertiesPayload.topic)
self.properties = properties
self.updatedOn = Iso8601Date(string: chatThreadPropertiesUpdatedPayload.editTime)
self.updatedBy = updatedBy
super.init(
threadId: chatThreadPropertiesUpdatedPayload.threadId,
version: chatThreadPropertiesUpdatedPayload.version
)
}
}
/// ChatThreadDeletedEvent for real-time notifications.
public class ChatThreadDeletedEvent: BaseChatThreadEvent {
// MARK: Properties
/// The timestamp when the thread was deleted. The timestamp is in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.
public var deletedOn: Iso8601Date?
/// The participant that deleted the chat thread.
public var deletedBy: SignalingChatParticipant?
// MARK: Initializers
/// Initialize a ChatThreadDeletedEvent.
/// - Parameters:
/// - threadId: Chat thread id.
/// - version: Chat thread version.
/// - deletedOn: Time that the thread was deleted.
/// - deletedBy: Participant that deleted the thread.
init(
threadId: String,
version: String,
deletedOn: Iso8601Date?,
deletedBy: SignalingChatParticipant?
) {
self.deletedOn = deletedOn
self.deletedBy = deletedBy
super.init(threadId: threadId, version: version)
}
/// Initialize a ChatThreadDeletedEvent from a TrouterRequest.
/// - Parameter request: The TrouterRequest.
init(from request: TrouterRequest) throws {
guard let requestJsonData = request.body.data(using: .utf8) else {
throw AzureError.client("Unable to convert request body to Data.")
}
let chatThreadDeletedPayload: ChatThreadDeletedPayload = try JSONDecoder()
.decode(ChatThreadDeletedPayload.self, from: requestJsonData)
guard let deletedByJsonData = chatThreadDeletedPayload.deletedBy.data(using: .utf8) else {
throw AzureError.client("Unable to convert payload deletedBy to Data.")
}
let deletedByPayload: ChatParticipantPayload = try JSONDecoder()
.decode(ChatParticipantPayload.self, from: deletedByJsonData)
let deletedBy = SignalingChatParticipant(
id: createCommunicationIdentifier(fromRawId: deletedByPayload.participantId),
displayName: deletedByPayload.displayName
)
self.deletedOn = Iso8601Date(string: chatThreadDeletedPayload.deleteTime)
self.deletedBy = deletedBy
super.init(
threadId: chatThreadDeletedPayload.threadId,
version: chatThreadDeletedPayload.version
)
}
}
/// ParticipantsAddedEvent for real-time notifications.
public class ParticipantsAddedEvent: BaseChatThreadEvent {
// MARK: Properties
/// The timestamp when the participant(s) were added. The timestamp is in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.
public var addedOn: Iso8601Date?
/// The participants that were added.
public var participantsAdded: [SignalingChatParticipant]?
/// The participant that added the new participant(s).
public var addedBy: SignalingChatParticipant?
// MARK: Initializers
/// Initialize a ParticipantsAddedEvent.
/// - Parameters:
/// - threadId: Chat thread id.
/// - version: Chat thread version.
/// - addedOn: Time that the participant(s) were added.
/// - participantsAdded: Array of the participant(s) that were added.
/// - addedBy: Participant who added the new participant(s).
init(
threadId: String,
version: String,
addedOn: Iso8601Date?,
participantsAdded: [SignalingChatParticipant]?,
addedBy: SignalingChatParticipant?
) {
self.addedOn = addedOn
self.participantsAdded = participantsAdded
self.addedBy = addedBy
super.init(threadId: threadId, version: version)
}
/// Initialize a ParticipantsAddedEvent from a TrouterRequest.
/// - Parameter request: The TrouterRequest.
init(from request: TrouterRequest) throws {
guard let requestJsonData = request.body.data(using: .utf8) else {
throw AzureError.client("Unable to convert request body to Data.")
}
let participantsAddedPayload: ParticipantsAddedPayload = try JSONDecoder()
.decode(ParticipantsAddedPayload.self, from: requestJsonData)
guard let addeddByJsonData = participantsAddedPayload.addedBy.data(using: .utf8) else {
throw AzureError.client("Unable to convert payload addedBy to Data.")
}
let addedByPayload: ChatParticipantPayload = try JSONDecoder()
.decode(ChatParticipantPayload.self, from: addeddByJsonData)
let addedBy = SignalingChatParticipant(
id: createCommunicationIdentifier(fromRawId: addedByPayload.participantId),
displayName: addedByPayload.displayName
)
guard let participantsJsonData = participantsAddedPayload.participantsAdded.data(using: .utf8) else {
throw AzureError.client("Unable to convert payload participantsAdded to Data.")
}
let participantsPayload: [ChatParticipantPayload] = try JSONDecoder()
.decode([ChatParticipantPayload].self, from: participantsJsonData)
let participants: [SignalingChatParticipant] = participantsPayload
.map { (memberPayload: ChatParticipantPayload) -> SignalingChatParticipant in
SignalingChatParticipant(
id: createCommunicationIdentifier(fromRawId: memberPayload.participantId),
displayName: memberPayload.displayName,
shareHistoryTime: Iso8601Date(
string: TrouterEventUtil
.toIso8601Date(unixTime: memberPayload.shareHistoryTime)
)
)
}
self.addedOn = Iso8601Date(string: participantsAddedPayload.time)
self.participantsAdded = participants
self.addedBy = addedBy
super.init(
threadId: participantsAddedPayload.threadId,
version: participantsAddedPayload.version
)
}
}
/// ParticipantsRemovedEvent for real-time notifications.
public class ParticipantsRemovedEvent: BaseChatThreadEvent {
// MARK: Properties
/// The timestamp when the participant(s) were removed. The timestamp is in RFC3339 format: `yyyy-MM-ddTHH:mm:ssZ`.
public var removedOn: Iso8601Date?
// TODO: Should this be singular?
public var participantsRemoved: [SignalingChatParticipant]?
/// The participant that initiated the removal.
public var removedBy: SignalingChatParticipant?
// MARK: Initializers
/// Initialize a ParticipantsRemovedEvent
/// - Parameters:
/// - threadId: Chat thread id.
/// - version: Chat thread version.
/// - removedOn: Time that the participant was removed.
/// - participantsRemoved: TODO
/// - removedBy: Participant that initiated the removal.
init(
threadId: String,
version: String,
removedOn: Iso8601Date?,
participantsRemoved: [SignalingChatParticipant]?,
removedBy: SignalingChatParticipant?
) {
self.removedOn = removedOn
self.participantsRemoved = participantsRemoved
self.removedBy = removedBy
super.init(threadId: threadId, version: version)
}
/// Initialize a ParticipantsRemovedEvent from a TrouterRequest.
/// - Parameter request: The TrouterRequest.
init(from request: TrouterRequest) throws {
guard let requestJsonData = request.body.data(using: .utf8) else {
throw AzureError.client("Unable to convert request body to Data.")
}
let participantsRemovedPayload: ParticipantsRemovedPayload = try JSONDecoder()
.decode(ParticipantsRemovedPayload.self, from: requestJsonData)
guard let removedByJsonData = participantsRemovedPayload.removedBy.data(using: .utf8) else {
throw AzureError.client("Unable to convert payload removedBy to Data.")
}
let removedByPayload: ChatParticipantPayload = try JSONDecoder()
.decode(ChatParticipantPayload.self, from: removedByJsonData)
let removedBy = SignalingChatParticipant(
id: createCommunicationIdentifier(fromRawId: removedByPayload.participantId),
displayName: removedByPayload.displayName
)
guard let participantsJsonData = participantsRemovedPayload.participantsRemoved.data(using: .utf8) else {
throw AzureError.client("Unable to convert payload participantsRemoved to Data.")
}
let participantsPayload: [ChatParticipantPayload] = try JSONDecoder()
.decode([ChatParticipantPayload].self, from: participantsJsonData)
let participants: [SignalingChatParticipant] = participantsPayload
.map { (memberPayload: ChatParticipantPayload) -> SignalingChatParticipant in
SignalingChatParticipant(
id: createCommunicationIdentifier(fromRawId: memberPayload.participantId),
displayName: memberPayload.displayName,
shareHistoryTime: Iso8601Date(
string: TrouterEventUtil
.toIso8601Date(unixTime: memberPayload.shareHistoryTime)
)
)
}
self.removedOn = Iso8601Date(string: participantsRemovedPayload.time)
self.participantsRemoved = participants
self.removedBy = removedBy
super.init(
threadId: participantsRemovedPayload.threadId,
version: participantsRemovedPayload.version
)
}
}
/// ChatEventId representing the different events for real-time notifications
public enum ChatEventId: String {
case realTimeNotificationConnected
case realTimeNotificationDisconnected
case chatMessageReceived
case typingIndicatorReceived
case readReceiptReceived
case chatMessageEdited
case chatMessageDeleted
case chatThreadCreated
case chatThreadPropertiesUpdated
case chatThreadDeleted
case participantsAdded
case participantsRemoved
init(forCode code: Int) throws {
switch code {
case 200:
self = .chatMessageReceived
case 245:
self = .typingIndicatorReceived
case 246:
self = .readReceiptReceived
case 247:
self = .chatMessageEdited
case 248:
self = .chatMessageDeleted
case 257:
self = .chatThreadCreated
case 258:
self = .chatThreadPropertiesUpdated
case 259:
self = .chatThreadDeleted
case 260:
self = .participantsAdded
case 261:
self = .participantsRemoved
default:
throw AzureError.client("Event code: \(code) is unsupported")
}
}
}