feature(agora): rtm version 1.4.10 -> 2.2.4
This commit is contained in:
		
							
								
								
									
										16
									
								
								Podfile
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								Podfile
									
									
									
									
									
								
							@@ -7,6 +7,7 @@ target 'SodaLive' do
 | 
			
		||||
 | 
			
		||||
  # Pods for SodaLive
 | 
			
		||||
  pod 'BootpayUI', '4.4.10'
 | 
			
		||||
  pod 'AgoraRtm', '2.2.4'
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@@ -16,9 +17,24 @@ target 'SodaLive-dev' do
 | 
			
		||||
 | 
			
		||||
  # Pods for SodaLive-dev
 | 
			
		||||
  pod 'BootpayUI', '4.4.10'
 | 
			
		||||
  pod 'AgoraRtm', '2.2.4'
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
pre_install do |installer|
 | 
			
		||||
  # Path to the AgoraRtm Pod directory inside the CocoaPods sandbox
 | 
			
		||||
  rtm_pod_path = File.join(installer.sandbox.root, 'AgoraRtm')
 | 
			
		||||
  # Full path to aosl.xcframework
 | 
			
		||||
  aosl_xcframework_path = File.join(rtm_pod_path, 'aosl.xcframework')
 | 
			
		||||
 | 
			
		||||
  if File.exist?(aosl_xcframework_path)
 | 
			
		||||
    puts "Deleting aosl.xcframework from #{aosl_xcframework_path}"
 | 
			
		||||
    FileUtils.rm_rf(aosl_xcframework_path)
 | 
			
		||||
  else
 | 
			
		||||
    puts "aosl.xcframework not found, skipping deletion."
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
post_install do |installer|
 | 
			
		||||
    installer.generated_projects.each do |project|
 | 
			
		||||
          project.targets.each do |target|
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								Podfile.lock
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Podfile.lock
									
									
									
									
									
								
							@@ -1,4 +1,9 @@
 | 
			
		||||
PODS:
 | 
			
		||||
  - AgoraRtm (2.2.4):
 | 
			
		||||
    - AgoraRtm/RtmBasic (= 2.2.4)
 | 
			
		||||
    - AgoraRtm/RtmKit (= 2.2.4)
 | 
			
		||||
  - AgoraRtm/RtmBasic (2.2.4)
 | 
			
		||||
  - AgoraRtm/RtmKit (2.2.4)
 | 
			
		||||
  - Alamofire (5.10.2)
 | 
			
		||||
  - Bootpay (4.4.6):
 | 
			
		||||
    - CryptoSwift
 | 
			
		||||
@@ -20,10 +25,12 @@ PODS:
 | 
			
		||||
  - SwiftyJSON (5.0.2)
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES:
 | 
			
		||||
  - AgoraRtm (= 2.2.4)
 | 
			
		||||
  - BootpayUI (= 4.4.10)
 | 
			
		||||
 | 
			
		||||
SPEC REPOS:
 | 
			
		||||
  trunk:
 | 
			
		||||
    - AgoraRtm
 | 
			
		||||
    - Alamofire
 | 
			
		||||
    - Bootpay
 | 
			
		||||
    - BootpayUI
 | 
			
		||||
@@ -34,6 +41,7 @@ SPEC REPOS:
 | 
			
		||||
    - SwiftyJSON
 | 
			
		||||
 | 
			
		||||
SPEC CHECKSUMS:
 | 
			
		||||
  AgoraRtm: 534144434383d41b3b0ebfae2a961ef0f51b0645
 | 
			
		||||
  Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
 | 
			
		||||
  Bootpay: cd7f0542b096ab0af0b09a6e12a6b87f2cbbb531
 | 
			
		||||
  BootpayUI: beec5b0bba002b4dbced8c0ecace571ed6a017bc
 | 
			
		||||
@@ -43,6 +51,6 @@ SPEC CHECKSUMS:
 | 
			
		||||
  SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a
 | 
			
		||||
  SwiftyJSON: f5b1bf1cd8dd53cd25887ac0eabcfd92301c6a5a
 | 
			
		||||
 | 
			
		||||
PODFILE CHECKSUM: a99afeba13301c2139b142c1e1592fe314698d39
 | 
			
		||||
PODFILE CHECKSUM: 197d8c8b434dbcc335438281fc68e94718f6a8e1
 | 
			
		||||
 | 
			
		||||
COCOAPODS: 1.16.2
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
  "originHash" : "021219245a6febf5a4891182273209d32ef45b11dd68b857e2eef1f7a8ca439d",
 | 
			
		||||
  "originHash" : "1f28da3687662a2a9efe60ffc2ca2499be411b5b0a1e07f72559059c40728121",
 | 
			
		||||
  "pins" : [
 | 
			
		||||
    {
 | 
			
		||||
      "identity" : "abseil-cpp-binary",
 | 
			
		||||
@@ -28,15 +28,6 @@
 | 
			
		||||
        "version" : "4.6.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "identity" : "agorartm_ios",
 | 
			
		||||
      "kind" : "remoteSourceControl",
 | 
			
		||||
      "location" : "https://github.com/AgoraIO/AgoraRtm_iOS",
 | 
			
		||||
      "state" : {
 | 
			
		||||
        "revision" : "8d8d126da7e420798f39d1d95b6148eeb93971aa",
 | 
			
		||||
        "version" : "1.4.10"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "identity" : "alamofire",
 | 
			
		||||
      "kind" : "remoteSourceControl",
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ final class Agora {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // MARK: RTC
 | 
			
		||||
    var rtcEngine: AgoraRtcEngineKit?
 | 
			
		||||
    private var rtcEngine: AgoraRtcEngineKit?
 | 
			
		||||
    var rtcEngineDelegate: AgoraRtcEngineDelegate?
 | 
			
		||||
    
 | 
			
		||||
    func initRtcEngine() {
 | 
			
		||||
@@ -71,85 +71,216 @@ final class Agora {
 | 
			
		||||
        rtcEngine?.muteAllRemoteAudioStreams(isMute)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func getRtcConnectionState() -> AgoraConnectionState {
 | 
			
		||||
        return rtcEngine!.getConnectionState()
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // MARK: RTM
 | 
			
		||||
    var rtmKit: AgoraRtmKit?
 | 
			
		||||
    var rtmChannel: AgoraRtmChannel?
 | 
			
		||||
    var rtmDelegate: AgoraRtmDelegate?
 | 
			
		||||
    private var rtmKit: AgoraRtmClientKit?
 | 
			
		||||
    private var roomChannelName: String? = nil
 | 
			
		||||
    
 | 
			
		||||
    // 상태 플래그: RTM 로그인 완료 여부
 | 
			
		||||
    private var rtmLoggedIn: Bool = false
 | 
			
		||||
    
 | 
			
		||||
    // 상태 플래그: RTM 로그인 진행 중 여부
 | 
			
		||||
    private var rtmLoginInProgress: Bool = false
 | 
			
		||||
    
 | 
			
		||||
    var rtmClientDelegate: AgoraRtmClientDelegate?
 | 
			
		||||
    
 | 
			
		||||
    func initRtmClient() {
 | 
			
		||||
        rtmKit = AgoraRtmKit(appId: AGORA_APP_ID, delegate: rtmDelegate)
 | 
			
		||||
        if rtmKit != nil {
 | 
			
		||||
            rtmKit?.logout()
 | 
			
		||||
            rtmKit?.destroy()
 | 
			
		||||
            rtmKit = nil
 | 
			
		||||
        }
 | 
			
		||||
        let userId = UserDefaults.int(forKey: .userId)
 | 
			
		||||
        let config = AgoraRtmClientConfig(appId: AGORA_APP_ID, userId: String(userId))
 | 
			
		||||
        rtmKit = try? AgoraRtmClientKit(config, delegate: rtmClientDelegate)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func deInitRtmClient() {
 | 
			
		||||
        rtmChannel?.leave(completion: nil)
 | 
			
		||||
        rtmKit?.logout(completion: nil)
 | 
			
		||||
        rtmChannel = nil
 | 
			
		||||
        rtmKit = nil
 | 
			
		||||
        let userId = UserDefaults.int(forKey: .userId)
 | 
			
		||||
        let group = DispatchGroup()
 | 
			
		||||
 | 
			
		||||
        if let channel = roomChannelName {
 | 
			
		||||
            group.enter()
 | 
			
		||||
            rtmKit?.unsubscribe(channel) { [weak self] _, error in
 | 
			
		||||
                if let error = error {
 | 
			
		||||
                    DEBUG_LOG("RTM unsubscribe fail - \(error.operation)")
 | 
			
		||||
                    DEBUG_LOG("RTM unsubscribe fail - \(error.errorCode)")
 | 
			
		||||
                    DEBUG_LOG("RTM unsubscribe fail - \(error.reason)")
 | 
			
		||||
                } else {
 | 
			
		||||
                    DEBUG_LOG("RTM unsubscribe - \(channel)")
 | 
			
		||||
                    self?.roomChannelName = nil
 | 
			
		||||
                }
 | 
			
		||||
                group.leave()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        group.enter()
 | 
			
		||||
        rtmKit?.unsubscribe("inbox_\(userId)") { _, error in
 | 
			
		||||
            if let error = error {
 | 
			
		||||
                DEBUG_LOG("RTM unsubscribe fail - \(error.operation)")
 | 
			
		||||
                DEBUG_LOG("RTM unsubscribe fail - \(error.errorCode)")
 | 
			
		||||
                DEBUG_LOG("RTM unsubscribe fail - \(error.reason)")
 | 
			
		||||
            } else {
 | 
			
		||||
                DEBUG_LOG("RTM unsubscribe - inbox_\(userId)")
 | 
			
		||||
            }
 | 
			
		||||
            group.leave()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        group.notify(queue: .global(qos: .userInitiated)) { [weak self] in
 | 
			
		||||
            guard let self = self else { return }
 | 
			
		||||
            self.rtmKit?.logout()
 | 
			
		||||
            self.rtmKit?.destroy()
 | 
			
		||||
            self.rtmKit = nil
 | 
			
		||||
            self.rtmLoggedIn = false
 | 
			
		||||
            self.rtmLoginInProgress = false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func rtmLogin(
 | 
			
		||||
        creatorId: Int,
 | 
			
		||||
        rtmToken: String,
 | 
			
		||||
        channelName: String,
 | 
			
		||||
        rtmChannelDelegate: AgoraRtmChannelDelegate,
 | 
			
		||||
        onConnectSuccess: @escaping (Bool) -> Void,
 | 
			
		||||
        onConnectFail: @escaping () -> Void
 | 
			
		||||
    ) {
 | 
			
		||||
        if rtmChannel != nil {
 | 
			
		||||
        if rtmLoggedIn && roomChannelName == channelName {
 | 
			
		||||
            DEBUG_LOG("rtmLogin - already logged in and subscribed. skip")
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        let userId = UserDefaults.int(forKey: .userId)
 | 
			
		||||
        // 로그인 시도 중이면 재호출 방지
 | 
			
		||||
        if (rtmLoginInProgress) {
 | 
			
		||||
            DEBUG_LOG("rtmLogin - already in progress. skip")
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        rtmChannel = rtmKit?.createChannel(
 | 
			
		||||
            withId: channelName,
 | 
			
		||||
            delegate: rtmChannelDelegate
 | 
			
		||||
        )
 | 
			
		||||
        roomChannelName = channelName
 | 
			
		||||
        
 | 
			
		||||
        rtmKit?.login(
 | 
			
		||||
            byToken: rtmToken,
 | 
			
		||||
            user: String(userId),
 | 
			
		||||
            completion: { [unowned self] loginErrorCode in
 | 
			
		||||
                if loginErrorCode == .ok {
 | 
			
		||||
                    self.rtmChannel?.join(completion: { joinChannelErrorCode in
 | 
			
		||||
                        if joinChannelErrorCode == .channelErrorOk {
 | 
			
		||||
                            if userId == creatorId {
 | 
			
		||||
                                self.setRole(role: .broadcaster)
 | 
			
		||||
                            } else {
 | 
			
		||||
                                self.setRole(role: .audience)
 | 
			
		||||
                            }
 | 
			
		||||
        func attemptLogin(_ attempt: Int) {
 | 
			
		||||
            rtmKit?.login(rtmToken) { [weak self] response, error in
 | 
			
		||||
                if let error = error {
 | 
			
		||||
                    DEBUG_LOG("rtmClient login - fail (attempt=\(attempt)), \(error.reason)")
 | 
			
		||||
                    if attempt < 4 {
 | 
			
		||||
                        
 | 
			
		||||
                            onConnectSuccess(userId == creatorId)
 | 
			
		||||
                        } else {
 | 
			
		||||
                            onConnectFail()
 | 
			
		||||
                        }
 | 
			
		||||
                    })
 | 
			
		||||
                    } else {
 | 
			
		||||
                        self?.rtmLoginInProgress = false
 | 
			
		||||
                        onConnectFail()
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    onConnectFail()
 | 
			
		||||
                    DEBUG_LOG("rtmClient login - success (attempt=\(attempt))")
 | 
			
		||||
                    // 로그인 성공 후 두 채널 구독 시도
 | 
			
		||||
                    self?.subscribeChannel(
 | 
			
		||||
                        creatorId: creatorId,
 | 
			
		||||
                        onConnectSuccess: onConnectSuccess,
 | 
			
		||||
                        onConnectFail: onConnectFail
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        rtmLoginInProgress = true
 | 
			
		||||
        attemptLogin(1)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func sendMessageToPeer(peerId: String, rawMessage: Data, completion: AgoraRtmSendPeerMessageBlock?) {
 | 
			
		||||
        let option = AgoraRtmSendMessageOptions()
 | 
			
		||||
        option.enableOfflineMessaging = false
 | 
			
		||||
        option.enableHistoricalMessaging = false
 | 
			
		||||
    private func subscribeChannel(
 | 
			
		||||
        creatorId: Int,
 | 
			
		||||
        onConnectSuccess: @escaping (Bool) -> Void,
 | 
			
		||||
        onConnectFail: @escaping () -> Void
 | 
			
		||||
    ) {
 | 
			
		||||
        let targetRoom = roomChannelName
 | 
			
		||||
        if (targetRoom == nil) {
 | 
			
		||||
            DEBUG_LOG("subscribeChannel - roomChannelName is nil")
 | 
			
		||||
            onConnectFail()
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        let message = AgoraRtmRawMessage(rawData: rawMessage, description: "")
 | 
			
		||||
        rtmKit?.send(message, toPeer: peerId, completion: completion)
 | 
			
		||||
        var completed = false
 | 
			
		||||
        var roomSubscribed = false
 | 
			
		||||
        var inboxSubscribed = false
 | 
			
		||||
        let userId = UserDefaults.int(forKey: .userId)
 | 
			
		||||
        
 | 
			
		||||
        func completeSuccessIfReady() {
 | 
			
		||||
            if (!completed && roomSubscribed && inboxSubscribed) {
 | 
			
		||||
                completed = true
 | 
			
		||||
                rtmLoggedIn = true
 | 
			
		||||
                rtmLoginInProgress = false
 | 
			
		||||
                DEBUG_LOG("RTM subscribe - both channels subscribed")
 | 
			
		||||
                if userId == creatorId {
 | 
			
		||||
                    self.setRole(role: .broadcaster)
 | 
			
		||||
                } else {
 | 
			
		||||
                    self.setRole(role: .audience)
 | 
			
		||||
                }
 | 
			
		||||
                onConnectSuccess(userId == creatorId)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        func failOnce(_ reason: String?) {
 | 
			
		||||
            if (!completed) {
 | 
			
		||||
                completed = true
 | 
			
		||||
                if let reason = reason {
 | 
			
		||||
                    DEBUG_LOG("RTM subscribe failed: \(reason)")
 | 
			
		||||
                } else {
 | 
			
		||||
                    DEBUG_LOG("RTM subscribe failed: nil")
 | 
			
		||||
                }
 | 
			
		||||
                onConnectFail()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        func subscribeRoom(_ attempt: Int) {
 | 
			
		||||
            DEBUG_LOG("RTM subscribe(room: \(targetRoom!)) attempt=\(attempt)")
 | 
			
		||||
            rtmKit?.subscribe(channelName: targetRoom!, option: nil) { _, error in
 | 
			
		||||
                if error != nil {
 | 
			
		||||
                    DEBUG_LOG("RTM subscribe(room) failure at attempt=\(attempt) operation=\(error!.operation) reason=\(error!.reason)  code=\(error!.errorCode)")
 | 
			
		||||
                    if (attempt < 4) {
 | 
			
		||||
                        subscribeRoom(attempt + 1)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        failOnce("room subscribe failed after 3 retries (4 attempts)")
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    DEBUG_LOG("RTM subscribe(room) success at attempt=\(attempt)")
 | 
			
		||||
                    roomSubscribed = true
 | 
			
		||||
                    completeSuccessIfReady()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        func subscribeInbox(_ attempt: Int) {
 | 
			
		||||
            let inboxChannel = "inbox_\(userId)"
 | 
			
		||||
            DEBUG_LOG("RTM subscribe(inbox: \(inboxChannel)) attempt=\(attempt)")
 | 
			
		||||
            rtmKit?.subscribe(channelName: inboxChannel, option: nil) { _, error in
 | 
			
		||||
                if error != nil {
 | 
			
		||||
                    DEBUG_LOG("RTM subscribe(inbox) failure at attempt=\(attempt) operation=\(error!.operation) reason=\(error!.reason) code=\(error!.errorCode)")
 | 
			
		||||
                    if (attempt < 4) {
 | 
			
		||||
                        subscribeInbox(attempt + 1)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        failOnce("room subscribe failed after 3 retries (4 attempts)")
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    DEBUG_LOG("RTM subscribe(inbox) success at attempt=\(attempt)")
 | 
			
		||||
                    inboxSubscribed = true
 | 
			
		||||
                    completeSuccessIfReady()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // 두 채널 구독을 병렬로 시도
 | 
			
		||||
        subscribeRoom(1)
 | 
			
		||||
        subscribeInbox(1)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func sendRawMessageToPeer(peerId: String, rawMessage: LiveRoomChatRawMessage, completion: AgoraRtmSendPeerMessageBlock? = nil, fail: (() -> Void)? = nil) {
 | 
			
		||||
    func sendMessageToPeer(peerId: String, rawMessage: Data, completion: AgoraRtmOperationBlock?) {
 | 
			
		||||
        rtmKit?.publish(channelName: "inbox_\(peerId)", data: rawMessage, option: nil, completion: completion)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func sendRawMessageToPeer(peerId: String, rawMessage: LiveRoomChatRawMessage, completion: AgoraRtmOperationBlock? = nil, fail: (() -> Void)? = nil) {
 | 
			
		||||
        let encoder = JSONEncoder()
 | 
			
		||||
        let jsonMessageData = try? encoder.encode(rawMessage)
 | 
			
		||||
        let option = AgoraRtmSendMessageOptions()
 | 
			
		||||
        option.enableOfflineMessaging = false
 | 
			
		||||
        option.enableHistoricalMessaging = false
 | 
			
		||||
        
 | 
			
		||||
        if let jsonMessageData = jsonMessageData {
 | 
			
		||||
            let message = AgoraRtmRawMessage(rawData: jsonMessageData, description: "")
 | 
			
		||||
            rtmKit?.send(message, toPeer: peerId, sendMessageOptions: option, completion: completion)
 | 
			
		||||
            rtmKit?.publish(channelName: "inbox_\(peerId)", data: jsonMessageData, option: nil, completion: completion)
 | 
			
		||||
        } else {
 | 
			
		||||
            if let fail = fail {
 | 
			
		||||
                fail()
 | 
			
		||||
@@ -157,22 +288,27 @@ final class Agora {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func sendMessageToGroup(textMessage: String, completion: @escaping AgoraRtmSendChannelMessageBlock) {
 | 
			
		||||
        let message = AgoraRtmMessage(text: textMessage)
 | 
			
		||||
        rtmChannel?.send(message, completion: completion)
 | 
			
		||||
    func sendMessageToGroup(textMessage: String, completion: @escaping AgoraRtmOperationBlock) {
 | 
			
		||||
        guard !textMessage.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return }
 | 
			
		||||
        guard let channelName = roomChannelName else { return }
 | 
			
		||||
        
 | 
			
		||||
        rtmKit?.publish(channelName: channelName, message: textMessage, option: nil, completion: completion)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func sendRawMessageToGroup(rawMessage: LiveRoomChatRawMessage, completion: AgoraRtmSendChannelMessageBlock? = nil, fail: (() -> Void)? = nil) {
 | 
			
		||||
    func sendRawMessageToGroup(rawMessage: LiveRoomChatRawMessage, completion: AgoraRtmOperationBlock? = nil, fail: (() -> Void)? = nil) {
 | 
			
		||||
        let encoder = JSONEncoder()
 | 
			
		||||
        let jsonMessageData = try? encoder.encode(rawMessage)
 | 
			
		||||
        
 | 
			
		||||
        if let jsonMessageData = jsonMessageData {
 | 
			
		||||
            let message = AgoraRtmRawMessage(rawData: jsonMessageData, description: "")
 | 
			
		||||
            rtmChannel?.send(message, completion: completion)
 | 
			
		||||
        if let jsonMessageData = jsonMessageData, let channelName = roomChannelName {
 | 
			
		||||
            rtmKit?.publish(channelName: channelName, data: jsonMessageData, option: nil, completion: completion)
 | 
			
		||||
        } else {
 | 
			
		||||
            if let fail = fail {
 | 
			
		||||
                fail()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func isRtmLoggedIn() -> Bool {
 | 
			
		||||
        return rtmLoggedIn
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -225,6 +225,8 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
    
 | 
			
		||||
    private var blockedMemberIdList = Set<Int>()
 | 
			
		||||
    
 | 
			
		||||
    private var hasInvokedJoinChannel = false
 | 
			
		||||
    
 | 
			
		||||
    func getBlockedMemberIdList() {
 | 
			
		||||
        userRepository.getBlockedMemberIdList()
 | 
			
		||||
            .sink { result in
 | 
			
		||||
@@ -265,7 +267,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
    
 | 
			
		||||
    func initAgoraEngine() {
 | 
			
		||||
        agora.rtcEngineDelegate = self
 | 
			
		||||
        agora.rtmDelegate = self
 | 
			
		||||
        agora.rtmClientDelegate = self
 | 
			
		||||
        agora.initialize()
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
@@ -370,15 +372,23 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
                        self.isActiveRoulette = data.isActiveRoulette
 | 
			
		||||
                        self.isLoading = true
 | 
			
		||||
                        
 | 
			
		||||
                        self.agora.joinRtcChannel(rtcToken: data.rtcToken, channelName: data.channelName)
 | 
			
		||||
                        self.agora.rtmLogin(
 | 
			
		||||
                            creatorId: data.creatorId,
 | 
			
		||||
                            rtmToken: data.rtmToken,
 | 
			
		||||
                            channelName: data.channelName,
 | 
			
		||||
                            rtmChannelDelegate: self,
 | 
			
		||||
                            onConnectSuccess: self.agoraConnectSuccess,
 | 
			
		||||
                            onConnectFail: self.agoraConnectFail
 | 
			
		||||
                        )
 | 
			
		||||
                        let rtcState = self.agora.getRtcConnectionState()
 | 
			
		||||
                        let rtcConnected = rtcState == AgoraConnectionState.connected
 | 
			
		||||
                        let rtmLoggedIn = self.agora.isRtmLoggedIn()
 | 
			
		||||
                        
 | 
			
		||||
                        if (!hasInvokedJoinChannel && !(rtcConnected && rtmLoggedIn)) {
 | 
			
		||||
                            hasInvokedJoinChannel = true
 | 
			
		||||
                            self.agora.joinRtcChannel(rtcToken: data.rtcToken, channelName: data.channelName)
 | 
			
		||||
                            self.agora.rtmLogin(
 | 
			
		||||
                                creatorId: data.creatorId,
 | 
			
		||||
                                rtmToken: data.rtmToken,
 | 
			
		||||
                                channelName: data.channelName,
 | 
			
		||||
                                onConnectSuccess: self.agoraConnectSuccess,
 | 
			
		||||
                                onConnectFail: self.agoraConnectFail
 | 
			
		||||
                            )
 | 
			
		||||
                        } else {
 | 
			
		||||
                            DEBUG_LOG("joinChannel - skip (rtcConnected=\(rtcConnected), rtmLoggedIn=\(rtmLoggedIn), hasInvokedJoinChannel=\(hasInvokedJoinChannel))")
 | 
			
		||||
                        }
 | 
			
		||||
                        
 | 
			
		||||
                        getTotalDonationCan()
 | 
			
		||||
                        getTotalHeartCount()
 | 
			
		||||
@@ -435,20 +445,17 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
                self.popupContent = "\(remainingNoChattingTime)초 동안 채팅하실 수 없습니다"
 | 
			
		||||
                self.isShowPopup = true
 | 
			
		||||
            } else if chatMessage.count > 0 {
 | 
			
		||||
                agora.sendMessageToGroup(textMessage: chatMessage, completion: { [unowned self] errorCode in
 | 
			
		||||
                    if errorCode == .errorOk {
 | 
			
		||||
                agora.sendMessageToGroup(textMessage: chatMessage) { _, error in
 | 
			
		||||
                    if error == nil {
 | 
			
		||||
                        let (nickname, profileUrl) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId))
 | 
			
		||||
                        let rank = getUserRank(userId: UserDefaults.int(forKey: .userId))
 | 
			
		||||
                        let rank = self.getUserRank(userId: UserDefaults.int(forKey: .userId))
 | 
			
		||||
                        self.messages.append(LiveRoomNormalChat(userId: UserDefaults.int(forKey: .userId), profileUrl: profileUrl, nickname: nickname, rank: rank, chat: chatMessage))
 | 
			
		||||
                        
 | 
			
		||||
                        self.messageChangeFlag.toggle()
 | 
			
		||||
                        if self.messages.count > 100 {
 | 
			
		||||
                            self.messages.remove(at: 0)
 | 
			
		||||
                        }
 | 
			
		||||
                        self.invalidateChat()
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    onSuccess()
 | 
			
		||||
                })
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -501,68 +508,54 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
                            UserDefaults.set(UserDefaults.int(forKey: .can) - can, forKey: .can)
 | 
			
		||||
                            
 | 
			
		||||
                            if isSecret {
 | 
			
		||||
                                agora.sendRawMessageToPeer(
 | 
			
		||||
                                    peerId: String(liveRoomInfo!.creatorId), rawMessage: donationRawMessage,
 | 
			
		||||
                                    completion: { [unowned self] errorCode in
 | 
			
		||||
                                        if errorCode == .ok {
 | 
			
		||||
                                            let (nickname, profileUrl) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId))
 | 
			
		||||
                                            self.messages.append(
 | 
			
		||||
                                                LiveRoomDonationChat(
 | 
			
		||||
                                                    memberId: UserDefaults.int(forKey: .userId),
 | 
			
		||||
                                                    profileUrl: profileUrl,
 | 
			
		||||
                                                    nickname: nickname,
 | 
			
		||||
                                                    chat: rawMessage,
 | 
			
		||||
                                                    can: can,
 | 
			
		||||
                                                    donationMessage: message
 | 
			
		||||
                                                )
 | 
			
		||||
                                agora.sendRawMessageToPeer(peerId: String(liveRoomInfo!.creatorId), rawMessage: donationRawMessage) { [unowned self] _, error in
 | 
			
		||||
                                    if error == nil {
 | 
			
		||||
                                        let (nickname, profileUrl) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId))
 | 
			
		||||
                                        self.messages.append(
 | 
			
		||||
                                            LiveRoomDonationChat(
 | 
			
		||||
                                                memberId: UserDefaults.int(forKey: .userId),
 | 
			
		||||
                                                profileUrl: profileUrl,
 | 
			
		||||
                                                nickname: nickname,
 | 
			
		||||
                                                chat: rawMessage,
 | 
			
		||||
                                                can: can,
 | 
			
		||||
                                                donationMessage: message
 | 
			
		||||
                                            )
 | 
			
		||||
                                        )
 | 
			
		||||
                                        
 | 
			
		||||
                                            addSignature(signature: decoded.data)
 | 
			
		||||
                                        addSignature(signature: decoded.data)
 | 
			
		||||
                                        
 | 
			
		||||
                                            self.messageChangeFlag.toggle()
 | 
			
		||||
                                            if self.messages.count > 100 {
 | 
			
		||||
                                                self.messages.remove(at: 0)
 | 
			
		||||
                                            }
 | 
			
		||||
                                        } else {
 | 
			
		||||
                                            refundDonation()
 | 
			
		||||
                                        }
 | 
			
		||||
                                    },
 | 
			
		||||
                                    fail: { [unowned self] in
 | 
			
		||||
                                        self.invalidateChat()
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        refundDonation()
 | 
			
		||||
                                    }
 | 
			
		||||
                                )
 | 
			
		||||
                                } fail: { [unowned self] in
 | 
			
		||||
                                    refundDonation()
 | 
			
		||||
                                }
 | 
			
		||||
                            } else {
 | 
			
		||||
                                agora.sendRawMessageToGroup(
 | 
			
		||||
                                    rawMessage: donationRawMessage,
 | 
			
		||||
                                    completion: { [unowned self] errorCode in
 | 
			
		||||
                                        if errorCode == .errorOk {
 | 
			
		||||
                                            let (nickname, profileUrl) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId))
 | 
			
		||||
                                            self.messages.append(
 | 
			
		||||
                                                LiveRoomDonationChat(
 | 
			
		||||
                                                    memberId: UserDefaults.int(forKey: .userId),
 | 
			
		||||
                                                    profileUrl: profileUrl,
 | 
			
		||||
                                                    nickname: nickname,
 | 
			
		||||
                                                    chat: rawMessage,
 | 
			
		||||
                                                    can: can,
 | 
			
		||||
                                                    donationMessage: message
 | 
			
		||||
                                                )
 | 
			
		||||
                                agora.sendRawMessageToGroup(rawMessage: donationRawMessage) { [unowned self] _, error in
 | 
			
		||||
                                    if error == nil {
 | 
			
		||||
                                        let (nickname, profileUrl) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId))
 | 
			
		||||
                                        self.messages.append(
 | 
			
		||||
                                            LiveRoomDonationChat(
 | 
			
		||||
                                                memberId: UserDefaults.int(forKey: .userId),
 | 
			
		||||
                                                profileUrl: profileUrl,
 | 
			
		||||
                                                nickname: nickname,
 | 
			
		||||
                                                chat: rawMessage,
 | 
			
		||||
                                                can: can,
 | 
			
		||||
                                                donationMessage: message
 | 
			
		||||
                                            )
 | 
			
		||||
                                        )
 | 
			
		||||
                                        
 | 
			
		||||
                                            totalDonationCan += can
 | 
			
		||||
                                            addSignature(signature: decoded.data)
 | 
			
		||||
                                        totalDonationCan += can
 | 
			
		||||
                                        addSignature(signature: decoded.data)
 | 
			
		||||
                                        
 | 
			
		||||
                                            self.messageChangeFlag.toggle()
 | 
			
		||||
                                            if self.messages.count > 100 {
 | 
			
		||||
                                                self.messages.remove(at: 0)
 | 
			
		||||
                                            }
 | 
			
		||||
                                        } else {
 | 
			
		||||
                                            refundDonation()
 | 
			
		||||
                                        }
 | 
			
		||||
                                    },
 | 
			
		||||
                                    fail: { [unowned self] in
 | 
			
		||||
                                        self.invalidateChat()
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        refundDonation()
 | 
			
		||||
                                    }
 | 
			
		||||
                                )
 | 
			
		||||
                                } fail: { [unowned self] in
 | 
			
		||||
                                    refundDonation()
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            if let message = decoded.message {
 | 
			
		||||
@@ -625,17 +618,17 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func inviteSpeaker(peerId: Int) {
 | 
			
		||||
        agora.sendMessageToPeer(peerId: String(peerId), rawMessage: LiveRoomRequestType.INVITE_SPEAKER.rawValue.data(using: .utf8)!, completion: { [unowned self] errorCode in
 | 
			
		||||
            if errorCode == .ok {
 | 
			
		||||
        agora.sendMessageToPeer(peerId: String(peerId), rawMessage: LiveRoomRequestType.INVITE_SPEAKER.rawValue.data(using: .utf8)!) { [unowned self] _, error in
 | 
			
		||||
            if error == nil {
 | 
			
		||||
                self.popupContent = "스피커 요청을 보냈습니다.\n잠시만 기다려 주세요."
 | 
			
		||||
                self.isShowPopup = true
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func changeListener(peerId: Int, isFromManager: Bool = false) {
 | 
			
		||||
        agora.sendMessageToPeer(peerId: String(peerId), rawMessage: LiveRoomRequestType.CHANGE_LISTENER.rawValue.data(using: .utf8)!, completion: { [unowned self] errorCode in
 | 
			
		||||
            if errorCode == .ok {
 | 
			
		||||
        agora.sendMessageToPeer(peerId: String(peerId), rawMessage: LiveRoomRequestType.CHANGE_LISTENER.rawValue.data(using: .utf8)!) { [unowned self] _, error in
 | 
			
		||||
            if error == nil {
 | 
			
		||||
                if isFromManager {
 | 
			
		||||
                    getRoomInfo()
 | 
			
		||||
                    setManagerMessage()
 | 
			
		||||
@@ -647,7 +640,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
                
 | 
			
		||||
                self.isShowPopup = true
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private func getUserNicknameAndProfileUrl(accountId: Int) -> (nickname: String, profileUrl: String) {
 | 
			
		||||
@@ -977,12 +970,10 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
                .store(in: &subscription)
 | 
			
		||||
            
 | 
			
		||||
            let nickname = getUserNicknameAndProfileUrl(accountId: kickOutId).nickname
 | 
			
		||||
            agora.sendMessageToPeer(peerId: String(kickOutId), rawMessage: LiveRoomRequestType.KICK_OUT.rawValue.data(using: .utf8)!, completion: { [unowned self] errorCode in
 | 
			
		||||
                if errorCode == .ok {
 | 
			
		||||
                    self.popupContent = "\(nickname)님을 내보냈습니다."
 | 
			
		||||
                    self.isShowPopup = true
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            agora.sendMessageToPeer(peerId: String(kickOutId), rawMessage: LiveRoomRequestType.KICK_OUT.rawValue.data(using: .utf8)!) { [unowned self] _, error in
 | 
			
		||||
                self.popupContent = "\(nickname)님을 내보냈습니다."
 | 
			
		||||
                self.isShowPopup = true
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if let index = muteSpeakers.firstIndex(of: UInt(kickOutId)) {
 | 
			
		||||
@@ -1424,22 +1415,18 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func setNoChatting() {
 | 
			
		||||
        agora.sendMessageToPeer(
 | 
			
		||||
            peerId: String(noChattingUserId),
 | 
			
		||||
            rawMessage: LiveRoomRequestType.NO_CHATTING.rawValue.data(using: .utf8)!,
 | 
			
		||||
            completion: { [unowned self] errorCode in
 | 
			
		||||
                if errorCode == .ok {
 | 
			
		||||
                    self.popupContent = "\(noChattingUserNickname)님을 3분간 채팅금지를 하였습니다."
 | 
			
		||||
                    self.isShowPopup = true
 | 
			
		||||
        agora.sendMessageToPeer(peerId: String(noChattingUserId), rawMessage: LiveRoomRequestType.NO_CHATTING.rawValue.data(using: .utf8)!) { [unowned self] _, error in
 | 
			
		||||
            if error == nil {
 | 
			
		||||
                self.popupContent = "\(noChattingUserNickname)님을 3분간 채팅금지를 하였습니다."
 | 
			
		||||
                self.isShowPopup = true
 | 
			
		||||
                
 | 
			
		||||
                    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
 | 
			
		||||
                        self.noChattingUserId = 0
 | 
			
		||||
                        self.noChattingUserNickname = ""
 | 
			
		||||
                        self.noChattingUserProfileUrl = ""
 | 
			
		||||
                    }
 | 
			
		||||
                DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
 | 
			
		||||
                    self.noChattingUserId = 0
 | 
			
		||||
                    self.noChattingUserNickname = ""
 | 
			
		||||
                    self.noChattingUserProfileUrl = ""
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private func setManagerMessage() {
 | 
			
		||||
@@ -1627,7 +1614,8 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
    
 | 
			
		||||
    private func removeNoChatRoom() {
 | 
			
		||||
        var noChatRoomList = getNoChatRoomListFromUserDefaults()
 | 
			
		||||
        if let index = noChatRoomList.firstIndex(of: liveRoomInfo!.roomId) {
 | 
			
		||||
        guard let roomId = liveRoomInfo?.roomId else { return }
 | 
			
		||||
        if let index = noChatRoomList.firstIndex(of: roomId) {
 | 
			
		||||
            noChatRoomList.remove(at: index)
 | 
			
		||||
        }
 | 
			
		||||
        saveNoChatRoomListToUserDefaults(noChatRoomList: noChatRoomList)
 | 
			
		||||
@@ -1760,36 +1748,29 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
            donationMessage: ""
 | 
			
		||||
        )
 | 
			
		||||
        
 | 
			
		||||
        self.agora.sendRawMessageToGroup(
 | 
			
		||||
            rawMessage: rouletteRawMessage,
 | 
			
		||||
            completion: { [unowned self] errorCode in
 | 
			
		||||
                if errorCode == .errorOk {
 | 
			
		||||
                    let (nickname, profileUrl) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId))
 | 
			
		||||
                    self.messages.append(
 | 
			
		||||
                        LiveRoomRouletteDonationChat(
 | 
			
		||||
                            profileUrl: profileUrl,
 | 
			
		||||
                            nickname: nickname,
 | 
			
		||||
                            rouletteResult: rouletteSelectedItem
 | 
			
		||||
                        )
 | 
			
		||||
        agora.sendRawMessageToGroup(rawMessage: rouletteRawMessage) { [unowned self] _, error in
 | 
			
		||||
            if error == nil {
 | 
			
		||||
                let (nickname, profileUrl) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId))
 | 
			
		||||
                self.messages.append(
 | 
			
		||||
                    LiveRoomRouletteDonationChat(
 | 
			
		||||
                        profileUrl: profileUrl,
 | 
			
		||||
                        nickname: nickname,
 | 
			
		||||
                        rouletteResult: rouletteSelectedItem
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
                
 | 
			
		||||
                    totalDonationCan += rouletteCan
 | 
			
		||||
                    self.rouletteItems.removeAll()
 | 
			
		||||
                    self.rouletteSelectedItem = ""
 | 
			
		||||
                    self.rouletteCan = 0
 | 
			
		||||
                totalDonationCan += rouletteCan
 | 
			
		||||
                self.rouletteItems.removeAll()
 | 
			
		||||
                self.rouletteSelectedItem = ""
 | 
			
		||||
                self.rouletteCan = 0
 | 
			
		||||
                
 | 
			
		||||
                    self.messageChangeFlag.toggle()
 | 
			
		||||
                    if self.messages.count > 100 {
 | 
			
		||||
                        self.messages.remove(at: 0)
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    self.refundRouletteDonation()
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            fail: { [unowned self] in
 | 
			
		||||
                self.invalidateChat()
 | 
			
		||||
            } else {
 | 
			
		||||
                self.refundRouletteDonation()
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        } fail: { [unowned self] in
 | 
			
		||||
            self.refundRouletteDonation()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func stopPeriodicPlaybackValidation() {
 | 
			
		||||
@@ -1949,28 +1930,21 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
                                    donationMessage: nil
 | 
			
		||||
                                )
 | 
			
		||||
                                
 | 
			
		||||
                                agora.sendRawMessageToGroup(
 | 
			
		||||
                                    rawMessage: donationRawMessage,
 | 
			
		||||
                                    completion: { [unowned self] errorCode in
 | 
			
		||||
                                        if errorCode == .errorOk {
 | 
			
		||||
                                            let (nickname, _) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId))
 | 
			
		||||
                                            self.addHeartMessage(nickname: nickname)
 | 
			
		||||
                                agora.sendRawMessageToGroup(rawMessage: donationRawMessage) { [unowned self] _, error in
 | 
			
		||||
                                    if error == nil {
 | 
			
		||||
                                        let (nickname, _) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId))
 | 
			
		||||
                                        self.addHeartMessage(nickname: nickname)
 | 
			
		||||
                                        
 | 
			
		||||
                                            totalHeartCount += 1
 | 
			
		||||
                                            addHeart()
 | 
			
		||||
                                        totalHeartCount += 1
 | 
			
		||||
                                        addHeart()
 | 
			
		||||
                                        
 | 
			
		||||
                                            self.messageChangeFlag.toggle()
 | 
			
		||||
                                            if self.messages.count > 100 {
 | 
			
		||||
                                                self.messages.remove(at: 0)
 | 
			
		||||
                                            }
 | 
			
		||||
                                        } else {
 | 
			
		||||
                                            refundDonation()
 | 
			
		||||
                                        }
 | 
			
		||||
                                    },
 | 
			
		||||
                                    fail: { [unowned self] in
 | 
			
		||||
                                        refundDonation()
 | 
			
		||||
                                        self.invalidateChat()
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        self.refundDonation()
 | 
			
		||||
                                    }
 | 
			
		||||
                                )
 | 
			
		||||
                                } fail: { [unowned self] in
 | 
			
		||||
                                    self.refundDonation()
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        } catch {
 | 
			
		||||
                            refundDonation()
 | 
			
		||||
@@ -2073,6 +2047,13 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
 | 
			
		||||
        heartTimer?.cancel()
 | 
			
		||||
        heartTimer = nil
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private func invalidateChat() {
 | 
			
		||||
        messageChangeFlag.toggle()
 | 
			
		||||
        if messages.count > 100 {
 | 
			
		||||
            messages.remove(at: 0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extension LiveRoomViewModel: AgoraRtcEngineDelegate {
 | 
			
		||||
@@ -2081,7 +2062,6 @@ extension LiveRoomViewModel: AgoraRtcEngineDelegate {
 | 
			
		||||
            .filter { $0.volume > 0 }
 | 
			
		||||
            .map { $0.uid }
 | 
			
		||||
        
 | 
			
		||||
        DEBUG_LOG("activeSpeakerIds::: \(activeSpeakerIds)")
 | 
			
		||||
        activeSpeakers.removeAll()
 | 
			
		||||
        activeSpeakers.append(contentsOf: activeSpeakerIds)
 | 
			
		||||
    }
 | 
			
		||||
@@ -2115,10 +2095,17 @@ extension LiveRoomViewModel: AgoraRtcEngineDelegate {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extension LiveRoomViewModel: AgoraRtmDelegate {
 | 
			
		||||
    func rtmKit(_ kit: AgoraRtmKit, messageReceived message: AgoraRtmMessage, fromPeer peerId: String) {
 | 
			
		||||
        if message.type == .raw, let rawMessage = message as? AgoraRtmRawMessage {
 | 
			
		||||
            let rawMessageString = String(data: rawMessage.rawData, encoding: .utf8)
 | 
			
		||||
extension LiveRoomViewModel: AgoraRtmClientDelegate {
 | 
			
		||||
    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveMessageEvent event: AgoraRtmMessageEvent) {
 | 
			
		||||
        DEBUG_LOG("Message received.\n channel: \(event.channelName), publisher: \(event.publisher)")
 | 
			
		||||
        
 | 
			
		||||
        let rawMessage = event.message.rawData
 | 
			
		||||
        let textMessage = event.message.stringData
 | 
			
		||||
        let publisher = event.publisher
 | 
			
		||||
        let (nickname, profileUrl) = getUserNicknameAndProfileUrl(accountId: Int(publisher)!)
 | 
			
		||||
        
 | 
			
		||||
        if let message = rawMessage {
 | 
			
		||||
            let rawMessageString = String(data: message, encoding: .utf8)
 | 
			
		||||
            
 | 
			
		||||
            DispatchQueue.main.async { [unowned self] in
 | 
			
		||||
                if rawMessageString == LiveRoomRequestType.CHANGE_LISTENER.rawValue {
 | 
			
		||||
@@ -2127,7 +2114,7 @@ extension LiveRoomViewModel: AgoraRtmDelegate {
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if rawMessageString == LiveRoomRequestType.REQUEST_SPEAKER.rawValue {
 | 
			
		||||
                    self.popupContent = "\(getUserNicknameAndProfileUrl(accountId: Int(peerId)!).nickname)님이 스피커 요청을 했어요!\n스퍼커로 초대할까요?"
 | 
			
		||||
                    self.popupContent = "\(nickname)님이 스피커 요청을 했어요!\n스퍼커로 초대할까요?"
 | 
			
		||||
                    self.popupCancelTitle = "건너뛰기"
 | 
			
		||||
                    self.popupCancelAction = {
 | 
			
		||||
                        self.isShowPopup = false
 | 
			
		||||
@@ -2136,7 +2123,7 @@ extension LiveRoomViewModel: AgoraRtmDelegate {
 | 
			
		||||
                    self.popupConfirmAction = {
 | 
			
		||||
                        self.isShowPopup = false
 | 
			
		||||
                        if self.liveRoomInfo!.speakerList.count <= 5 {
 | 
			
		||||
                            self.requestSpeakerAllow(peerId)
 | 
			
		||||
                            self.requestSpeakerAllow(publisher)
 | 
			
		||||
                        } else {
 | 
			
		||||
                            self.errorMessage = "스피커 정원이 초과되었습니다."
 | 
			
		||||
                            self.isShowErrorPopup = true
 | 
			
		||||
@@ -2214,13 +2201,12 @@ extension LiveRoomViewModel: AgoraRtmDelegate {
 | 
			
		||||
                
 | 
			
		||||
                do {
 | 
			
		||||
                    let jsonDecoder = JSONDecoder()
 | 
			
		||||
                    let decoded = try jsonDecoder.decode(LiveRoomChatRawMessage.self, from: rawMessage.rawData)
 | 
			
		||||
                    let (nickname, profileUrl) = getUserNicknameAndProfileUrl(accountId: Int(peerId)!)
 | 
			
		||||
                    let decoded = try jsonDecoder.decode(LiveRoomChatRawMessage.self, from: message)
 | 
			
		||||
                    
 | 
			
		||||
                    if decoded.type == .SECRET_DONATION {
 | 
			
		||||
                        self.messages.append(
 | 
			
		||||
                            LiveRoomDonationChat(
 | 
			
		||||
                                memberId: Int(peerId)!,
 | 
			
		||||
                                memberId: Int(publisher)!,
 | 
			
		||||
                                profileUrl: profileUrl,
 | 
			
		||||
                                nickname: nickname,
 | 
			
		||||
                                chat: decoded.message,
 | 
			
		||||
@@ -2234,98 +2220,86 @@ extension LiveRoomViewModel: AgoraRtmDelegate {
 | 
			
		||||
                        } else if let imageUrl = decoded.signatureImageUrl {
 | 
			
		||||
                            self.addSignatureImage(imageUrl: imageUrl)
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if decoded.type == .DONATION {
 | 
			
		||||
                        self.messages.append(
 | 
			
		||||
                            LiveRoomDonationChat(
 | 
			
		||||
                                memberId: Int(publisher)!,
 | 
			
		||||
                                profileUrl: profileUrl,
 | 
			
		||||
                                nickname: nickname,
 | 
			
		||||
                                chat: decoded.message,
 | 
			
		||||
                                can: decoded.can,
 | 
			
		||||
                                donationMessage: decoded.donationMessage ?? ""
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                        
 | 
			
		||||
                        self.totalDonationCan += decoded.can
 | 
			
		||||
                        
 | 
			
		||||
                        if let signature = decoded.signature {
 | 
			
		||||
                            self.addSignature(signature: signature)
 | 
			
		||||
                        } else if let imageUrl = decoded.signatureImageUrl {
 | 
			
		||||
                            self.addSignatureImage(imageUrl: imageUrl)
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if decoded.type == .ROULETTE_DONATION {
 | 
			
		||||
                        self.messages.append(
 | 
			
		||||
                            LiveRoomRouletteDonationChat(
 | 
			
		||||
                                profileUrl: profileUrl,
 | 
			
		||||
                                nickname: nickname,
 | 
			
		||||
                                rouletteResult: decoded.message
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                        
 | 
			
		||||
                        self.totalDonationCan += decoded.can
 | 
			
		||||
                    } else if decoded.type == .TOGGLE_ROULETTE && decoded.isActiveRoulette != nil {
 | 
			
		||||
                        self.isActiveRoulette = decoded.isActiveRoulette!
 | 
			
		||||
                    } else if decoded.type == .EDIT_ROOM_INFO || decoded.type == .SET_MANAGER {
 | 
			
		||||
                        self.getRoomInfo()
 | 
			
		||||
                    } else if decoded.type == .HEART_DONATION {
 | 
			
		||||
                        self.addHeartMessage(nickname: nickname)
 | 
			
		||||
                        self.totalHeartCount += decoded.can
 | 
			
		||||
                        self.addHeart()
 | 
			
		||||
                    }
 | 
			
		||||
                } catch {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
        
 | 
			
		||||
extension LiveRoomViewModel: AgoraRtmChannelDelegate {
 | 
			
		||||
    func channel(_ channel: AgoraRtmChannel, messageReceived message: AgoraRtmMessage, from member: AgoraRtmMember) {
 | 
			
		||||
        let (nickname, profileUrl) = getUserNicknameAndProfileUrl(accountId: Int(member.userId)!)
 | 
			
		||||
        
 | 
			
		||||
        if message.type == .raw, let rawMessage = message as? AgoraRtmRawMessage {
 | 
			
		||||
            do {
 | 
			
		||||
                let jsonDecoder = JSONDecoder()
 | 
			
		||||
                let decoded = try jsonDecoder.decode(LiveRoomChatRawMessage.self, from: rawMessage.rawData)
 | 
			
		||||
                
 | 
			
		||||
                if decoded.type == .DONATION {
 | 
			
		||||
                    self.messages.append(
 | 
			
		||||
                        LiveRoomDonationChat(
 | 
			
		||||
                            memberId: Int(member.userId)!,
 | 
			
		||||
                            profileUrl: profileUrl,
 | 
			
		||||
                            nickname: nickname,
 | 
			
		||||
                            chat: decoded.message,
 | 
			
		||||
                            can: decoded.can,
 | 
			
		||||
                            donationMessage: decoded.donationMessage ?? ""
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                    
 | 
			
		||||
                    self.totalDonationCan += decoded.can
 | 
			
		||||
                    
 | 
			
		||||
                    if let signature = decoded.signature {
 | 
			
		||||
                        self.addSignature(signature: signature)
 | 
			
		||||
                    } else if let imageUrl = decoded.signatureImageUrl {
 | 
			
		||||
                        self.addSignatureImage(imageUrl: imageUrl)
 | 
			
		||||
                    }
 | 
			
		||||
                } else if decoded.type == .ROULETTE_DONATION {
 | 
			
		||||
                    self.messages.append(
 | 
			
		||||
                        LiveRoomRouletteDonationChat(
 | 
			
		||||
                            profileUrl: profileUrl,
 | 
			
		||||
                            nickname: nickname,
 | 
			
		||||
                            rouletteResult: decoded.message
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                    
 | 
			
		||||
                    self.totalDonationCan += decoded.can
 | 
			
		||||
                } else if decoded.type == .TOGGLE_ROULETTE && decoded.isActiveRoulette != nil {
 | 
			
		||||
                    self.isActiveRoulette = decoded.isActiveRoulette!
 | 
			
		||||
                } else if decoded.type == .EDIT_ROOM_INFO || decoded.type == .SET_MANAGER {
 | 
			
		||||
                    self.getRoomInfo()
 | 
			
		||||
                } else if decoded.type == .HEART_DONATION {
 | 
			
		||||
                    self.addHeartMessage(nickname: nickname)
 | 
			
		||||
                    self.totalHeartCount += decoded.can
 | 
			
		||||
                    self.addHeart()
 | 
			
		||||
                }
 | 
			
		||||
            } catch {
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            let memberId = Int(member.userId) ?? 0
 | 
			
		||||
            let chat = message.text
 | 
			
		||||
        if let message = textMessage {
 | 
			
		||||
            let memberId = Int(publisher) ?? 0
 | 
			
		||||
            let rank = getUserRank(userId: memberId)
 | 
			
		||||
            
 | 
			
		||||
            if !chat.trimmingCharacters(in: .whitespaces).isEmpty && !blockedMemberIdList.contains(memberId) {
 | 
			
		||||
                messages.append(LiveRoomNormalChat(userId: memberId, profileUrl: profileUrl, nickname: nickname, rank: rank, chat: chat))
 | 
			
		||||
            if !message.trimmingCharacters(in: .whitespaces).isEmpty && !blockedMemberIdList.contains(memberId) {
 | 
			
		||||
                messages.append(LiveRoomNormalChat(userId: memberId, profileUrl: profileUrl, nickname: nickname, rank: rank, chat: message))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        DispatchQueue.main.async { [unowned self] in
 | 
			
		||||
            self.messageChangeFlag.toggle()
 | 
			
		||||
            if self.messages.count > 100 {
 | 
			
		||||
                self.messages.remove(at: 0)
 | 
			
		||||
            }
 | 
			
		||||
            self.invalidateChat()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func channel(_ channel: AgoraRtmChannel, memberJoined member: AgoraRtmMember) {
 | 
			
		||||
        getRoomInfo(userId: Int(member.userId)!) { [unowned self] nickname in
 | 
			
		||||
            if !nickname.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && isEntryMessageEnabled {
 | 
			
		||||
                DispatchQueue.main.async { [unowned self] in
 | 
			
		||||
                    self.messages.append(LiveRoomJoinChat(nickname: nickname))
 | 
			
		||||
                    self.messageChangeFlag.toggle()
 | 
			
		||||
                    if self.messages.count > 100 {
 | 
			
		||||
                        self.messages.remove(at: 0)
 | 
			
		||||
    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceivePresenceEvent event: AgoraRtmPresenceEvent) {
 | 
			
		||||
        DEBUG_LOG("didReceivePresenceEvent - \(event.type) - \(String(describing: event.publisher))")
 | 
			
		||||
        let eventType = event.type
 | 
			
		||||
        
 | 
			
		||||
        if let memberId = event.publisher {
 | 
			
		||||
            if eventType == .remoteJoinChannel {
 | 
			
		||||
                getRoomInfo(userId: Int(memberId)!) { [unowned self] nickname in
 | 
			
		||||
                    if !nickname.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && isEntryMessageEnabled {
 | 
			
		||||
                        DispatchQueue.main.async { [unowned self] in
 | 
			
		||||
                            self.messages.append(LiveRoomJoinChat(nickname: nickname))
 | 
			
		||||
                            self.invalidateChat()
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else if eventType == .remoteLeaveChannel {
 | 
			
		||||
                if let liveRoomInfo = liveRoomInfo, liveRoomInfo.creatorId != Int(memberId)! {
 | 
			
		||||
                    getRoomInfo()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func channel(_ channel: AgoraRtmChannel, memberLeft member: AgoraRtmMember) {
 | 
			
		||||
        if let liveRoomInfo = liveRoomInfo, liveRoomInfo.creatorId != Int(member.userId)! {
 | 
			
		||||
            getRoomInfo()
 | 
			
		||||
        }
 | 
			
		||||
    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveLinkStateEvent event: AgoraRtmLinkStateEvent) {
 | 
			
		||||
        DEBUG_LOG("Signaling link state change current state is: \(event.currentState.rawValue) previous state is :\(event.previousState.rawValue)")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user